- Small step forward Linux boots and almost works...
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@795 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#define APIC 1
|
||||
#endif
|
||||
|
||||
|
||||
static void cache_on(struct mem_range *mem)
|
||||
{
|
||||
post_code(0x60);
|
||||
@@ -90,6 +91,11 @@ static void interrupts_on()
|
||||
| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
|
||||
APIC_DELIVERY_MODE_NMI)
|
||||
);
|
||||
#if 1
|
||||
printk_debug(" apic_id: %d ",
|
||||
apic_read(APIC_ID));
|
||||
#endif
|
||||
|
||||
#else /* APIC */
|
||||
#ifdef i686
|
||||
/* Only Pentium Pro and later have those MSR stuff */
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <arch/pciconf.h>
|
||||
#include <pci.h>
|
||||
#include <pci_ids.h>
|
||||
#include <pci_ops.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <device/pci_ops.h>
|
||||
|
||||
static const struct pci_ops *conf;
|
||||
struct pci_ops {
|
||||
|
86
src/arch/i386/smp/ioapic.c
Normal file
86
src/arch/i386/smp/ioapic.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <console/console.h>
|
||||
#include <arch/ioapic.h>
|
||||
|
||||
/* TODO: this must move to chip/intel */
|
||||
/* we have to do more than we thought. I assumed Linux would do all the
|
||||
* interesting parts, and I was wrong.
|
||||
*/
|
||||
struct ioapicreg {
|
||||
unsigned int reg;
|
||||
unsigned int value_low, value_high;
|
||||
};
|
||||
struct ioapicreg ioapicregvalues[] = {
|
||||
#define ALL (0xff << 24)
|
||||
#define NONE (0)
|
||||
#define DISABLED (1 << 16)
|
||||
#define ENABLED (0 << 16)
|
||||
#define TRIGGER_EDGE (0 << 15)
|
||||
#define TRIGGER_LEVEL (1 << 15)
|
||||
#define POLARITY_HIGH (0 << 13)
|
||||
#define POLARITY_LOW (1 << 13)
|
||||
#define PHYSICAL_DEST (0 << 11)
|
||||
#define LOGICAL_DEST (1 << 11)
|
||||
#define ExtINT (7 << 8)
|
||||
#define NMI (4 << 8)
|
||||
#define SMI (2 << 8)
|
||||
#define INT (1 << 8)
|
||||
/* mask, trigger, polarity, destination, delivery, vector */
|
||||
{0x00, DISABLED, NONE},
|
||||
{0x01, DISABLED, NONE},
|
||||
{0x02, DISABLED, NONE},
|
||||
{0x03, DISABLED, NONE},
|
||||
{0x04, DISABLED, NONE},
|
||||
{0x05, DISABLED, NONE},
|
||||
{0x06, DISABLED, NONE},
|
||||
{0x07, DISABLED, NONE},
|
||||
{0x08, DISABLED, NONE},
|
||||
{0x09, DISABLED, NONE},
|
||||
{0x0a, DISABLED, NONE},
|
||||
{0x0b, DISABLED, NONE},
|
||||
{0x0c, DISABLED, NONE},
|
||||
{0x0d, DISABLED, NONE},
|
||||
{0x0e, DISABLED, NONE},
|
||||
{0x0f, DISABLED, NONE},
|
||||
{0x10, DISABLED, NONE},
|
||||
{0x11, DISABLED, NONE},
|
||||
{0x12, DISABLED, NONE},
|
||||
{0x13, DISABLED, NONE},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x15, DISABLED, NONE},
|
||||
{0x16, DISABLED, NONE},
|
||||
{0x17, DISABLED, NONE},
|
||||
};
|
||||
|
||||
void setup_ioapic(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long value_low, value_high;
|
||||
unsigned long nvram = 0xfec00000;
|
||||
volatile unsigned long *l;
|
||||
struct ioapicreg *a = ioapicregvalues;
|
||||
|
||||
l = (unsigned long *) nvram;
|
||||
#if defined(i786)
|
||||
/* For the pentium 4 and above apic deliver their interrupts
|
||||
* on the front side bus, enable that.
|
||||
*/
|
||||
l[0] = 0x03;
|
||||
l[4] = 1;
|
||||
#endif /* i786 */
|
||||
for (i = 0; i < sizeof(ioapicregvalues) / sizeof(ioapicregvalues[0]);
|
||||
i++, a++) {
|
||||
l[0] = (a->reg * 2) + 0x10;
|
||||
l[4] = a->value_low;
|
||||
value_low = l[4];
|
||||
l[0] = (a->reg *2) + 0x11;
|
||||
l[4] = a->value_high;
|
||||
value_high = l[4];
|
||||
if ((i==0) && (value_low == 0xffffffff)) {
|
||||
printk_warning("IO APIC not responding.\n");
|
||||
return;
|
||||
}
|
||||
printk_spew("for IRQ, reg 0x%08x value 0x%08x 0x%08x\n",
|
||||
a->reg, a->value_low, a->value_high);
|
||||
}
|
||||
}
|
@@ -113,14 +113,13 @@ void smp_write_processors(struct mp_config_table *mc,
|
||||
unsigned long cpu_flag;
|
||||
if(initial_apicid[i]==-1)
|
||||
continue;
|
||||
cpu_flag = MPC_CPU_ENABLED
|
||||
cpu_flag = MPC_CPU_ENABLED;
|
||||
if (processor_map[i] & CPU_BOOTPROCESSOR) {
|
||||
cpu_flag |= MPC_CPU_BOOTPROCESSOR;
|
||||
}
|
||||
smp_write_processor(mc, cpu_apicid, apic_version,
|
||||
cpu_flag, cpu_features, cpu_feature_flags
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
249
src/arch/i386/smp/start_stop.c
Normal file
249
src/arch/i386/smp/start_stop.c
Normal file
@@ -0,0 +1,249 @@
|
||||
#include <smp/start_stop.h>
|
||||
#include <arch/smp/mpspec.h>
|
||||
#include <cpu/p6/apic.h>
|
||||
#include <delay.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef START_CPU_SEG
|
||||
#define START_CPU_SEG 0x90000
|
||||
#endif
|
||||
#if (START_CPU_SEG&0xffff) != 0
|
||||
#error START_CPU_SEG must be 64k aligned
|
||||
#endif
|
||||
|
||||
static inline void hlt(void)
|
||||
{
|
||||
asm("hlt");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long this_processors_id(void)
|
||||
{
|
||||
return apic_read(APIC_ID) >> 24;
|
||||
}
|
||||
|
||||
int processor_index(unsigned long apicid)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < MAX_CPUS; i++) {
|
||||
if (initial_apicid[i] == apicid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void stop_cpu(unsigned long apicid)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long send_status;
|
||||
|
||||
/* send an APIC INIT to myself */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
|
||||
|
||||
/* wait for the ipi send to finish */
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_err("timed out\n");
|
||||
}
|
||||
mdelay(10);
|
||||
|
||||
printk_spew("Deasserting INIT.\n");
|
||||
/* Deassert the APIC INIT */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_err("timed out\n");
|
||||
}
|
||||
|
||||
while(1) {
|
||||
hlt();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
int start_cpu(unsigned long apicid)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long send_status, accept_status, start_eip;
|
||||
int j, num_starts, maxlvt;
|
||||
extern char _secondary_start[];
|
||||
|
||||
/*
|
||||
* Starting actual IPI sequence...
|
||||
*/
|
||||
|
||||
printk_spew("Asserting INIT.\n");
|
||||
|
||||
/*
|
||||
* Turn INIT on target chip
|
||||
*/
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/*
|
||||
* Send IPI
|
||||
*/
|
||||
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
|
||||
| APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_err("CPU %d: First apic write timed out. Disabling\n",
|
||||
apicid);
|
||||
// too bad.
|
||||
printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
|
||||
if (apic_read(APIC_ESR)) {
|
||||
printk_err("Try to reset ESR\n");
|
||||
apic_write_around(APIC_ESR, 0);
|
||||
printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
mdelay(10);
|
||||
|
||||
printk_spew("Deasserting INIT.\n");
|
||||
|
||||
/* Target chip */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/* Send IPI */
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_err("CPU %d: Second apic write timed out. Disabling\n",
|
||||
apicid);
|
||||
// too bad.
|
||||
return 0;
|
||||
}
|
||||
|
||||
start_eip = (unsigned long)_secondary_start;
|
||||
printk_spew("start_eip=0x%08lx\n", start_eip);
|
||||
|
||||
num_starts = 2;
|
||||
|
||||
/*
|
||||
* Run STARTUP IPI loop.
|
||||
*/
|
||||
printk_spew("#startup loops: %d.\n", num_starts);
|
||||
|
||||
maxlvt = 4;
|
||||
|
||||
for (j = 1; j <= num_starts; j++) {
|
||||
printk_spew("Sending STARTUP #%d to %u.\n", j, apicid);
|
||||
apic_read_around(APIC_SPIV);
|
||||
apic_write(APIC_ESR, 0);
|
||||
apic_read(APIC_ESR);
|
||||
printk_spew("After apic_write.\n");
|
||||
|
||||
/*
|
||||
* STARTUP IPI
|
||||
*/
|
||||
|
||||
/* Target chip */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/* Boot on the stack */
|
||||
/* Kick the second */
|
||||
apic_write_around(APIC_ICR, APIC_DM_STARTUP
|
||||
| (start_eip >> 12));
|
||||
|
||||
/*
|
||||
* Give the other CPU some time to accept the IPI.
|
||||
*/
|
||||
udelay(300);
|
||||
|
||||
printk_spew("Startup point 1.\n");
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_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) {
|
||||
apic_read_around(APIC_SPIV);
|
||||
apic_write(APIC_ESR, 0);
|
||||
}
|
||||
accept_status = (apic_read(APIC_ESR) & 0xEF);
|
||||
if (send_status || accept_status)
|
||||
break;
|
||||
}
|
||||
printk_spew("After Startup.\n");
|
||||
if (send_status)
|
||||
printk_warning("APIC never delivered???\n");
|
||||
if (accept_status)
|
||||
printk_warning("APIC delivery error (%lx).\n", accept_status);
|
||||
if (send_status || accept_status)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void startup_other_cpus(unsigned long *processor_map)
|
||||
{
|
||||
unsigned long apicid = this_processors_id();
|
||||
int i;
|
||||
|
||||
/* Assume the cpus are densly packed by apicid */
|
||||
for(i = 0; i < MAX_CPUS; i++) {
|
||||
unsigned long cpu_apicid = initial_apicid[i];
|
||||
if (cpu_apicid == -1) {
|
||||
printk_err("CPU %d not found\n",i);
|
||||
processor_map[i] = 0;
|
||||
continue;
|
||||
}
|
||||
if (cpu_apicid == apicid ) {
|
||||
continue;
|
||||
}
|
||||
if (!start_cpu(cpu_apicid)) {
|
||||
/* Put an error in processor_map[i]? */
|
||||
printk_err("CPU %d/%u would not start!\n",
|
||||
i, cpu_apicid);
|
||||
processor_map[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user