X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/8b5fcfe2eabb8f50c8211d71788097cd4bfd98ba..abe45f39559867d84370bf61f05b7649cd17a7b9:/sys/platform/pc32/i386/mp_machdep.c diff --git a/sys/platform/pc32/i386/mp_machdep.c b/sys/platform/pc32/i386/mp_machdep.c index 5f1b3bfa92..1be79555eb 100644 --- a/sys/platform/pc32/i386/mp_machdep.c +++ b/sys/platform/pc32/i386/mp_machdep.c @@ -87,7 +87,7 @@ /* MP Floating Pointer Structure */ typedef struct MPFPS { char signature[4]; - void *pap; + u_int32_t pap; u_char length; u_char spec_rev; u_char checksum; @@ -158,6 +158,12 @@ typedef struct BASETABLE_ENTRY { char name[16]; } basetable_entry; +struct mptable_pos { + mpfps_t mp_fps; + mpcth_t mp_cth; + vm_size_t mp_cth_mapsz; +}; + /* * this code MUST be enabled here and in mpboot.s. * it follows the very early stages of AP boot by placing values in CMOS ram. @@ -214,19 +220,20 @@ static int need_hyperthreading_fixup; static u_int logical_cpus; u_int logical_cpus_mask; +static int madt_probe_test; +TUNABLE_INT("hw.madt_probe_test", &madt_probe_test); + /** XXX FIXME: where does this really belong, isa.h/isa.c perhaps? */ int current_postcode; /** XXX FIXME: what system files declare these??? */ extern struct region_descriptor r_gdt, r_idt; -int bsp_apic_ready = 0; /* flags useability of BSP apic */ int mp_naps; /* # of Applications processors */ -int mp_nbusses; /* # of busses */ +static int mp_nbusses; /* # of busses */ #ifdef APIC_IO int mp_napics; /* # of IO APICs */ #endif -int boot_cpu_id; /* designated BSP */ vm_offset_t cpu_apic_address; #ifdef APIC_IO vm_offset_t io_apic_address[NAPICID]; /* NAPICID is more than enough */ @@ -238,6 +245,8 @@ u_int32_t cpu_apic_versions[MAXCPU]; int64_t tsc0_offset; extern int64_t tsc_offsets[]; +extern u_long ebda_addr; + #ifdef APIC_IO struct apic_intmapinfo int_to_apicintpin[APIC_INTMAPSIZE]; #endif @@ -277,20 +286,22 @@ struct pcb stoppcbs[MAXCPU]; * Local data and functions. */ -static int mp_capable; static u_int boot_address; static u_int base_memory; static int mp_finish; -static mpfps_t mpfps; -static int search_for_sig(u_int32_t target, int count); static void mp_enable(u_int boot_addr); +static int mptable_probe(void); +static int mptable_search_sig(u_int32_t target, int count); static void mptable_hyperthread_fixup(u_int id_mask); -static void mptable_pass1(void); -static int mptable_pass2(void); -static void default_mp_table(int type); -static void fix_mp_table(void); +static void mptable_pass1(struct mptable_pos *); +static int mptable_pass2(struct mptable_pos *); +static void mptable_default(int type); +static void mptable_fix(void); +static void mptable_map(struct mptable_pos *, vm_paddr_t); +static void mptable_unmap(struct mptable_pos *); + #ifdef APIC_IO static void setup_apic_irq_mapping(void); static int apic_int_is_bus_type(int intr, int bus_type); @@ -324,11 +335,10 @@ mp_bootaddress(u_int basemem) /* * Look for an Intel MP spec table (ie, SMP capable hardware). */ -int -mp_probe(void) +static int +mptable_probe(void) { int x; - u_long segment; u_int32_t target; /* @@ -340,39 +350,25 @@ mp_probe(void) POSTCODE(MP_PROBE_POST); /* see if EBDA exists */ - if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) { + if (ebda_addr != 0) { /* search first 1K of EBDA */ - target = (u_int32_t) (segment << 4); - if ((x = search_for_sig(target, 1024 / 4)) >= 0) - goto found; + target = (u_int32_t)ebda_addr; + if ((x = mptable_search_sig(target, 1024 / 4)) > 0) + return x; } else { /* last 1K of base memory, effective 'top of base' passed in */ - target = (u_int32_t) (base_memory - 0x400); - if ((x = search_for_sig(target, 1024 / 4)) >= 0) - goto found; + target = (u_int32_t)(base_memory - 0x400); + if ((x = mptable_search_sig(target, 1024 / 4)) > 0) + return x; } /* search the BIOS */ - target = (u_int32_t) BIOS_BASE; - if ((x = search_for_sig(target, BIOS_COUNT)) >= 0) - goto found; + target = (u_int32_t)BIOS_BASE; + if ((x = mptable_search_sig(target, BIOS_COUNT)) > 0) + return x; /* nothing found */ - mpfps = (mpfps_t)0; - mp_capable = 0; return 0; - -found: - /* - * Calculate needed resources. We can safely map physical - * memory into SMPpt after mptable_pass1() completes. - */ - mpfps = (mpfps_t)x; - mptable_pass1(); - - /* flag fact that we are running multiple processors */ - mp_capable = 1; - return 1; } @@ -383,12 +379,7 @@ void mp_start(void) { POSTCODE(MP_START_POST); - - /* look for MP capable motherboard */ - if (mp_capable) - mp_enable(boot_address); - else - panic("MP hardware not found!"); + mp_enable(boot_address); } @@ -508,32 +499,69 @@ mp_enable(u_int boot_addr) int apic; u_int ux; #endif /* APIC_IO */ + vm_paddr_t mpfps_paddr; POSTCODE(MP_ENABLE_POST); - if (cpu_apic_address == 0) - panic("pmap_bootstrap: no local apic!"); + if (madt_probe_test) + mpfps_paddr = 0; + else + mpfps_paddr = mptable_probe(); - /* local apic is mapped on last page */ - SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N | - pmap_get_pgeflag() | (cpu_apic_address & PG_FRAME)); + if (mpfps_paddr) { + struct mptable_pos mpt; - /* turn on 4MB of V == P addressing so we can get to MP table */ - *(int *)PTD = PG_V | PG_RW | ((uintptr_t)(void *)KPTphys & PG_FRAME); - cpu_invltlb(); + mptable_map(&mpt, mpfps_paddr); - /* examine the MP table for needed info, uses physical addresses */ - x = mptable_pass2(); + /* + * We can safely map physical memory into SMPpt after + * mptable_pass1() completes. + */ + mptable_pass1(&mpt); - *(int *)PTD = 0; - cpu_invltlb(); + if (cpu_apic_address == 0) + panic("mp_enable: no local apic (mptable)!\n"); - /* can't process default configs till the CPU APIC is pmapped */ - if (x) - default_mp_table(x); + /* + * Examine the MP table for needed info + */ + x = mptable_pass2(&mpt); + + mptable_unmap(&mpt); - /* post scan cleanup */ - fix_mp_table(); + /* Local apic is mapped on last page */ + SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N | + pmap_get_pgeflag() | (cpu_apic_address & PG_FRAME)); + + /* + * Can't process default configs till the + * CPU APIC is pmapped + */ + if (x) + mptable_default(x); + + /* Post scan cleanup */ + mptable_fix(); + } else { + vm_paddr_t madt_paddr; + int bsp_apic_id; + + madt_paddr = madt_probe(); + if (madt_paddr == 0) + panic("mp_enable: madt_probe failed\n"); + + cpu_apic_address = madt_pass1(madt_paddr); + if (cpu_apic_address == 0) + panic("mp_enable: no local apic (madt)!\n"); + + /* Local apic is mapped on last page */ + SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N | + pmap_get_pgeflag() | (cpu_apic_address & PG_FRAME)); + + bsp_apic_id = (lapic.id & 0xff000000) >> 24; + if (madt_pass2(madt_paddr, bsp_apic_id)) + panic("mp_enable: madt_pass2 failed\n"); + } #if defined(APIC_IO) @@ -590,17 +618,28 @@ mp_enable(u_int boot_addr) #define MP_SIG 0x5f504d5f /* _MP_ */ #define NEXT(X) ((X) += 4) static int -search_for_sig(u_int32_t target, int count) +mptable_search_sig(u_int32_t target, int count) { - int x; - u_int32_t *addr = (u_int32_t *) (KERNBASE + target); + vm_size_t map_size; + u_int32_t *addr; + int x, ret; + + KKASSERT(target != 0); - for (x = 0; x < count; NEXT(x)) - if (addr[x] == MP_SIG) + map_size = count * sizeof(u_int32_t); + addr = pmap_mapdev((vm_paddr_t)target, map_size); + + ret = 0; + for (x = 0; x < count; NEXT(x)) { + if (addr[x] == MP_SIG) { /* make array index a byte index */ - return (target + (x * sizeof(u_int32_t))); + ret = target + (x * sizeof(u_int32_t)); + break; + } + } - return -1; + pmap_unmapdev((vm_offset_t)addr, map_size); + return ret; } @@ -690,9 +729,6 @@ static int lookup_bus_type (char *name); /* * 1st pass on motherboard's Intel MP specification table. * - * initializes: - * ncpus = 1 - * * determines: * cpu_apic_address (common to all CPUs) * io_apic_address[N] @@ -700,13 +736,16 @@ static int lookup_bus_type (char *name); * mp_nbusses * mp_napics * nintrs + * need_hyperthreading_fixup + * logical_cpus */ static void -mptable_pass1(void) +mptable_pass1(struct mptable_pos *mpt) { #ifdef APIC_IO int x; #endif + mpfps_t fps; mpcth_t cth; int totalSize; void* position; @@ -716,6 +755,9 @@ mptable_pass1(void) POSTCODE(MPTABLE_PASS1_POST); + fps = mpt->mp_fps; + KKASSERT(fps != NULL); + #ifdef APIC_IO /* clear various tables */ for (x = 0; x < NAPICID; ++x) { @@ -733,7 +775,7 @@ mptable_pass1(void) id_mask = 0; /* check for use of 'default' configuration */ - if (mpfps->mpfb1 != 0) { + if (fps->mpfb1 != 0) { /* use default addresses */ cpu_apic_address = DEFAULT_APIC_BASE; #ifdef APIC_IO @@ -742,14 +784,15 @@ mptable_pass1(void) /* fill in with defaults */ mp_naps = 2; /* includes BSP */ - mp_nbusses = default_data[mpfps->mpfb1 - 1][0]; + mp_nbusses = default_data[fps->mpfb1 - 1][0]; #if defined(APIC_IO) mp_napics = 1; nintrs = 16; #endif /* APIC_IO */ } else { - if ((cth = mpfps->pap) == 0) + cth = mpt->mp_cth; + if (cth == NULL) panic("MP Configuration Table Header MISSING!"); cpu_apic_address = (vm_offset_t) cth->apic_address; @@ -808,12 +851,6 @@ mptable_pass1(void) /* See if we need to fixup HT logical CPUs. */ mptable_hyperthread_fixup(id_mask); - - /* - * Count the BSP. - * This is also used as a counter while starting the APs. - */ - ncpus = 1; --mp_naps; /* subtract the BSP */ } @@ -823,7 +860,7 @@ mptable_pass1(void) * 2nd pass on motherboard's Intel MP specification table. * * sets: - * boot_cpu_id + * logical_cpus_mask * ID_TO_IO(N), phy APIC ID to log CPU/IO table * CPU_TO_ID(N), logical CPU to APIC ID table * IO_TO_ID(N), logical IO to APIC ID table @@ -831,10 +868,11 @@ mptable_pass1(void) * io_apic_ints[N] */ static int -mptable_pass2(void) +mptable_pass2(struct mptable_pos *mpt) { struct PROCENTRY proc; int x; + mpfps_t fps; mpcth_t cth; int totalSize; void* position; @@ -845,6 +883,9 @@ mptable_pass2(void) POSTCODE(MPTABLE_PASS2_POST); + fps = mpt->mp_fps; + KKASSERT(fps != NULL); + /* Initialize fake proc entry for use with HT fixup. */ bzero(&proc, sizeof(proc)); proc.type = 0; @@ -888,17 +929,15 @@ mptable_pass2(void) } #endif - /* setup the cpu/apic mapping arrays */ - boot_cpu_id = -1; - /* record whether PIC or virtual-wire mode */ - machintr_setvar_simple(MACHINTR_VAR_IMCR_PRESENT, mpfps->mpfb2 & 0x80); + machintr_setvar_simple(MACHINTR_VAR_IMCR_PRESENT, fps->mpfb2 & 0x80); /* check for use of 'default' configuration */ - if (mpfps->mpfb1 != 0) - return mpfps->mpfb1; /* return default configuration type */ + if (fps->mpfb1 != 0) + return fps->mpfb1; /* return default configuration type */ - if ((cth = mpfps->pap) == 0) + cth = mpt->mp_cth; + if (cth == NULL) panic("MP Configuration Table Header MISSING!"); /* walk the table, recording info of interest */ @@ -957,7 +996,7 @@ mptable_pass2(void) position = (uint8_t *)position + basetable_entry_types[type].length; } - if (boot_cpu_id == -1) + if (CPU_TO_ID(0) < 0) panic("NO BSP found!"); /* report fact that its NOT a default configuration */ @@ -979,22 +1018,90 @@ mptable_pass2(void) static void mptable_hyperthread_fixup(u_int id_mask) { - u_int i, id; + int i, id, lcpus_max; - /* Nothing to do if there is no HTT support. */ if ((cpu_feature & CPUID_HTT) == 0) return; - logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - if (logical_cpus <= 1) + + lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16; + if (lcpus_max <= 1) return; + if (strcmp(cpu_vendor, "GenuineIntel") == 0) { + /* + * INSTRUCTION SET REFERENCE, A-M (#253666) + * Page 3-181, Table 3-20 + * "The nearest power-of-2 integer that is not smaller + * than EBX[23:16] is the number of unique initial APIC + * IDs reserved for addressing different logical + * processors in a physical package." + */ + for (i = 0; ; ++i) { + if ((1 << i) >= lcpus_max) { + lcpus_max = 1 << i; + break; + } + } + } + + if (mp_naps == lcpus_max) { + /* We have nothing to fix */ + return; + } else if (mp_naps == 1) { + /* XXX this may be incorrect */ + logical_cpus = lcpus_max; + } else { + int cur, prev, dist; + + /* + * Calculate the distances between two nearest + * APIC IDs. If all such distances are same, + * then it is the number of missing cpus that + * we are going to fill later. + */ + dist = cur = prev = -1; + for (id = 0; id < MAXCPU; ++id) { + if ((id_mask & 1 << id) == 0) + continue; + + cur = id; + if (prev >= 0) { + int new_dist = cur - prev; + + if (dist < 0) + dist = new_dist; + + /* + * Make sure that all distances + * between two nearest APIC IDs + * are same. + */ + if (dist != new_dist) + return; + } + prev = cur; + } + if (dist == 1) + return; + + /* Must be power of 2 */ + if (dist & (dist - 1)) + return; + + /* Can't exceed CPU package capacity */ + if (dist > lcpus_max) + logical_cpus = lcpus_max; + else + logical_cpus = dist; + } + /* * For each APIC ID of a CPU that is set in the mask, * scan the other candidate APIC ID's for this * physical processor. If any of those ID's are * already in the table, then kill the fixup. */ - for (id = 0; id <= MAXCPU; id++) { + for (id = 0; id < MAXCPU; id++) { if ((id_mask & 1 << id) == 0) continue; /* First, make sure we are on a logical_cpus boundary. */ @@ -1013,6 +1120,48 @@ mptable_hyperthread_fixup(u_int id_mask) mp_naps *= logical_cpus; } +static void +mptable_map(struct mptable_pos *mpt, vm_paddr_t mpfps_paddr) +{ + mpfps_t fps = NULL; + mpcth_t cth = NULL; + vm_size_t cth_mapsz = 0; + + fps = pmap_mapdev(mpfps_paddr, sizeof(*fps)); + if (fps->pap != 0) { + /* + * Map configuration table header to get + * the base table size + */ + cth = pmap_mapdev(fps->pap, sizeof(*cth)); + cth_mapsz = cth->base_table_length; + pmap_unmapdev((vm_offset_t)cth, sizeof(*cth)); + + /* + * Map the base table + */ + cth = pmap_mapdev(fps->pap, cth_mapsz); + } + + mpt->mp_fps = fps; + mpt->mp_cth = cth; + mpt->mp_cth_mapsz = cth_mapsz; +} + +static void +mptable_unmap(struct mptable_pos *mpt) +{ + if (mpt->mp_cth != NULL) { + pmap_unmapdev((vm_offset_t)mpt->mp_cth, mpt->mp_cth_mapsz); + mpt->mp_cth = NULL; + mpt->mp_cth_mapsz = 0; + } + if (mpt->mp_fps != NULL) { + pmap_unmapdev((vm_offset_t)mpt->mp_fps, sizeof(*mpt->mp_fps)); + mpt->mp_fps = NULL; + } +} + #ifdef APIC_IO void @@ -1218,7 +1367,7 @@ io_apic_find_int_entry(int apic, int pin) * parse an Intel MP specification table */ static void -fix_mp_table(void) +mptable_fix(void) { int x; #ifdef APIC_IO @@ -1411,9 +1560,18 @@ setup_apic_irq_mapping(void) #endif +void +mp_set_cpuids(int cpu_id, int apic_id) +{ + CPU_TO_ID(cpu_id) = apic_id; + ID_TO_CPU(apic_id) = cpu_id; +} + static int processor_entry(proc_entry_ptr entry, int cpu) { + KKASSERT(cpu > 0); + /* check for usability */ if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) return 0; @@ -1422,16 +1580,13 @@ processor_entry(proc_entry_ptr entry, int cpu) panic("CPU APIC ID out of range (0..%d)", NAPICID - 1); /* check for BSP flag */ if (entry->cpu_flags & PROCENTRY_FLAG_BP) { - boot_cpu_id = entry->apic_id; - CPU_TO_ID(0) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = 0; + mp_set_cpuids(0, entry->apic_id); return 0; /* its already been counted */ } /* add another AP to list, if less than max number of CPUs */ else if (cpu < MAXCPU) { - CPU_TO_ID(cpu) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = cpu; + mp_set_cpuids(cpu, entry->apic_id); return 1; } @@ -1876,9 +2031,9 @@ apic_polarity(int apic, int pin) * FIXME: probably not complete yet... */ static void -default_mp_table(int type) +mptable_default(int type) { - int ap_cpu_id; + int ap_cpu_id, boot_cpu_id; #if defined(APIC_IO) int io_apic_id; int pin; @@ -2056,7 +2211,6 @@ start_all_aps(u_int boot_addr) /* Initialize BSP's local APIC */ apic_initialize(TRUE); - bsp_apic_ready = 1; /* install the AP 1st level boot code */ install_ap_tramp(boot_addr);