patch-1.3.70 linux/arch/i386/kernel/smp.c
Next file: linux/arch/i386/kernel/time.c
Previous file: linux/arch/i386/kernel/irq.c
Back to the patch index
Back to the overall index
- Lines: 507
- Date:
Fri Mar 1 07:50:38 1996
- Orig file:
v1.3.69/linux/arch/i386/kernel/smp.c
- Orig date:
Wed Feb 28 11:50:00 1996
diff -u --recursive --new-file v1.3.69/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
@@ -7,6 +7,8 @@
* Much of the core SMP work is based on previous work by Thomas Radke, to
* whom a great many thanks are extended.
*
+ * Thanks to Intel for testing against several Pentium and Pentium Pro
+ * MP machines.
*
* This code is released under the GNU public license version 2 or
* later.
@@ -35,12 +37,12 @@
#include <asm/pgtable.h>
#include <asm/smp.h>
-static int smp_found_config=0; /* Have we found an SMP box */
+int smp_found_config=0; /* Have we found an SMP box */
unsigned long cpu_present_map = 0; /* Bitmask of existing CPU's */
int smp_num_cpus; /* Total count of live CPU's */
int smp_threads_ready=0; /* Set when the idlers are all forked */
-volatile unsigned long cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */
+volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */
volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map thats also checked in the spinlock */
struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters */
@@ -49,6 +51,7 @@
unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */
static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
+int apic_version[NR_CPUS]; /* APIC version number */
static volatile int smp_commenced=0; /* Tripped when we start scheduling */
unsigned long apic_addr=0xFEE00000; /* Address of APIC (defaults to 0xFEE00000) */
unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */
@@ -114,6 +117,8 @@
"Unknown","Unknown",
"80486DX/4"
};
+ if(family==0x6)
+ return("Pentium(tm) Pro");
if(family==0x5)
return("Pentium(tm)");
if(family==0x0F && model==0x0F)
@@ -208,7 +213,10 @@
if(m->mpc_apicid>NR_CPUS)
printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
else
+ {
cpu_present_map|=(1<<m->mpc_apicid);
+ apic_version[m->mpc_apicid]=m->mpc_apicver;
+ }
}
mpt+=sizeof(*m);
count+=sizeof(*m);
@@ -345,6 +353,10 @@
else
cpu_present_map=3;
printk("Processors: %d\n", num_processors);
+ /*
+ * Only use the first one found.
+ */
+ return;
}
}
bp+=4;
@@ -494,19 +506,44 @@
void smp_boot_cpus(void)
{
- int i=0;
+ int i,j;
int cpucount=0;
+ unsigned long cfg;
void *stack;
extern unsigned long init_user_stack[];
/*
+ * Initialize the logical to physical cpu number mapping
+ */
+
+ for (i = 0; i < NR_CPUS; i++)
+ cpu_number_map[i] = -1;
+
+ /*
+ * Setup boot CPU information
+ */
+
+ kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */
+
+ smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
+
+ cpu_present_map |= (1 << smp_processor_id());
+ cpu_number_map[boot_cpu_id] = 0;
+ active_kernel_processor=boot_cpu_id;
+
+ /*
+ * If we don't conform to the Intel MPS standard, get out
+ * of here now!
+ */
+
+ if (!smp_found_config)
+ return;
+
+ /*
* Map the local APIC into kernel space
*/
- /* Mapping on non-Intel conforming platforms is a bad move. */
- if (1<cpu_present_map)
- apic_reg = vremap(0xFEE00000,4096);
-
+ apic_reg = vremap(0xFEE00000,4096);
if(apic_reg == NULL)
panic("Unable to map local apic.\n");
@@ -515,39 +552,68 @@
{
int reg;
+ /*
+ * This is to verify that we're looking at
+ * a real local APIC. Check these against
+ * your board if the CPUs aren't getting
+ * started for no apparent reason.
+ */
+
reg = apic_read(APIC_VERSION);
- printk("Getting VERSION: %x\n", reg);
+ SMP_PRINTK(("Getting VERSION: %x\n", reg));
apic_write(APIC_VERSION, 0);
reg = apic_read(APIC_VERSION);
- printk("Getting VERSION: %x\n", reg);
+ SMP_PRINTK(("Getting VERSION: %x\n", reg));
+
+ /*
+ * The two version reads above should print the same
+ * NON-ZERO!!! numbers. If the second one is zero,
+ * there is a problem with the APIC write/read
+ * definitions.
+ *
+ * The next two are just to see if we have sane values.
+ * They're only really relevant if we're in Virtual Wire
+ * compatibility mode, but most boxes are anymore.
+ */
+
reg = apic_read(APIC_LVT0);
- printk("Getting LVT0: %x\n", reg);
+ SMP_PRINTK(("Getting LVT0: %x\n", reg));
reg = apic_read(APIC_LVT1);
- printk("Getting LVT1: %x\n", reg);
+ SMP_PRINTK(("Getting LVT1: %x\n", reg));
}
#endif
/*
- * Now scan the cpu present map and fire up anything we find.
+ * Enable the local APIC
*/
-
- kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */
-
- smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
-
- active_kernel_processor=boot_cpu_id;
+
+ cfg=apic_read(APIC_SPIV);
+ cfg|=(1<<8); /* Enable APIC */
+ apic_write(APIC_SPIV,cfg);
+ udelay(10);
+
+ /*
+ * Now scan the cpu present map and fire up the other CPUs.
+ */
+
SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
for(i=0;i<NR_CPUS;i++)
{
- if((cpu_present_map&(1<<i)) && i!=boot_cpu_id) /* Rebooting yourself is a bad move */
+ /*
+ * Don't even attempt to start the boot CPU!
+ */
+ if (i == boot_cpu_id)
+ continue;
+
+ if (cpu_present_map & (1 << i))
{
- unsigned long cfg, send_status, accept_status;
- int timeout;
+ unsigned long send_status, accept_status;
+ int timeout, num_starts;
/*
* We need a kernel stack for each processor.
@@ -560,16 +626,8 @@
install_trampoline(stack);
printk("Booting processor %d stack %p: ",i,stack); /* So we set whats up */
-
- /*
- * Enable the local APIC
- */
-
- cfg=apic_read(APIC_SPIV);
- cfg|=(1<<8); /* Enable APIC */
- apic_write(APIC_SPIV,cfg);
-
- /*
+
+ /*
* This gunge runs the startup process for
* the targeted processor.
*/
@@ -577,17 +635,24 @@
SMP_PRINTK(("Setting warm reset code and vector.\n"));
/*
- * Needed to boot a 486 board.
+ * Install a writable page 0 entry.
*/
CMOS_WRITE(0xa, 0xf);
pg0[0]=7;
+ local_invalidate();
*((volatile unsigned short *) 0x467) = ((unsigned long)stack)>>4;
*((volatile unsigned short *) 0x469) = 0;
+
+ /*
+ * Protect it again
+ */
+
pg0[0]= pte_val(mk_pte(0, PAGE_READONLY));
+ local_invalidate();
/*
- * Clean up the errors
+ * Be paranoid about clearing APIC errors.
*/
apic_write(APIC_ESR, 0);
@@ -597,9 +662,13 @@
* Status is now clean
*/
- send_status = 0;
+ send_status = 0;
accept_status = 0;
+ /*
+ * Starting actual IPI sequence...
+ */
+
SMP_PRINTK(("Asserting INIT.\n"));
/*
@@ -611,123 +680,76 @@
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xCDFFF; /* Clear bits */
- cfg|=0x0000c500; /* Urgh.. fix for constants */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
apic_write(APIC_ICR, cfg); /* Send IPI */
- timeout = 0;
- do {
- udelay(1000);
- if ((send_status = (!(apic_read(APIC_ICR) & 0x00001000))))
- break;
- } while (timeout++ < 1000);
-
-#ifdef EEK2
- if (send_status) {
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
-#endif
+ udelay(200);
+ SMP_PRINTK(("Deasserting INIT.\n"));
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
/*
- * And off again
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't
+ * send the STARTUP IPIs.
*/
-
- if (send_status && !accept_status)
- {
- SMP_PRINTK(("Deasserting INIT.\n"));
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF; /* Clear bits */
- cfg|=0x00008500;
- apic_write(APIC_ICR, cfg); /* Send IPI */
-
- timeout = 0;
- do {
- udelay(1000);
- if ((send_status = !(apic_read(APIC_ICR) & 0x00001000) ))
- break;
- } while (timeout++ < 1000);
- if (send_status) {
- udelay(1000000);
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
- }
+ if ( apic_version[i] & 0xF0 )
+ num_starts = 2;
+ else
+ num_starts = 0;
/*
- * We currently assume an integrated
- * APIC only, so STARTUP IPIs must be
- * sent as well.
+ * Run STARTUP IPI loop.
*/
- if (send_status && !accept_status)
+ for (j = 0; !(send_status || accept_status)
+ && (j < num_starts) ; j++)
{
- SMP_PRINTK(("Sending first STARTUP.\n"));
-
- /*
- * First STARTUP IPI
- */
-
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF ; /* Clear bits */
- cfg|=APIC_DEST_FIELD|APIC_DEST_DM_STARTUP|(((unsigned long)stack)>>12); /* Boot on the stack */
- apic_write(APIC_ICR, cfg); /* Kick the second */
+ SMP_PRINTK(("Sending STARTUP #%d.\n",j));
- timeout = 0;
- do {
- udelay(1000);
- if ((send_status = !(apic_read(APIC_ICR) & 0x00001000)) )
- break;
- } while (timeout++ < 1000);
-
- if (send_status) {
- udelay(1000000);
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
- }
-
- if (send_status && !accept_status)
- {
- SMP_PRINTK(("Sending second STARTUP.\n"));
+ apic_write(APIC_ESR, 0);
/*
- * Second STARTUP IPI
+ * STARTUP IPI
*/
cfg=apic_read(APIC_ICR2);
cfg&=0x00FFFFFF;
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
cfg=apic_read(APIC_ICR);
- cfg&=~0xCDFFF ; /* Clear bits */
- cfg|=APIC_DEST_FIELD|APIC_DEST_DM_STARTUP|(((unsigned long)stack)>>12); /* Boot on the stack */
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD
+ | APIC_DEST_DM_STARTUP
+ | (((int) stack) >> 12) ); /* Boot on the stack */
apic_write(APIC_ICR, cfg); /* Kick the second */
timeout = 0;
do {
- udelay(1000);
- if ((send_status = !(apic_read(APIC_ICR) & 0x00001000)))
- break;
- } while (timeout++ < 1000);
+ udelay(10);
+ } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
+ && (timeout++ < 1000));
+ udelay(200);
- if (send_status) {
- udelay(1000000);
- apic_write(APIC_ESR, 0);
- accept_status = (apic_read(APIC_ESR) & 0xEF);
- }
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
}
- if (!send_status) /* APIC never delivered?? */
+ if (send_status) /* APIC never delivered?? */
printk("APIC never delivered???\n");
- else if (accept_status) /* Send accept error */
+ if (accept_status) /* Send accept error */
printk("APIC delivery error (%lx).\n", accept_status);
+
+ if( !(send_status || accept_status) )
{
for(timeout=0;timeout<50000;timeout++)
{
@@ -746,28 +768,54 @@
if(*((volatile unsigned char *)8192)==0xA5)
printk("Stuck ??\n");
else
- printk("Not responding val=(%lx).\n", *((unsigned long *) stack));
- cpu_present_map&=~(1<<i);
- cpu_number_map[i] = -1;
+ printk("Not responding.\n");
}
}
/* mark "stuck" area as not stuck */
*((volatile unsigned long *)8192) = 0;
}
- else if (i == boot_cpu_id)
- {
- cpu_number_map[i] = 0;
- }
- else
- {
- cpu_number_map[i] = -1;
- }
-
+
+ /*
+ * Make sure we unmap all failed CPUs
+ */
+
+ if (cpu_number_map[i] == -1)
+ cpu_present_map &= ~(1 << i);
}
+
+ /*
+ * Cleanup possible dangling ends...
+ */
+
+ /*
+ * Install writable page 0 entry.
+ */
+
+ cfg = pg0[0];
+ pg0[0] = 3; /* writeable, present, addr 0 */
+ local_invalidate();
+
+ /*
+ * Paranoid: Set warm reset code and vector here back
+ * to default values.
+ */
+
+ CMOS_WRITE(0, 0xf);
+
+ *((volatile long *) 0x467) = 0;
+
+ /*
+ * Restore old page 0 entry.
+ */
+
+ pg0[0] = cfg;
+ local_invalidate();
+
/*
* Allow the user to impress friends.
*/
+
if(cpucount==0)
{
printk("Error: only one processor found.\n");
@@ -1000,7 +1048,7 @@
* Reschedule call back
*/
-void smp_reschedule_irq(int cpl, struct pt_regs *regs)
+void smp_reschedule_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
#ifdef DEBUGGING_SMP_RESCHED
static int ct=0;
@@ -1101,7 +1149,7 @@
* Message call back.
*/
-void smp_message_irq(int cpl, struct pt_regs *regs)
+void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
int i=smp_processor_id();
/* static int n=0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this