Staticize mp_nbusses
[dragonfly.git] / sys / platform / pc32 / i386 / mp_machdep.c
index e042a13..1be7955 100644 (file)
@@ -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 */
@@ -283,15 +290,18 @@ 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);
@@ -325,8 +335,8 @@ 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_int32_t target;
@@ -343,33 +353,22 @@ mp_probe(void)
        if (ebda_addr != 0) {
                /* search first 1K of EBDA */
                target = (u_int32_t)ebda_addr;
-               if ((x = search_for_sig(target, 1024 / 4)) >= 0)
-                       goto found;
+               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;
        return 0;
-
-found:
-       /*
-        * Calculate needed resources.  We can safely map physical
-        * memory into SMPpt after mptable_pass1() completes.
-        */
-       mpfps = (mpfps_t)x;
-       mptable_pass1();
-
-       return 1;
 }
 
 
@@ -500,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);
+
+               /*
+                * We can safely map physical memory into SMPpt after
+                * mptable_pass1() completes.
+                */
+               mptable_pass1(&mpt);
 
-       /* examine the MP table for needed info, uses physical addresses */
-       x = mptable_pass2();
+               if (cpu_apic_address == 0)
+                       panic("mp_enable: no local apic (mptable)!\n");
 
-       *(int *)PTD = 0;
-       cpu_invltlb();
+               /*
+                * Examine the MP table for needed info
+                */
+               x = mptable_pass2(&mpt);
+
+               mptable_unmap(&mpt);
+
+               /* 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;
 
-       /* can't process default configs till the CPU APIC is pmapped */
-       if (x)
-               default_mp_table(x);
+               madt_paddr = madt_probe();
+               if (madt_paddr == 0)
+                       panic("mp_enable: madt_probe failed\n");
 
-       /* post scan cleanup */
-       fix_mp_table();
+               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)
 
@@ -582,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);
+
+       map_size = count * sizeof(u_int32_t);
+       addr = pmap_mapdev((vm_paddr_t)target, map_size);
 
-       for (x = 0; x < count; NEXT(x))
-               if (addr[x] == MP_SIG)
+       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;
 }
 
 
@@ -682,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]
@@ -692,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;
@@ -708,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) {
@@ -725,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
@@ -734,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;
@@ -809,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
@@ -817,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;
@@ -831,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;
@@ -874,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 */
@@ -943,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 */
@@ -965,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. */
@@ -999,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
@@ -1204,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
@@ -1397,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;
@@ -1408,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;
        }
 
@@ -1862,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;
@@ -2042,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);