summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/intel/core2/init_cpus.c604
-rw-r--r--arch/x86/secondary.S42
-rw-r--r--include/arch/x86/lapic.h2
-rw-r--r--mainboard/kontron/986lcd-m/Makefile6
-rw-r--r--mainboard/kontron/986lcd-m/initram.c21
-rw-r--r--mainboard/kontron/986lcd-m/stage1.c2
-rw-r--r--mainboard/kontron/Kconfig2
-rw-r--r--northbridge/intel/i945/reset_test.c31
9 files changed, 694 insertions, 18 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 7a86aa99170a..d6142ce27fe4 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -117,14 +117,12 @@ config K8_ALLOCATE_MMIO_RANGE
config LOGICAL_CPUS
hex
- depends CPU_AMD_K8 || CPU_INTEL_CORE2
default 1
help
How many logical CPUs there are. FIXME.
config MAX_PHYSICAL_CPUS
hex
- depends CPU_AMD_K8
default 1
help
Maximum number of physical CPUs (sockets).
diff --git a/arch/x86/intel/core2/init_cpus.c b/arch/x86/intel/core2/init_cpus.c
new file mode 100644
index 000000000000..7577ad8d86c2
--- /dev/null
+++ b/arch/x86/intel/core2/init_cpus.c
@@ -0,0 +1,604 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) YingHai Lu
+ * Copyright (C) 2005 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007 Stefan Reinauer
+ * Copyright (C) 2008 coresystems GmbH
+ * Copyright (C) 2009 Ronald G. Minnich <rminnich@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <mainboard.h>
+#include <types.h>
+#include <lib.h>
+#include <console.h>
+#include <cpu.h>
+#include <globalvars.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <msr.h>
+#include <io.h>
+#include <lapic.h>
+#include <arch/atomic.h>
+#include <arch/spinlock.h>
+#include <lapic.h>
+
+#ifdef CONFIG_SMM
+void smm_init(void);
+#endif
+
+#define SERIAL_CPU_INIT 1
+
+enum {
+ AP_START = 1,
+ AP_ACTIVEUP,
+ AP_LOCKED,
+ AP_INITDONE,
+ AP_UNLOCKED,
+ AP_ACTIVEDOWN,
+ AP_STARTFAIL = 0x7f,
+ AP_STOP = 0x80,
+ AP_SELFIPI,
+ AP_IPIDONE,
+ AP_DOWNINIT,
+ AP_STOP_OK = 0xfe,
+ AP_STOP_FAIL = 0xff,
+};
+/* this was an empty function in core 2 */
+void
+cpu_initialize(void)
+{
+}
+
+/**
+ * return count of how many nodes we have.
+ */
+unsigned int get_nodes(void)
+{
+ struct cpuid_result result;
+ int nodes, siblings;
+ result = cpuid(1);
+ /* See how many sibling cpus we have */
+ siblings = (result.ebx >> 16) & 0xff;
+ if (siblings < 1) {
+ siblings = 1;
+ }
+ nodes = siblings + 1;
+ printk(BIOS_DEBUG, "%s: %d\n", __func__, nodes);
+ return nodes;
+}
+/**
+ * lapic remote read
+ * lapics are more than just an interrupt steering system. They are a key part of inter-processor communication.
+ * They can be used to start, control, and interrupt other CPUs from the BSP. It is not possible to bring up
+ * an SMP system without somehow using the APIC.
+ * CPUs and their attached IOAPICs all have an ID. For convenience, these IDs are unique.
+ * The communications is packet-based, using (in coreboot) a polling-based strategy. As with most APIC ops,
+ * the ID is the APIC ID. Even more fun, code can read registers in remote APICs, and this in turn can
+ * provide us with remote CPU status.
+ * This function does a remote read given an apic id. It returns the value or an error. It can time out.
+ * @param apicid Remote APIC id
+ * @param reg The register number to read
+ * @param pvalue pointer to int for return value
+ * @returns 0 on success, -1 on error
+ */
+int lapic_remote_read(int apicid, int reg, unsigned int *pvalue)
+{
+ int timeout;
+ unsigned status;
+ int result;
+ /* Wait for the idle state. Could we enter this with the APIC busy? It's possible. */
+ lapic_wait_icr_idle();
+ /* The APIC Interrupt Control Registers define the operations and destinations.
+ * In this case, we set ICR2 to the dest, set the op to REMOTE READ, and set the
+ * reg (which is 16-bit aligned, it seems, hence the >> 4
+ */
+ lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+ lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
+
+ /* it's started. now we wait. */
+ timeout = 0;
+
+ do {
+ /* note here the ICR is command and status. */
+ /* Why don't we use the lapic_wait_icr_idle() above? */
+ /* That said, it's a bad idea to mess with this code too much.
+ * APICs (and their code) are quite fragile.
+ */
+ status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (status == LAPIC_ICR_BUSY && timeout++ < 1000);
+
+ /* interesting but the timeout is not checked, hence no error on the send! */
+
+ timeout = 0;
+ do {
+ status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
+ } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
+
+ result = -1;
+ if (status == LAPIC_ICR_RR_VALID) {
+ *pvalue = lapic_read(LAPIC_RRR);
+ result = 0;
+ }
+ return result;
+}
+
+#define LAPIC_MSG_REG 0x380
+
+void print_apicid_nodeid_coreid(unsigned apicid, struct node_core_id id,
+ const char *str)
+{
+ printk(BIOS_DEBUG, "%s --- { APICID = %02x NODEID = %02x COREID = %02x} ---\n",
+ str, apicid, id.nodeid, id.coreid);
+}
+
+/* this is "generic" lapic init. They are now in the core2 until we figure out how
+ * a generic version for v3 should look.
+ */
+/* These functions are critically dependent on which APIC we are using. That said,
+ * this seems to be a universally safe definition.
+ */
+# define FORCE_READ_AROUND_WRITE 1
+# define lapic_read_around(x) lapic_read(x)
+# define lapic_write_around(x,y) lapic_write_atomic((x),(y))
+
+/* This is a lot more paranoid now, since Linux can NOT handle
+ * being told there is a CPU when none exists. So any errors
+ * will return 0, meaning no CPU.
+ *
+ * We actually handling that case by noting which cpus startup
+ * and not telling anyone about the ones that dont.
+ */
+static unsigned long get_valid_start_eip(unsigned long orig_start_eip)
+{
+ return (unsigned long)orig_start_eip & 0xffff; // 16 bit to avoid 0xa0000
+}
+
+/**
+ * copy the secondary start POR code to low memory.
+ * Secondary start assembly code is way up in the FLASH ROM.
+ * we have to copy it to low memory since we turn the processor in
+ * in 16-bit mode. This is a bit of a hack at present since there is no real
+ * check for clashes. But hopefully there is no issue. Hmm.
+ */
+static u32 * copy_secondary_start_to_1m_below(void)
+{
+ extern char _secondary_start[];
+ extern char _secondary_start_end[];
+ unsigned long code_size;
+ unsigned long start_eip;
+
+ start_eip = get_valid_start_eip((unsigned long)_secondary_start);
+ code_size = (unsigned long)_secondary_start_end - (unsigned long)_secondary_start;
+
+ /* copy the _secondary_start to the ram below 1M*/
+ memcpy((unsigned char *)start_eip, (unsigned char *)_secondary_start, code_size);
+
+ printk(BIOS_DEBUG, "start_eip=0x%08lx, offset=0x%08lx, code_size=0x%08lx\n", start_eip, ((unsigned long)_secondary_start - start_eip), code_size);
+ return (u32 *)start_eip;
+}
+
+static int lapic_start_cpu(unsigned long apicid, u32 *secondary_base)
+{
+ int timeout;
+ unsigned long send_status, accept_status, start_eip;
+ int j, num_starts, maxlvt;
+ extern char _secondary_start[];
+
+ /*
+ * Starting actual IPI sequence...
+ */
+
+ printk(BIOS_SPEW, "Asserting INIT.\n");
+
+ /*
+ * Turn INIT on target chip
+ */
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+
+ /*
+ * Send IPI
+ */
+
+ lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT
+ | LAPIC_DM_INIT);
+
+ printk(BIOS_SPEW, "Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ printk(BIOS_SPEW, "+");
+ udelay(100);
+ send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+ if (timeout >= 1000) {
+ printk(BIOS_ERR, "CPU %ld: First apic write timed out. Disabling\n",
+ apicid);
+ // too bad.
+ printk(BIOS_ERR, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
+ if (lapic_read(LAPIC_ESR)) {
+ printk(BIOS_ERR, "Try to reset ESR\n");
+ lapic_write_around(LAPIC_ESR, 0);
+ printk(BIOS_ERR, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
+ }
+ return 0;
+ }
+ mdelay(10);
+
+ printk(BIOS_SPEW, "Deasserting INIT.\n");
+
+ /* Target chip */
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+
+ /* Send IPI */
+ lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
+
+ printk(BIOS_SPEW, "Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ printk(BIOS_SPEW, "+");
+ udelay(100);
+ send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+ if (timeout >= 1000) {
+ printk(BIOS_ERR, "CPU %ld: Second apic write timed out. Disabling\n",
+ apicid);
+ // too bad.
+ return 0;
+ }
+
+ /* the first 32 bits of secondary_base is the stack pointer */
+ /* N.B.: + 1 because secondary_base is a u32 *! */
+ start_eip = (u32) (secondary_base + 1);
+ num_starts = 2;
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+ printk(BIOS_SPEW, "#startup loops: %d.\n", num_starts);
+
+ maxlvt = 4;
+
+ for (j = 1; j <= num_starts; j++) {
+ printk(BIOS_SPEW, "Sending STARTUP #%d to %lu.\n", j, apicid);
+ lapic_read_around(LAPIC_SPIV);
+ lapic_write(LAPIC_ESR, 0);
+ lapic_read(LAPIC_ESR);
+ printk(BIOS_SPEW, "After apic_write.\n");
+
+ /*
+ * STARTUP IPI
+ */
+
+ /* Target chip */
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+
+ /* Boot on the stack */
+ /* Kick the second */
+ lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP
+ | (start_eip >> 12));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(300);
+
+ printk(BIOS_SPEW, "Startup point 1.\n");
+
+ printk(BIOS_SPEW, "Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ printk(BIOS_SPEW, "+");
+ udelay(100);
+ send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(200);
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ if (maxlvt > 3) {
+ lapic_read_around(LAPIC_SPIV);
+ lapic_write(LAPIC_ESR, 0);
+ }
+ accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
+ if (send_status || accept_status)
+ break;
+ }
+ printk(BIOS_SPEW, "After Startup.\n");
+ if (send_status)
+ printk(BIOS_WARNING, "APIC never delivered???\n");
+ if (accept_status)
+ printk(BIOS_WARNING, "APIC delivery error (%lx).\n", accept_status);
+ if (send_status || accept_status)
+ return 0;
+ return 1;
+}
+
+/* stack is 16k minus the status pointer */
+/* we compile the secondary start code such that this looks like a stack frame
+ */
+struct stack {
+ u32 post;
+ u32 index;
+ u32 apicid;
+ struct atomic *active_cpus;
+ struct spinlock *start_cpu_lock;
+ u32 callerpc;
+ u32 data[16384/sizeof(u32) - 4];
+};
+
+struct stackmem {
+ unsigned char pagetable[20480];
+ struct stack stacks[0];
+};
+
+int start_cpu(u32 apicid, struct atomic *active_cpus, struct spinlock *start_cpu_lock, int *last_cpu_index, u32 *secondary_base)
+{
+
+ unsigned long stack_end;
+ unsigned long index;
+ unsigned long count;
+ int result;
+ struct stackmem *stackmem = (void *) 0x100000;
+
+ /* Get an index for the new processor */
+
+ index = *last_cpu_index + 1;
+ *last_cpu_index = index;
+
+ /* Find end of the new processors stack */
+ /* on this CPU we are going to always use memory above 1M. Or so we think. */
+ /* since the SP points to data, it will appear as though pc, and other
+ * structure components are on the stack. Thus the BSP and AP
+ * can see them.
+ */
+ stack_end = (u32)&stackmem->stacks[index].data;
+ printk(BIOS_SPEW, "Stack for AP %ld is %lx\n", index, stack_end);
+
+ stackmem->stacks[index].index= index;
+ stackmem->stacks[index].apicid = apicid;
+ stackmem->stacks[index].post = 0;
+ stackmem->stacks[index].active_cpus = active_cpus;
+ stackmem->stacks[index].start_cpu_lock = start_cpu_lock;
+ /* Advertise the new stack to start_cpu */
+ *secondary_base = stack_end;
+
+ /* Start the cpu */
+ result = lapic_start_cpu(apicid, secondary_base);
+
+ if (result) {
+ result = 0;
+ /* Wait 1s or until the new the new cpu calls in */
+ for(count = 0; count < 100000 ; count++) {
+ if (stackmem->stacks[index].post) {
+ result = 1;
+ break;
+ }
+ udelay(10);
+ }
+ }
+ spin_unlock(start_cpu_lock);
+ return result;
+}
+
+/**
+ * Normally this function is defined in lapic.h as an always inline function
+ * that just keeps the CPU in a hlt() loop. This does not work on all CPUs.
+ * I think all hyperthreading CPUs might need this version, but I could only
+ * verify this on the Intel Core Duo
+ */
+void stop_cpu(u32 *post)
+{
+ int timeout;
+ unsigned long send_status;
+ unsigned long lapicid;
+
+ lapicid = lapic_read(LAPIC_ID) >> 24;
+ *post = AP_STOP;
+
+ printk(BIOS_DEBUG, "CPU %ld going down...\n", lapicid);
+
+ /* send an LAPIC INIT to myself */
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid));
+ lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT | LAPIC_DM_INIT);
+ *post = AP_SELFIPI;
+
+ /* wait for the ipi send to finish */
+#if 0
+ // When these two printk_spew calls are not removed, the
+ // machine will hang when log level is SPEW. Why?
+ printk(BIOS_SPEW, "Waiting for send to finish...\n");
+#endif
+ timeout = 0;
+ do {
+#if 0
+ printk(BIOS_SPEW, "+");
+#endif
+ udelay(100);
+ send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+ if (timeout >= 1000) {
+ *post = AP_STOP_FAIL;
+ printk(BIOS_ERR, "timed out\n");
+ }
+ mdelay(10);
+
+ printk(BIOS_SPEW, "Deasserting INIT.\n");
+ /* Deassert the LAPIC INIT */
+ *post = AP_IPIDONE;
+ lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid));
+ lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
+
+ printk(BIOS_SPEW, "Waiting for send to finish...\n");
+ timeout = 0;
+ *post = AP_DOWNINIT;
+ do {
+ printk(BIOS_SPEW, "+");
+ udelay(100);
+ send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+ if (timeout >= 1000) {
+ printk(BIOS_ERR, "timed out\n");
+ }
+
+ while(1) {
+ *post = AP_STOP_OK;
+ hlt();
+ }
+}
+/* C entry point of secondary cpus */
+/* we call this with the stack set up such that the args are visible to BOTH
+ * this function and cpu0. It's an easy trick and a simple way to get shared
+ * memory
+ */
+void __attribute__((regparm(0))) secondary_cpu_init(
+ u32 post,
+ u32 index,
+ u32 apicid,
+ struct atomic *active_cpus,
+ struct spinlock *start_cpu_lock)
+{
+ post = AP_START;
+ atomic_inc(active_cpus);
+ post = AP_ACTIVEUP;
+ if (SERIAL_CPU_INIT && (CONFIG_MAX_PHYSICAL_CPUS > 2))
+ spin_lock(start_cpu_lock);
+ post = AP_LOCKED;
+ cpu_initialize();
+ post = AP_INITDONE;
+ if (SERIAL_CPU_INIT && (CONFIG_MAX_PHYSICAL_CPUS > 2))
+ spin_unlock(start_cpu_lock);
+ post = AP_UNLOCKED;
+
+ atomic_dec(active_cpus);
+ post = AP_ACTIVEDOWN;
+
+ stop_cpu(&post);
+}
+
+/* this is an index, not an apicid */
+static void start_other_cpus(u32 numcpus,struct atomic *active_cpus, struct spinlock *start_cpu_lock, int *last_cpu_index, u32 *secondary_base)
+{
+ int i;
+ /* Loop through the cpus once getting them started */
+
+ for(i = 1; i < numcpus; i++) {
+
+ if (!start_cpu(i, active_cpus, start_cpu_lock, last_cpu_index, secondary_base)) {
+ /* Record the error in cpu? */
+ printk(BIOS_ERR, "CPU 0x%02x would not start!\n", i);
+ }
+
+ if (SERIAL_CPU_INIT && (CONFIG_MAX_PHYSICAL_CPUS > 2))
+ udelay(10);
+ }
+
+}
+
+static void wait_other_cpus_stop(struct atomic *active_cpus)
+{
+ /* todo: walk the stacks and print out POST codes from APs */
+ int old_active_count, active_count;
+ /* Now loop until the other cpus have finished initializing */
+ old_active_count = 1;
+ active_count = atomic_read(active_cpus);
+ while(active_count > 1) {
+ if (active_count != old_active_count) {
+ printk(BIOS_INFO, "Waiting for %d CPUS to stop\n", active_count - 1);
+ old_active_count = active_count;
+ }
+ udelay(10);
+ active_count = atomic_read(active_cpus);
+ }
+ printk(BIOS_DEBUG, "All AP CPUs stopped\n");
+}
+
+/**
+ * Init all the CPUs.
+ * this was unnecessarily tricky in v2 (surprise!)
+ * let's do some math. If you look at the lapic start stuff, we do a few IPIs and spin for 200 microseconds
+ * on them. Then we wait for the CPU to start. This process takes maybe 1 millisecond worst case.
+ * So on core 2, need we worry about serial CPU
+ * vs. parallel CPU init? We need not. In fact in most cases we need not until we get to machines with
+ * huge memory per CPU; we'll do them later. We know how. Further, on v2 there is this
+ * unnecessarily complex atomic CPU mask to support the asynchrony. We're not an OS, we're a B IOS.
+ * Simple rule for parallel
+ * programming: whenever possible, don't have multiple writers for variables.
+ * It's easier and cleaner to give every CPU
+ * its own status word; no atomic ops needed, no worry later about all the problems that come with
+ * them.
+ * So, basic algorithm:
+ * 1. Figure out how many nodes there are
+ * 2. If < 2, done.
+ * 3. Copy the .S-based code to low memory (< 0xa0000) since it starts in 16-bit mode
+ * 4. Craft up a stack. The stack will have info at the base.
+ * The AP will increment this status word as it passes through its startup.
+ * 5. start the AP with appropriate IPI messages.
+ * 6. Wait for AP to transition variable from 0 -> 1 (means started) -> 0xff (means done).
+ * Why 0xff? Because we can use this variable as a POST code! 8 bits are ever so much nicer than one bit.
+ *
+ * @param soft_reset Are we here from a soft reset?
+ * @param sysinfo The sys_info pointer
+ * @returns the BSP APIC ID
+ */
+unsigned int init_cpus(unsigned cpu_init_detectedx,
+ struct sys_info *sysinfo)
+{
+ /* Number of cpus that are currently running in coreboot */
+ struct atomic active_cpus;
+ u32 *secondary_base;
+
+ /* every AP gets a stack. The stacks are linear and start at 0x100000 */
+ struct spinlock start_cpu_lock;
+ int last_cpu_index;
+
+ atomic_set(&active_cpus, 1);
+ start_cpu_lock = SPIN_LOCK_UNLOCKED;
+ last_cpu_index = 0;
+ /* Ensure the local apic is enabled */
+ /* this was conditional in V2 but will always be true in V3. */
+ enable_lapic();
+ // why here? In case some day we can start core1 in amd_sibling_init
+ secondary_base = copy_secondary_start_to_1m_below();
+
+#ifdef CONFIG_SMM
+ smm_init();
+#endif
+
+ if (! SERIAL_CPU_INIT)
+ /* start all aps at first, so we can init ECC all together */
+ start_other_cpus(get_nodes(), &active_cpus, &start_cpu_lock, &last_cpu_index, secondary_base);
+
+ /* Initialize the bootstrap processor */
+ cpu_initialize();
+
+ if (SERIAL_CPU_INIT)
+ start_other_cpus(get_nodes(), &active_cpus, &start_cpu_lock, &last_cpu_index, secondary_base);
+
+ /* Now wait the rest of the cpus stop*/
+ wait_other_cpus_stop(&active_cpus);
+
+ return 0;
+}
+
+#ifdef WAIT_BEFORE_CPUS_INIT
+ #define cpus_ready_for_init() do {} while(0)
+#endif
+
diff --git a/arch/x86/secondary.S b/arch/x86/secondary.S
index 14ec3cc654ec..899f90a50d97 100644
--- a/arch/x86/secondary.S
+++ b/arch/x86/secondary.S
@@ -26,6 +26,7 @@
.balign 4096
_secondary_start:
.code16
+ .long 0
cli
xorl %eax, %eax
movl %eax, %cr3 /* Invalidate TLB*/
@@ -58,18 +59,51 @@ _secondary_start:
/* Load the Interrupt descriptor table */
lidt idtarg
- /* Set the stack pointer, and flag that we are done */
- xorl %eax, %eax
- movl secondary_stack, %esp
- movl %eax, secondary_stack
+ /* Set the stack pointer */
+ movl _secondary_start, %esp
call secondary_cpu_init
1: hlt
jmp 1b
+ .align 4
+
+gdt_limit = gdt_end - gdt - 1 /* Compute the table limit. */
+
+gdt:
+gdtptr:
+ .word gdt_end - gdt -1 /* Compute the table limit. */
+ .long gdt /* We know the offset. */
+ .word 0
+
+ /* selgdt 0x08, flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+ /* selgdt 0x10, flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+
+ /* selgdt 0x18, flat code segment for CAR */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00
+
+ /* selgdt 0x20, flat data segment for CAR */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+gdt_end:
+
gdtaddr:
.word gdt_limit /* the table limit */
.long gdt /* we know the offset */
+idtarg:
+ .word _idt_end - _idt - 1 /* limit */
+ .long _idt
+ .word 0
+_idt:
+ .fill 20, 8, 0 # idt is unitiailzed
+_idt_end:
+
_secondary_start_end:
.code32
diff --git a/include/arch/x86/lapic.h b/include/arch/x86/lapic.h
index e72cded7f5f5..48673dbd9ff5 100644
--- a/include/arch/x86/lapic.h
+++ b/include/arch/x86/lapic.h
@@ -115,7 +115,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
}
-extern inline void lapic_write_atomic(unsigned long reg, unsigned long v)
+static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
{
xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE+reg), v);
}
diff --git a/mainboard/kontron/986lcd-m/Makefile b/mainboard/kontron/986lcd-m/Makefile
index 3ee0443cbef0..c7419ddfcea4 100644
--- a/mainboard/kontron/986lcd-m/Makefile
+++ b/mainboard/kontron/986lcd-m/Makefile
@@ -23,9 +23,13 @@
STAGE0_MAINBOARD_SRC := $(src)/lib/clog2.c \
$(src)/mainboard/$(MAINBOARDDIR)/stage1.c \
$(src)/mainboard/$(MAINBOARDDIR)/stage1_debug.c \
-
INITRAM_SRC= $(src)/mainboard/$(MAINBOARDDIR)/initram.c \
+ $(src)/northbridge/intel/i945//reset_test.c \
+ $(src)/arch/x86/intel/core2/init_cpus.c \
+
+INITRAM_OBJ = \
+ $(obj)/arch/x86/secondary.o \
STAGE2_CHIPSET_SRC=
diff --git a/mainboard/kontron/986lcd-m/initram.c b/mainboard/kontron/986lcd-m/initram.c
index 4d501c671ae8..b1c2d8ba3833 100644
--- a/mainboard/kontron/986lcd-m/initram.c
+++ b/mainboard/kontron/986lcd-m/initram.c
@@ -157,16 +157,30 @@ static void rcba_config(void)
*/
int main(void)
{
+ struct sys_info *sysinfo;
int boot_mode = 0;
void i945_early_initialization(void);
void enable_smbus(void);
int fixup_i945_errata(void);
void i945_late_initialization(void);
void sdram_initialize(int boot_mode);
+ int is_coldboot(void);
+ unsigned int init_cpus(unsigned cpu_init_detectedx,
+ struct sys_info *sysinfo);
- if (MCHBAR16(SSKPD) == 0xCAFE) {
+
+ struct node_core_id me;
+
+// me = get_node_core_id();
+ /* hack */
+ memset(&me, 0, sizeof(me));
+ printk(BIOS_DEBUG, "Hi there from stage1, cpu%d, core%d\n", me.nodeid, me.coreid);
+ post_code(POST_START_OF_MAIN);
+ sysinfo = &(global_vars()->sys_info);
+
+ boot_mode = is_coldboot();
+ if (boot_mode) {
printk(BIOS_DEBUG, "soft reset detected.\n");
- boot_mode = 1;
}
/* Perform some early chipset initialization required
@@ -212,5 +226,8 @@ int main(void)
}
#endif
MCHBAR16(SSKPD) = 0xCAFE;
+
+ init_cpus(boot_mode, sysinfo);
+
return 0;
}
diff --git a/mainboard/kontron/986lcd-m/stage1.c b/mainboard/kontron/986lcd-m/stage1.c
index 781115435a62..f057d5c59caa 100644
--- a/mainboard/kontron/986lcd-m/stage1.c
+++ b/mainboard/kontron/986lcd-m/stage1.c
@@ -208,7 +208,7 @@ void hardware_stage1(void)
void early_superio_config_w83627thg(void);
void ich7_enable_lpc(void);
-#warning Reboot won't work until this is fixed.
+#warning Reboot will not work until this is fixed.
#if 1
/* hack */
diff --git a/mainboard/kontron/Kconfig b/mainboard/kontron/Kconfig
index 99c7566ffc94..526b05bcd8fe 100644
--- a/mainboard/kontron/Kconfig
+++ b/mainboard/kontron/Kconfig
@@ -31,7 +31,7 @@ config BOARD_KONTRON_986LCD_M
select SOUTHBRIDGE_INTEL_I82801GX
select SUPERIO_WINBOND_W83627THG
select PIRQ_TABLE
- select SMM
+# select SMM
help
Kontron 986LCD-M Series mainboards
diff --git a/northbridge/intel/i945/reset_test.c b/northbridge/intel/i945/reset_test.c
index 80d6316d1a62..2f69ed12d493 100644
--- a/northbridge/intel/i945/reset_test.c
+++ b/northbridge/intel/i945/reset_test.c
@@ -16,13 +16,32 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <mainboard.h>
+#include <console.h>
+#include <string.h>
+#include <mtrr.h>
+#include <macros.h>
+#include <spd_ddr2.h>
+#include <cpu.h>
+#include <msr.h>
+#include <device/pci.h>
+#include <pci_ops.h>
+#include <mc146818rtc.h>
+#include <lib.h>
+#include <spd.h>
+#include <io.h>
+#include <types.h>
+#include "raminit.h"
+#include "i945.h"
+#include "pcie_config.h"
-static int bios_reset_detected(void)
+int is_coldboot(void)
{
- /* For now ...
- * DO NOT, I repeat, DO NOT remove this. If you don't like the
- * situation, implement this instead.
- */
- return 0;
+ int boot_mode = 0;
+ if (MCHBAR16(SSKPD) == 0xCAFE) {
+ printk(BIOS_DEBUG, "soft reset detected.\n");
+ boot_mode = 1;
+ }
+ return boot_mode;
}