patch-2.3.40 linux/arch/i386/kernel/smpboot.c
Next file: linux/arch/i386/kernel/time.c
Previous file: linux/arch/i386/kernel/smp.c
Back to the patch index
Back to the overall index
- Lines: 1307
- Date:
Thu Jan 20 09:51:42 2000
- Orig file:
v2.3.39/linux/arch/i386/kernel/smpboot.c
- Orig date:
Tue Jan 11 22:31:36 2000
diff -u --recursive --new-file v2.3.39/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
@@ -1,8 +1,8 @@
/*
- * Intel MP v1.1/v1.4 specification compliant parsing routines.
+ * x86 SMP booting functions
*
* (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
- * (c) 1998, 1999 Ingo Molnar <mingo@redhat.com>
+ * (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
*
* Much of the core SMP work is based on previous work by Thomas Radke, to
* whom a great many thanks are extended.
@@ -26,10 +26,8 @@
* Alan Cox : Dumb bug: 'B' step PPro's are fine
* Ingo Molnar : Added APIC timers, based on code
* from Jose Renau
- * Alan Cox : Added EBDA scanning
* Ingo Molnar : various cleanups and rewrites
* Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
- * Maciej W. Rozycki : Bits for genuine 82489DX timers
*/
#include <linux/config.h>
@@ -51,70 +49,28 @@
/* Setup configured maximum number of CPUs to activate */
static int max_cpus = -1;
-/* 1 if "noapic" boot option passed */
-int skip_ioapic_setup = 0;
/* Total count of live CPUs */
int smp_num_cpus = 1;
-/* Internal processor count */
-static unsigned int num_processors = 1;
-/* Have we found an SMP box */
-int smp_found_config = 0;
-
-/* Bitmask of physically existing CPUs */
-unsigned long cpu_present_map = 0;
/* Bitmask of currently online CPUs */
unsigned long cpu_online_map = 0;
-/* which CPU maps to which logical number */
-volatile int cpu_number_map[NR_CPUS];
-/* which logical number maps to which CPU */
-volatile int __cpu_logical_map[NR_CPUS];
+/* which CPU (physical APIC ID) maps to which logical CPU number */
+volatile int x86_apicid_to_cpu[NR_CPUS];
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+volatile int x86_cpu_to_apicid[NR_CPUS];
static volatile unsigned long cpu_callin_map = 0;
static volatile unsigned long cpu_callout_map = 0;
/* Per CPU bogomips and other parameters */
struct cpuinfo_x86 cpu_data[NR_CPUS];
-/* Processor that is doing the boot up */
-static unsigned int boot_cpu_id = 0;
/* Set when the idlers are all forked */
int smp_threads_ready = 0;
/*
- * Various Linux-internal data structures created from the
- * MP-table.
- */
-int apic_version [NR_CPUS];
-int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
-extern int nr_ioapics;
-extern struct mpc_config_ioapic mp_ioapics [MAX_IO_APICS];
-extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
-extern int mpc_default_type;
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
-int mp_current_pci_id = 0;
-unsigned long mp_lapic_addr = 0;
-int pic_mode;
-
-extern void cache_APIC_registers (void);
-
-#define SMP_DEBUG 1
-
-#if SMP_DEBUG
-#define dprintk(x...) printk(##x)
-#else
-#define dprintk(x...)
-#endif
-
-/*
- * IA s/w dev Vol 3, Section 7.4
- */
-#define APIC_DEFAULT_PHYS_BASE 0xfee00000
-
-/*
* Setup routine for controlling SMP activation
*
* Command-line option of "nosmp" or "maxcpus=0" will disable SMP
@@ -142,471 +98,6 @@
__setup("maxcpus=", maxcpus);
/*
- * Intel MP BIOS table parsing routines:
- */
-
-#ifndef CONFIG_X86_VISWS_APIC
-/*
- * Checksum an MP configuration block.
- */
-
-static int __init mpf_checksum(unsigned char *mp, int len)
-{
- int sum=0;
- while(len--)
- sum+=*mp++;
- return sum&0xFF;
-}
-
-/*
- * Processor encoding in an MP configuration block
- */
-
-static char __init *mpc_family(int family,int model)
-{
- static char n[32];
- static char *model_defs[]=
- {
- "80486DX","80486DX",
- "80486SX","80486DX/2 or 80487",
- "80486SL","80486SX/2",
- "Unknown","80486DX/2-WB",
- "80486DX/4","80486DX/4-WB"
- };
-
- switch (family) {
- case 0x04:
- if (model < 10)
- return model_defs[model];
- break;
-
- case 0x05:
- return("Pentium(tm)");
-
- case 0x06:
- return("Pentium(tm) Pro");
-
- case 0x0F:
- if (model == 0x0F)
- return("Special controller");
- }
- sprintf(n,"Unknown CPU [%d:%d]",family, model);
- return n;
-}
-
-static void __init MP_processor_info (struct mpc_config_processor *m)
-{
- int ver;
-
- if (!(m->mpc_cpuflag & CPU_ENABLED))
- return;
-
- printk("Processor #%d %s APIC version %d\n",
- m->mpc_apicid,
- mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 ,
- (m->mpc_cpufeature & CPU_MODEL_MASK)>>4),
- m->mpc_apicver);
-
-#ifdef SMP_DEBUG
- if (m->mpc_featureflag&(1<<0))
- printk(" Floating point unit present.\n");
- if (m->mpc_featureflag&(1<<7))
- printk(" Machine Exception supported.\n");
- if (m->mpc_featureflag&(1<<8))
- printk(" 64 bit compare & exchange supported.\n");
- if (m->mpc_featureflag&(1<<9))
- printk(" Internal APIC present.\n");
-#endif
-
- if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
- dprintk(" Bootup CPU\n");
- boot_cpu_id = m->mpc_apicid;
- } else
- /* Boot CPU already counted */
- num_processors++;
-
- if (m->mpc_apicid > NR_CPUS) {
- printk("Processor #%d unused. (Max %d processors).\n",
- m->mpc_apicid, NR_CPUS);
- return;
- }
- ver = m->mpc_apicver;
-
- cpu_present_map |= (1<<m->mpc_apicid);
- /*
- * Validate version
- */
- if (ver == 0x0) {
- printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
- ver = 0x10;
- }
- apic_version[m->mpc_apicid] = ver;
-}
-
-static void __init MP_bus_info (struct mpc_config_bus *m)
-{
- char str[7];
-
- memcpy(str, m->mpc_bustype, 6);
- str[6] = 0;
- dprintk("Bus #%d is %s\n", m->mpc_busid, str);
-
- if (strncmp(str, "ISA", 3) == 0) {
- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
- } else {
- if (strncmp(str, "EISA", 4) == 0) {
- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
- } else {
- if (strncmp(str, "PCI", 3) == 0) {
- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
- mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
- mp_current_pci_id++;
- } else {
- printk("Unknown bustype %s\n", str);
- panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu");
- } } }
-}
-
-static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
-{
- if (!(m->mpc_flags & MPC_APIC_USABLE))
- return;
-
- printk("I/O APIC #%d Version %d at 0x%lX.\n",
- m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
- if (nr_ioapics >= MAX_IO_APICS) {
- printk("Max # of I/O APICs (%d) exceeded (found %d).\n",
- MAX_IO_APICS, nr_ioapics);
- panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
- }
- mp_ioapics[nr_ioapics] = *m;
- nr_ioapics++;
-}
-
-static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
-{
- mp_irqs [mp_irq_entries] = *m;
- if (++mp_irq_entries == MAX_IRQ_SOURCES)
- panic("Max # of irq sources exceeded!!\n");
-}
-
-static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m)
-{
- /*
- * Well it seems all SMP boards in existence
- * use ExtINT/LVT1 == LINT0 and
- * NMI/LVT2 == LINT1 - the following check
- * will show us if this assumptions is false.
- * Until then we do not have to add baggage.
- */
- if ((m->mpc_irqtype == mp_ExtINT) &&
- (m->mpc_destapiclint != 0))
- BUG();
- if ((m->mpc_irqtype == mp_NMI) &&
- (m->mpc_destapiclint != 1))
- BUG();
-}
-
-/*
- * Read/parse the MPC
- */
-
-static int __init smp_read_mpc(struct mp_config_table *mpc)
-{
- char str[16];
- int count=sizeof(*mpc);
- unsigned char *mpt=((unsigned char *)mpc)+count;
-
- if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
- {
- panic("SMP mptable: bad signature [%c%c%c%c]!\n",
- mpc->mpc_signature[0],
- mpc->mpc_signature[1],
- mpc->mpc_signature[2],
- mpc->mpc_signature[3]);
- return 1;
- }
- if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
- {
- panic("SMP mptable: checksum error!\n");
- return 1;
- }
- if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
- {
- printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
- return 1;
- }
- memcpy(str,mpc->mpc_oem,8);
- str[8]=0;
- printk("OEM ID: %s ",str);
-
- memcpy(str,mpc->mpc_productid,12);
- str[12]=0;
- printk("Product ID: %s ",str);
-
- printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
-
- /* save the local APIC address, it might be non-default */
- mp_lapic_addr = mpc->mpc_lapic;
-
- /*
- * Now process the configuration blocks.
- */
- while (count < mpc->mpc_length) {
- switch(*mpt) {
- case MP_PROCESSOR:
- {
- struct mpc_config_processor *m=
- (struct mpc_config_processor *)mpt;
- MP_processor_info(m);
- mpt += sizeof(*m);
- count += sizeof(*m);
- break;
- }
- case MP_BUS:
- {
- struct mpc_config_bus *m=
- (struct mpc_config_bus *)mpt;
- MP_bus_info(m);
- mpt += sizeof(*m);
- count += sizeof(*m);
- break;
- }
- case MP_IOAPIC:
- {
- struct mpc_config_ioapic *m=
- (struct mpc_config_ioapic *)mpt;
- MP_ioapic_info(m);
- mpt+=sizeof(*m);
- count+=sizeof(*m);
- break;
- }
- case MP_INTSRC:
- {
- struct mpc_config_intsrc *m=
- (struct mpc_config_intsrc *)mpt;
-
- MP_intsrc_info(m);
- mpt+=sizeof(*m);
- count+=sizeof(*m);
- break;
- }
- case MP_LINTSRC:
- {
- struct mpc_config_lintsrc *m=
- (struct mpc_config_lintsrc *)mpt;
- MP_lintsrc_info(m);
- mpt+=sizeof(*m);
- count+=sizeof(*m);
- break;
- }
- }
- }
- return num_processors;
-}
-
-/*
- * Scan the memory blocks for an SMP configuration block.
- */
-static int __init smp_get_mpf(struct intel_mp_floating *mpf)
-{
- printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
- if (mpf->mpf_feature2 & (1<<7)) {
- printk(" IMCR and PIC compatibility mode.\n");
- pic_mode = 1;
- } else {
- printk(" Virtual Wire compatibility mode.\n");
- pic_mode = 0;
- }
- smp_found_config = 1;
- /*
- * default CPU id - if it's different in the mptable
- * then we change it before first using it.
- */
- boot_cpu_id = 0;
- /*
- * Now see if we need to read further.
- */
- if (mpf->mpf_feature1 != 0) {
- /*
- * local APIC has default address
- */
- mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-
- /*
- * 2 CPUs, numbered 0 & 1.
- */
- cpu_present_map = 3;
- num_processors = 2;
-
- nr_ioapics = 1;
- mp_ioapics[0].mpc_apicaddr = 0xFEC00000;
- /*
- * Save the default type number, we
- * need it later to set the IO-APIC
- * up properly:
- */
- mpc_default_type = mpf->mpf_feature1;
-
- printk("Bus #0 is ");
- }
-
- switch (mpf->mpf_feature1) {
- case 1:
- case 5:
- printk("ISA\n");
- break;
- case 2:
- printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n");
- break;
- case 6:
- case 3:
- printk("EISA\n");
- break;
- case 4:
- case 7:
- printk("MCA\n");
- break;
- case 0:
- if (!mpf->mpf_physptr)
- BUG();
- break;
- default:
- printk("???\nUnknown standard configuration %d\n",
- mpf->mpf_feature1);
- return 1;
- }
- if (mpf->mpf_feature1 > 4) {
- printk("Bus #1 is PCI\n");
-
- /*
- * Set local APIC version to the integrated form.
- * It's initialized to zero otherwise, representing
- * a discrete 82489DX.
- */
- apic_version[0] = 0x10;
- apic_version[1] = 0x10;
- }
- /*
- * Read the physical hardware table. Anything here will override the
- * defaults.
- */
- if (mpf->mpf_physptr)
- smp_read_mpc((void *)mpf->mpf_physptr);
-
- __cpu_logical_map[0] = boot_cpu_id;
- global_irq_holder = boot_cpu_id;
- current->processor = boot_cpu_id;
-
- printk("Processors: %d\n", num_processors);
- /*
- * Only use the first configuration found.
- */
- return 1;
-}
-
-static int __init smp_scan_config(unsigned long base, unsigned long length)
-{
- unsigned long *bp = phys_to_virt(base);
- struct intel_mp_floating *mpf;
-
- dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
- if (sizeof(*mpf) != 16)
- printk("Error: MPF size\n");
-
- while (length > 0) {
- mpf = (struct intel_mp_floating *)bp;
- if ((*bp == SMP_MAGIC_IDENT) &&
- (mpf->mpf_length == 1) &&
- !mpf_checksum((unsigned char *)bp, 16) &&
- ((mpf->mpf_specification == 1)
- || (mpf->mpf_specification == 4)) ) {
-
- printk("found SMP MP-table at %08ld\n",
- virt_to_phys(mpf));
- smp_get_mpf(mpf);
- return 1;
- }
- bp += 4;
- length -= 16;
- }
- return 0;
-}
-
-void __init init_intel_smp (void)
-{
- unsigned int address;
-
- /*
- * FIXME: Linux assumes you have 640K of base ram..
- * this continues the error...
- *
- * 1) Scan the bottom 1K for a signature
- * 2) Scan the top 1K of base RAM
- * 3) Scan the 64K of bios
- */
- if (smp_scan_config(0x0,0x400) ||
- smp_scan_config(639*0x400,0x400) ||
- smp_scan_config(0xF0000,0x10000))
- return;
- /*
- * If it is an SMP machine we should know now, unless the
- * configuration is in an EISA/MCA bus machine with an
- * extended bios data area.
- *
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E, calculate and scan it here.
- *
- * NOTE! There are Linux loaders that will corrupt the EBDA
- * area, and as such this kind of SMP config may be less
- * trustworthy, simply because the SMP table may have been
- * stomped on during early boot. These loaders are buggy and
- * should be fixed.
- */
-
- address = *(unsigned short *)phys_to_virt(0x40E);
- address <<= 4;
- smp_scan_config(address, 0x1000);
- if (smp_found_config)
- printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");
-}
-
-#else
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesnt have a BIOS(-configuration table).
- * No problem for Linux.
- */
-void __init init_visws_smp(void)
-{
- smp_found_config = 1;
-
- cpu_present_map |= 2; /* or in id 1 */
- apic_version[1] |= 0x10; /* integrated APIC */
- apic_version[0] |= 0x10;
-
- mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-#endif
-
-/*
- * - Intel MP Configuration Table
- * - or SGI Visual Workstation configuration
- */
-void __init init_smp_config (void)
-{
-#ifndef CONFIG_VISWS
- init_intel_smp();
-#else
- init_visws_smp();
-#endif
-}
-
-
-
-/*
* Trampoline 80x86 program as an array.
*/
@@ -686,209 +177,12 @@
/*
* Lets the callins below out of their loop.
*/
- dprintk("Setting commenced=1, go go go\n");
+ Dprintk("Setting commenced=1, go go go\n");
wmb();
atomic_set(&smp_commenced,1);
}
-extern void __error_in_io_apic_c(void);
-
-
-int get_maxlvt(void)
-{
- unsigned int v, ver, maxlvt;
-
- v = apic_read(APIC_LVR);
- ver = GET_APIC_VERSION(v);
- /* 82489DXs do not report # of LVT entries. */
- maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
- return maxlvt;
-}
-
-void disable_local_APIC (void)
-{
- unsigned long value;
- int maxlvt;
-
- /*
- * Disable APIC
- */
- value = apic_read(APIC_SPIV);
- value &= ~(1<<8);
- apic_write(APIC_SPIV,value);
-
- /*
- * Clean APIC state for other OSs:
- */
- value = apic_read(APIC_SPIV);
- value &= ~(1<<8);
- apic_write(APIC_SPIV,value);
- maxlvt = get_maxlvt();
- apic_write_around(APIC_LVTT, 0x00010000);
- apic_write_around(APIC_LVT0, 0x00010000);
- apic_write_around(APIC_LVT1, 0x00010000);
- if (maxlvt >= 3)
- apic_write_around(APIC_LVTERR, 0x00010000);
- if (maxlvt >= 4)
- apic_write_around(APIC_LVTPC, 0x00010000);
-}
-
-void __init setup_local_APIC (void)
-{
- unsigned long value, ver, maxlvt;
-
- if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f)
- __error_in_io_apic_c();
-
- value = apic_read(APIC_SPIV);
- /*
- * Enable APIC
- */
- value |= (1<<8);
-
- /*
- * Some unknown Intel IO/APIC (or APIC) errata is biting us with
- * certain networking cards. If high frequency interrupts are
- * happening on a particular IOAPIC pin, plus the IOAPIC routing
- * entry is masked/unmasked at a high rate as well then sooner or
- * later IOAPIC line gets 'stuck', no more interrupts are received
- * from the device. If focus CPU is disabled then the hang goes
- * away, oh well :-(
- *
- * [ This bug can be reproduced easily with a level-triggered
- * PCI Ne2000 networking cards and PII/PIII processors, dual
- * BX chipset. ]
- */
-#if 0
- /* Enable focus processor (bit==0) */
- value &= ~(1<<9);
-#else
- /* Disable focus processor (bit==1) */
- value |= (1<<9);
-#endif
- /*
- * Set spurious IRQ vector
- */
- value |= SPURIOUS_APIC_VECTOR;
- apic_write(APIC_SPIV,value);
-
- /*
- * Set up LVT0, LVT1:
- *
- * set up through-local-APIC on the BP's LINT0. This is not
- * strictly necessery in pure symmetric-IO mode, but sometimes
- * we delegate interrupts to the 8259A.
- */
- if (hard_smp_processor_id() == boot_cpu_id) {
- value = 0x00000700;
- printk("enabled ExtINT on CPU#%d\n", hard_smp_processor_id());
- } else {
- value = 0x00010700;
- printk("masked ExtINT on CPU#%d\n", hard_smp_processor_id());
- }
- apic_write_around(APIC_LVT0,value);
-
- /*
- * only the BP should see the LINT1 NMI signal, obviously.
- */
- if (hard_smp_processor_id() == boot_cpu_id)
- value = 0x00000400; // unmask NMI
- else
- value = 0x00010400; // mask NMI
- apic_write_around(APIC_LVT1,value);
-
- value = apic_read(APIC_LVR);
- ver = GET_APIC_VERSION(value);
- if (APIC_INTEGRATED(ver)) { /* !82489DX */
- maxlvt = get_maxlvt();
- /*
- * Due to the Pentium erratum 3AP.
- */
- if (maxlvt > 3) {
- apic_readaround(APIC_SPIV); // not strictly necessery
- apic_write(APIC_ESR, 0);
- }
- value = apic_read(APIC_ESR);
- printk("ESR value before enabling vector: %08lx\n", value);
-
- value = apic_read(APIC_LVTERR);
- value = ERROR_APIC_VECTOR; // enables sending errors
- apic_write(APIC_LVTERR,value);
- /*
- * spec says clear errors after enabling vector.
- */
- if (maxlvt != 3) {
- apic_readaround(APIC_SPIV);
- apic_write(APIC_ESR, 0);
- }
- value = apic_read(APIC_ESR);
- printk("ESR value after enabling vector: %08lx\n", value);
- } else
- printk("No ESR for 82489DX.\n");
-
- /*
- * Set Task Priority to 'accept all'. We never change this
- * later on.
- */
- value = apic_read(APIC_TASKPRI);
- value &= ~APIC_TPRI_MASK;
- apic_write(APIC_TASKPRI,value);
-
- /*
- * Set up the logical destination ID and put the
- * APIC into flat delivery mode.
- */
- value = apic_read(APIC_LDR);
- value &= ~APIC_LDR_MASK;
- value |= (1<<(smp_processor_id()+24));
- apic_write(APIC_LDR,value);
-
- value = apic_read(APIC_DFR);
- value |= SET_APIC_DFR(0xf);
- apic_write(APIC_DFR, value);
-}
-
-void __init init_smp_mappings(void)
-{
- unsigned long apic_phys;
-
- if (smp_found_config) {
- apic_phys = mp_lapic_addr;
- } else {
- /*
- * set up a fake all zeroes page to simulate the
- * local APIC and another one for the IO-APIC. We
- * could use the real zero-page, but it's safer
- * this way if some buggy code writes to this page ...
- */
- apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
- apic_phys = __pa(apic_phys);
- }
- set_fixmap(FIX_APIC_BASE, apic_phys);
- dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
-
-#ifdef CONFIG_X86_IO_APIC
- {
- unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
- int i;
-
- for (i = 0; i < nr_ioapics; i++) {
- if (smp_found_config) {
- ioapic_phys = mp_ioapics[i].mpc_apicaddr;
- } else {
- ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
- ioapic_phys = __pa(ioapic_phys);
- }
- set_fixmap(idx,ioapic_phys);
- dprintk("mapped IOAPIC to %08lx (%08lx)\n",
- __fix_to_virt(idx), ioapic_phys);
- idx++;
- }
- }
-#endif
-}
-
/*
* TSC synchronization.
*
@@ -988,20 +282,14 @@
}
sum = 0;
- for (i = 0; i < NR_CPUS; i++) {
- if (!(cpu_online_map & (1 << i)))
- continue;
-
+ for (i = 0; i < smp_num_cpus; i++) {
t0 = tsc_values[i];
sum += t0;
}
avg = div64(sum, smp_num_cpus);
sum = 0;
- for (i = 0; i < NR_CPUS; i++) {
- if (!(cpu_online_map & (1 << i)))
- continue;
-
+ for (i = 0; i < smp_num_cpus; i++) {
delta = tsc_values[i] - avg;
if (delta < 0)
delta = -delta;
@@ -1057,15 +345,20 @@
void __init smp_callin(void)
{
- int cpuid;
+ int cpuid, phys_id;
unsigned long timeout;
/*
* (This works even if the APIC is not enabled.)
*/
- cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
- dprintk("CPU#%d waiting for CALLOUT\n", cpuid);
+ phys_id = GET_APIC_ID(apic_read(APIC_ID));
+ cpuid = current->processor;
+ if (test_and_set_bit(cpuid, &cpu_online_map)) {
+ printk("huh, phys CPU#%d, CPU#%d already present??\n",
+ phys_id, cpuid);
+ BUG();
+ }
+ Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
/*
* STARTUP IPIs are fragile beasts as they might sometimes
@@ -1100,7 +393,7 @@
* boards)
*/
- dprintk("CALLIN, before setup_local_APIC().\n");
+ Dprintk("CALLIN, before setup_local_APIC().\n");
setup_local_APIC();
sti();
@@ -1115,7 +408,7 @@
* Get our bogomips.
*/
calibrate_delay();
- dprintk("Stack at about %p\n",&cpuid);
+ Dprintk("Stack at about %p\n",&cpuid);
/*
* Save our processor parameters
@@ -1131,7 +424,7 @@
* Synchronize the TSC with the BP
*/
if (cpu_has_tsc)
- synchronize_tsc_ap ();
+ synchronize_tsc_ap();
}
int cpucount = 0;
@@ -1196,21 +489,21 @@
return do_fork(CLONE_VM|CLONE_PID, 0, ®s);
}
-static void __init do_boot_cpu(int i)
+static void __init do_boot_cpu (int apicid)
{
unsigned long cfg;
struct task_struct *idle;
unsigned long send_status, accept_status;
- int timeout, num_starts, j;
+ int timeout, num_starts, j, cpu;
unsigned long start_eip;
- cpucount++;
+ cpu = ++cpucount;
/*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
if (fork_by_hand() < 0)
- panic("failed fork for CPU %d", i);
+ panic("failed fork for CPU %d", cpu);
/*
* We remove it from the pidhash and the runqueue
@@ -1218,23 +511,23 @@
*/
idle = init_task.prev_task;
if (!idle)
- panic("No idle process for CPU %d", i);
+ panic("No idle process for CPU %d", cpu);
- idle->processor = i;
- __cpu_logical_map[cpucount] = i;
- cpu_number_map[i] = cpucount;
+ idle->processor = cpu;
+ x86_cpu_to_apicid[cpu] = apicid;
+ x86_apicid_to_cpu[apicid] = cpu;
idle->has_cpu = 1; /* we schedule the first task manually */
idle->thread.eip = (unsigned long) start_secondary;
del_from_runqueue(idle);
unhash_process(idle);
- init_tasks[cpucount] = idle;
+ init_tasks[cpu] = idle;
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();
/* So we see what's up */
- printk("Booting processor %d eip %lx\n", i, start_eip);
+ printk("Booting processor %d eip %lx\n", cpu, start_eip);
stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
/*
@@ -1242,21 +535,20 @@
* the targeted processor.
*/
- dprintk("Setting warm reset code and vector.\n");
+ Dprintk("Setting warm reset code and vector.\n");
CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
- dprintk("1.\n");
+ Dprintk("1.\n");
*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
- dprintk("2.\n");
+ Dprintk("2.\n");
*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
- dprintk("3.\n");
+ Dprintk("3.\n");
/*
* Be paranoid about clearing APIC errors.
*/
-
- if (APIC_INTEGRATED(apic_version[i])) {
+ if (APIC_INTEGRATED(apic_version[apicid])) {
apic_readaround(APIC_SPIV);
apic_write(APIC_ESR, 0);
accept_status = (apic_read(APIC_ESR) & 0xEF);
@@ -1272,7 +564,7 @@
* Starting actual IPI sequence...
*/
- dprintk("Asserting INIT.\n");
+ Dprintk("Asserting INIT.\n");
/*
* Turn INIT on
@@ -1283,7 +575,7 @@
/*
* Target chip
*/
- apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(i));
+ apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
/*
* Send IPI
@@ -1294,12 +586,12 @@
apic_write(APIC_ICR, cfg);
udelay(200);
- dprintk("Deasserting INIT.\n");
+ Dprintk("Deasserting INIT.\n");
/* Target chip */
cfg = apic_read(APIC_ICR2);
cfg &= 0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(apicid));
/* Send IPI */
cfg = apic_read(APIC_ICR);
@@ -1314,8 +606,7 @@
* If we don't have an integrated APIC, don't
* send the STARTUP IPIs.
*/
-
- if (APIC_INTEGRATED(apic_version[i]))
+ if (APIC_INTEGRATED(apic_version[apicid]))
num_starts = 2;
else
num_starts = 0;
@@ -1323,13 +614,14 @@
/*
* Run STARTUP IPI loop.
*/
+ Dprintk("#startup loops: %d.\n", num_starts);
for (j = 1; j <= num_starts; j++) {
- dprintk("Sending STARTUP #%d.\n",j);
+ Dprintk("Sending STARTUP #%d.\n",j);
apic_readaround(APIC_SPIV);
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
- dprintk("After apic_write.\n");
+ Dprintk("After apic_write.\n");
/*
* STARTUP IPI
@@ -1338,7 +630,7 @@
/* Target chip */
cfg = apic_read(APIC_ICR2);
cfg &= 0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i));
+ apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(apicid));
/* Boot on the stack */
cfg = apic_read(APIC_ICR);
@@ -1348,12 +640,12 @@
/* Kick the second */
apic_write(APIC_ICR, cfg);
- dprintk("Startup point 1.\n");
+ Dprintk("Startup point 1.\n");
- dprintk("Waiting for send to finish...\n");
+ Dprintk("Waiting for send to finish...\n");
timeout = 0;
do {
- dprintk("+");
+ Dprintk("+");
udelay(100);
send_status = apic_read(APIC_ICR) & 0x1000;
} while (send_status && (timeout++ < 1000));
@@ -1366,7 +658,7 @@
if (send_status || accept_status)
break;
}
- dprintk("After Startup.\n");
+ Dprintk("After Startup.\n");
if (send_status)
printk("APIC never delivered???\n");
@@ -1377,24 +669,24 @@
/*
* allow APs to start initializing.
*/
- dprintk("Before Callout %d.\n", i);
- set_bit(i, &cpu_callout_map);
- dprintk("After Callout %d.\n", i);
+ Dprintk("Before Callout %d.\n", cpu);
+ set_bit(cpu, &cpu_callout_map);
+ Dprintk("After Callout %d.\n", cpu);
/*
* Wait 5s total for a response
*/
- for (timeout = 0; timeout < 50000; timeout++) {
- if (test_bit(i, &cpu_callin_map))
+ for (timeout = 0; timeout < 1000000000; timeout++) {
+ if (test_bit(cpu, &cpu_callin_map))
break; /* It has booted */
udelay(100);
}
- if (test_bit(i, &cpu_callin_map)) {
+ if (test_bit(cpu, &cpu_callin_map)) {
/* number CPUs logically, starting from 1 (BSP is 0) */
- printk("OK.\n");
- printk("CPU%d: ", i);
- print_cpu_info(&cpu_data[i]);
+ Dprintk("OK.\n");
+ printk("CPU%d: ", cpu);
+ print_cpu_info(&cpu_data[cpu]);
} else {
if (*((volatile unsigned char *)phys_to_virt(8192))
== 0xA5) /* trampoline code not run */
@@ -1402,10 +694,10 @@
else
printk("CPU booted but not responding.\n");
}
- dprintk("CPU has booted.\n");
+ Dprintk("CPU has booted.\n");
} else {
- __cpu_logical_map[cpucount] = -1;
- cpu_number_map[i] = -1;
+ x86_cpu_to_apicid[cpu] = -1;
+ x86_apicid_to_cpu[apicid] = -1;
cpucount--;
}
@@ -1460,7 +752,7 @@
void __init smp_boot_cpus(void)
{
- int i;
+ int apicid, cpu;
#ifdef CONFIG_MTRR
/* Must be done before other processors booted */
@@ -1471,58 +763,63 @@
* and the per-CPU profiling counter/multiplier
*/
- for (i = 0; i < NR_CPUS; i++) {
- cpu_number_map[i] = -1;
- prof_counter[i] = 1;
- prof_old_multiplier[i] = 1;
- prof_multiplier[i] = 1;
+ for (apicid = 0; apicid < NR_CPUS; apicid++) {
+ x86_apicid_to_cpu[apicid] = -1;
+ prof_counter[apicid] = 1;
+ prof_old_multiplier[apicid] = 1;
+ prof_multiplier[apicid] = 1;
}
/*
* Setup boot CPU information
*/
-
- smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
- smp_tune_scheduling();
- printk("CPU%d: ", boot_cpu_id);
- print_cpu_info(&cpu_data[boot_cpu_id]);
+ smp_store_cpu_info(0); /* Final full version of the data */
+ printk("CPU%d: ", 0);
+ print_cpu_info(&cpu_data[0]);
/*
- * not necessary because the MP table should list the boot
- * CPU too, but we do it for the sake of robustness anyway.
- * (and for the case when a non-SMP board boots an SMP kernel)
- */
- cpu_present_map |= (1 << hard_smp_processor_id());
-
- cpu_number_map[boot_cpu_id] = 0;
-
+ * We have the boot CPU online for sure.
+ */
+ set_bit(0, &cpu_online_map);
+ x86_apicid_to_cpu[boot_cpu_id] = 0;
+ x86_cpu_to_apicid[0] = boot_cpu_id;
+ global_irq_holder = 0;
+ current->processor = 0;
init_idle();
+ smp_tune_scheduling();
/*
* If we couldnt find an SMP configuration at boot time,
* get out of here now!
*/
-
if (!smp_found_config) {
printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
#ifndef CONFIG_VISWS
io_apic_irqs = 0;
#endif
- cpu_online_map = cpu_present_map;
+ cpu_online_map = phys_cpu_present_map = 1;
smp_num_cpus = 1;
goto smp_done;
}
/*
- * If SMP should be disabled, then really disable it!
+ * Should not be necessary because the MP table should list the boot
+ * CPU too, but we do it for the sake of robustness anyway.
*/
+ if (!test_bit(boot_cpu_id, &phys_cpu_present_map)) {
+ printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
+ boot_cpu_id);
+ phys_cpu_present_map |= (1 << hard_smp_processor_id());
+ }
+ /*
+ * If SMP should be disabled, then really disable it!
+ */
if (!max_cpus) {
smp_found_config = 0;
printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
}
-#ifdef SMP_DEBUG
{
int reg;
@@ -1534,11 +831,11 @@
*/
reg = apic_read(APIC_LVR);
- dprintk("Getting VERSION: %x\n", reg);
+ Dprintk("Getting VERSION: %x\n", reg);
apic_write(APIC_LVR, 0);
reg = apic_read(APIC_LVR);
- dprintk("Getting VERSION: %x\n", reg);
+ Dprintk("Getting VERSION: %x\n", reg);
/*
* The two version reads above should print the same
@@ -1551,14 +848,12 @@
* compatibility mode, but most boxes are anymore.
*/
-
reg = apic_read(APIC_LVT0);
- dprintk("Getting LVT0: %x\n", reg);
+ Dprintk("Getting LVT0: %x\n", reg);
reg = apic_read(APIC_LVT1);
- dprintk("Getting LVT1: %x\n", reg);
+ Dprintk("Getting LVT1: %x\n", reg);
}
-#endif
setup_local_APIC();
@@ -1568,42 +863,33 @@
/*
* Now scan the CPU present map and fire up the other CPUs.
*/
+ Dprintk("CPU present map: %lx\n", phys_cpu_present_map);
- /*
- * Add all detected CPUs. (later on we can down individual
- * CPUs which will change cpu_online_map but not necessarily
- * cpu_present_map. We are pretty much ready for hot-swap CPUs.)
- */
- cpu_online_map = cpu_present_map;
- mb();
-
- dprintk("CPU map: %lx\n", cpu_present_map);
-
- for (i = 0; i < NR_CPUS; i++) {
+ for (apicid = 0; apicid < NR_CPUS; apicid++) {
/*
* Don't even attempt to start the boot CPU!
*/
- if (i == boot_cpu_id)
+ if (apicid == boot_cpu_id)
continue;
- if ((cpu_online_map & (1 << i))
- && (max_cpus < 0 || max_cpus > cpucount+1)) {
- do_boot_cpu(i);
- }
+ if (!(phys_cpu_present_map & (1 << apicid)))
+ continue;
+ if ((max_cpus >= 0) && (max_cpus < cpucount+1))
+ continue;
+
+ do_boot_cpu(apicid);
/*
* Make sure we unmap all failed CPUs
*/
- if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) {
- printk("CPU #%d not responding - cannot use it.\n",i);
- cpu_online_map &= ~(1 << i);
- }
+ if ((x86_apicid_to_cpu[apicid] == -1) &&
+ (phys_cpu_present_map & (1 << apicid)))
+ printk("phys CPU #%d not responding - cannot use it.\n",apicid);
}
/*
* Cleanup possible dangling ends...
*/
-
#ifndef CONFIG_VISWS
{
/*
@@ -1625,26 +911,25 @@
* Allow the user to impress friends.
*/
- dprintk("Before bogomips.\n");
+ Dprintk("Before bogomips.\n");
if (!cpucount) {
printk(KERN_ERR "Error: only one processor found.\n");
- cpu_online_map = (1<<hard_smp_processor_id());
} else {
unsigned long bogosum = 0;
- for(i = 0; i < 32; i++)
- if (cpu_online_map&(1<<i))
- bogosum+=cpu_data[i].loops_per_sec;
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ if (cpu_online_map & (1<<cpu))
+ bogosum += cpu_data[cpu].loops_per_sec;
printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
cpucount+1,
(bogosum+2500)/500000,
((bogosum+2500)/5000)%100);
- dprintk("Before bogocount - setting activated=1.\n");
+ Dprintk("Before bogocount - setting activated=1.\n");
}
smp_num_cpus = cpucount + 1;
if (smp_b_stepping)
printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
- dprintk("Boot done.\n");
+ Dprintk("Boot done.\n");
cache_APIC_registers();
#ifndef CONFIG_VISWS
@@ -1657,12 +942,6 @@
#endif
smp_done:
- /*
- * now we know the other CPUs have fired off and we know our
- * APIC ID, so we can go init the TSS and stuff:
- */
- cpu_init();
-
/*
* Set up all local APIC timers in the system:
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)