root/arch/i386/i386/mpbios.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mp_print
  2. mp_match
  3. mpbios_map
  4. mpbios_unmap
  5. mpbios_probe
  6. mpbios_cksum
  7. mpbios_search
  8. mpbios_scan
  9. mpbios_invent
  10. mpbios_cpu
  11. mp_cfg_special_intr
  12. mp_cfg_pci_intr
  13. mp_cfg_eisa_intr
  14. mp_cfg_isa_intr
  15. mp_print_special_intr
  16. mp_print_pci_intr
  17. mp_print_isa_intr
  18. mp_print_eisa_intr
  19. mpbios_bus
  20. mpbios_ioapic
  21. mpbios_int

    1 /*      $OpenBSD: mpbios.c,v 1.22 2007/04/24 13:00:59 tom Exp $ */
    2 /*      $NetBSD: mpbios.c,v 1.2 2002/10/01 12:56:57 fvdl Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by RedBack Networks Inc.
   10  *
   11  * Author: Bill Sommerfeld
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. All advertising materials mentioning features or use of this software
   22  *    must display the following acknowledgement:
   23  *        This product includes software developed by the NetBSD
   24  *        Foundation, Inc. and its contributors.
   25  * 4. Neither the name of The NetBSD Foundation nor the names of its
   26  *    contributors may be used to endorse or promote products derived
   27  *    from this software without specific prior written permission.
   28  *
   29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   39  * POSSIBILITY OF SUCH DAMAGE.
   40  */
   41 
   42 /*
   43  * Copyright (c) 1999 Stefan Grefen
   44  *
   45  * Redistribution and use in source and binary forms, with or without
   46  * modification, are permitted provided that the following conditions
   47  * are met:
   48  * 1. Redistributions of source code must retain the above copyright
   49  *    notice, this list of conditions and the following disclaimer.
   50  * 2. Redistributions in binary form must reproduce the above copyright
   51  *    notice, this list of conditions and the following disclaimer in the
   52  *    documentation and/or other materials provided with the distribution.
   53  * 3. All advertising materials mentioning features or use of this software
   54  *    must display the following acknowledgement:
   55  *      This product includes software developed by the NetBSD
   56  *      Foundation, Inc. and its contributors.
   57  * 4. Neither the name of The NetBSD Foundation nor the names of its
   58  *    contributors may be used to endorse or promote products derived
   59  *    from this software without specific prior written permission.
   60  *
   61  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   62  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
   65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   71  * SUCH DAMAGE.
   72  */
   73 /*
   74  * Derived from FreeBSD's mp_machdep.c
   75  */
   76 /*
   77  * Copyright (c) 1996, by Steve Passe
   78  * All rights reserved.
   79  *
   80  * Redistribution and use in source and binary forms, with or without
   81  * modification, are permitted provided that the following conditions
   82  * are met:
   83  * 1. Redistributions of source code must retain the above copyright
   84  *    notice, this list of conditions and the following disclaimer.
   85  * 2. The name of the developer may NOT be used to endorse or promote products
   86  *    derived from this software without specific prior written permission.
   87  *
   88  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   89  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   90  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   91  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   92  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   93  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   94  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   95  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   96  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   97  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   98  * SUCH DAMAGE.
   99  */
  100 
  101 /*
  102  * The Intel MP-stuff is just one way of x86 SMP systems
  103  * so only Intel MP specific stuff is here.
  104  */
  105 
  106 #include "mpbios.h"
  107 
  108 #include <sys/param.h>
  109 #include <sys/systm.h>
  110 #include <sys/kernel.h>
  111 #include <sys/device.h>
  112 #include <sys/malloc.h>
  113 
  114 #include <uvm/uvm_extern.h>
  115 
  116 #include <machine/specialreg.h>
  117 #include <machine/cputypes.h>
  118 #include <machine/cpuvar.h>
  119 #include <machine/bus.h>
  120 #include <machine/mpbiosreg.h>
  121 #include <machine/mpbiosvar.h>
  122 
  123 #include <machine/i82093reg.h>
  124 #include <machine/i82093var.h>
  125 #include <machine/i82489reg.h>
  126 #include <machine/i82489var.h>
  127 
  128 #include <dev/isa/isareg.h>
  129 #include <dev/pci/pcivar.h>
  130 
  131 #include <dev/eisa/eisavar.h>   /* for ELCR* def'ns */
  132 
  133 #include "pci.h"
  134 
  135 
  136 static struct mpbios_ioapic default_ioapic = {
  137     2, 0, 1, IOAPICENTRY_FLAG_EN, (caddr_t)IOAPIC_BASE_DEFAULT
  138 };
  139 
  140 /* descriptions of MP basetable entries */
  141 struct mpbios_baseentry {
  142         u_int8_t        type;
  143         u_int8_t        length;
  144         u_int16_t       count;
  145         const char      *name;
  146 };
  147 
  148 static const char *loc_where[] = {
  149         "extended bios data area",
  150         "last page of base memory",
  151         "bios"
  152 };
  153 
  154 struct mp_map
  155 {
  156         vaddr_t         baseva;
  157         int             vsize;
  158         paddr_t         pa;
  159         paddr_t         pg;
  160         int             psize;
  161 };
  162 
  163 int     mp_print(void *, const char *);
  164 int     mp_match(struct device *, void *, void *);
  165 int     mpbios_cpu_start(struct cpu_info *);
  166 const void *mpbios_search(struct device *, paddr_t, int,
  167     struct mp_map *);
  168 static __inline int mpbios_cksum(const void *, int);
  169 
  170 void    mp_cfg_special_intr(const struct mpbios_int *, u_int32_t *);
  171 void    mp_cfg_pci_intr(const struct mpbios_int *, u_int32_t *);
  172 void    mp_cfg_eisa_intr(const struct mpbios_int *, u_int32_t *);
  173 void    mp_cfg_isa_intr(const struct mpbios_int *, u_int32_t *);
  174 void    mp_print_special_intr (int);
  175 void    mp_print_pci_intr (int);
  176 void    mp_print_eisa_intr (int);
  177 void    mp_print_isa_intr (int);
  178 
  179 void    mpbios_cpu(const u_int8_t *, struct device *);
  180 void    mpbios_bus(const u_int8_t *, struct device *);
  181 void    mpbios_ioapic(const u_int8_t *, struct device *);
  182 int     mpbios_int(const u_int8_t *, struct mp_intr_map *);
  183 
  184 const void *mpbios_map(paddr_t, int, struct mp_map *);
  185 static __inline void mpbios_unmap(struct mp_map *);
  186 
  187 /*
  188  * globals to help us bounce our way through parsing the config table.
  189  */
  190 
  191 static struct mp_map mp_cfg_table_map;
  192 static struct mp_map mp_fp_map;
  193 const struct mpbios_cth *mp_cth;
  194 const struct mpbios_fps *mp_fps;
  195 
  196 #ifdef MPVERBOSE
  197 int mp_verbose = 1;
  198 #else
  199 int mp_verbose = 0;
  200 #endif
  201 
  202 int
  203 mp_print(void *aux, const char *pnp)
  204 {
  205         struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
  206         if (pnp)
  207                 printf("%s at %s:", caa->caa_name, pnp);
  208         return (UNCONF);
  209 }
  210 
  211 int
  212 mp_match(struct device *parent, void *cfv, void *aux)
  213 {
  214         struct cfdata *cf = (struct cfdata *)cfv;
  215         struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
  216         if (strcmp(caa->caa_name, cf->cf_driver->cd_name))
  217                 return 0;
  218 
  219         return ((*cf->cf_attach->ca_match)(parent, cf, aux));
  220 }
  221 
  222 /*
  223  * Map a chunk of memory read-only and return an appropriately
  224  * const'ed pointer.
  225  */
  226 const void *
  227 mpbios_map(paddr_t pa, int len, struct mp_map *handle)
  228 {
  229         paddr_t pgpa = trunc_page(pa);
  230         paddr_t endpa = round_page(pa + len);
  231         vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa);
  232         vaddr_t retva = va + (pa & PGOFSET);
  233 
  234         handle->pa = pa;
  235         handle->pg = pgpa;
  236         handle->psize = len;
  237         handle->baseva = va;
  238         handle->vsize = endpa-pgpa;
  239 
  240         do {
  241 #if 1
  242                 pmap_kenter_pa(va, pgpa, VM_PROT_READ);
  243 #else
  244                 pmap_enter(pmap_kernel(), va, pgpa, VM_PROT_READ, TRUE,
  245                     VM_PROT_READ);
  246 #endif
  247                 va += NBPG;
  248                 pgpa += NBPG;
  249         } while (pgpa < endpa);
  250 
  251         return ((const void *)retva);
  252 }
  253 
  254 static __inline void
  255 mpbios_unmap(struct mp_map *handle)
  256 {
  257 #if 1
  258         pmap_kremove(handle->baseva, handle->vsize);
  259 #else
  260         pmap_extract(pmap_kernel(), handle->baseva, NULL);
  261 #endif
  262         uvm_km_free(kernel_map, handle->baseva, handle->vsize);
  263 }
  264 
  265 /*
  266  * Look for an Intel MP spec table, indicating SMP capable hardware.
  267  */
  268 int
  269 mpbios_probe(struct device *self)
  270 {
  271         paddr_t         ebda, memtop;
  272 
  273         paddr_t         cthpa;
  274         int             cthlen;
  275         const u_int8_t  *mpbios_page;
  276         int             scan_loc;
  277 
  278         struct          mp_map t;
  279 
  280         /*
  281          * Skip probe if someone else (e.g. acpi) already provided the
  282          * necessary details.
  283          */
  284         if (mp_busses)
  285                 return (0);
  286 
  287         /* see if EBDA exists */
  288 
  289         mpbios_page = mpbios_map(0, NBPG, &t);
  290 
  291         /* XXX Ugly magic constants below. */
  292         ebda = *(const u_int16_t *)(&mpbios_page[0x40e]);
  293         ebda <<= 4;
  294 
  295         memtop = *(const u_int16_t *)(&mpbios_page[0x413]);
  296         memtop <<= 10;
  297 
  298         mpbios_page = NULL;
  299         mpbios_unmap(&t);
  300 
  301         scan_loc = 0;
  302 
  303         if (ebda && ebda < IOM_BEGIN ) {
  304                 mp_fps = mpbios_search(self, ebda, 1024, &mp_fp_map);
  305                 if (mp_fps != NULL)
  306                         goto found;
  307         }
  308 
  309         scan_loc = 1;
  310 
  311         if (memtop && memtop <= IOM_BEGIN ) {
  312                 mp_fps = mpbios_search(self, memtop - 1024, 1024, &mp_fp_map);
  313                 if (mp_fps != NULL)
  314                         goto found;
  315         }
  316 
  317         scan_loc = 2;
  318 
  319         mp_fps = mpbios_search(self, BIOS_BASE, BIOS_COUNT, &mp_fp_map);
  320         if (mp_fps != NULL)
  321                 goto found;
  322 
  323         /* nothing found */
  324         return (0);
  325 
  326  found:
  327         if (mp_verbose)
  328                 printf("%s: MP floating pointer found in %s at 0x%lx\n",
  329                     self->dv_xname, loc_where[scan_loc], mp_fp_map.pa);
  330 
  331         if (mp_fps->pap == 0) {
  332                 if (mp_fps->mpfb1 == 0) {
  333                         printf("%s: MP fps invalid: "
  334                             "no default config and no configuration table\n",
  335                             self->dv_xname);
  336 
  337                         goto err;
  338                 }
  339                 printf("%s: MP default configuration %d\n",
  340                     self->dv_xname, mp_fps->mpfb1);
  341                 return (10);
  342         }
  343 
  344         cthpa = mp_fps->pap;
  345 
  346         mp_cth = mpbios_map(cthpa, sizeof (*mp_cth), &mp_cfg_table_map);
  347         cthlen = mp_cth->base_len;
  348         mpbios_unmap(&mp_cfg_table_map);
  349 
  350         mp_cth = mpbios_map(cthpa, cthlen, &mp_cfg_table_map);
  351 
  352         if (mp_verbose)
  353                 printf("%s: MP config table at 0x%lx, %d bytes long\n",
  354                     self->dv_xname, cthpa, cthlen);
  355 
  356         if (mp_cth->signature != MP_CT_SIG) {
  357                 printf("%s: MP signature mismatch (%x vs %x)\n",
  358                     self->dv_xname,
  359                     MP_CT_SIG, mp_cth->signature);
  360                 goto err;
  361         }
  362 
  363         if (mpbios_cksum(mp_cth, cthlen)) {
  364                 printf ("%s: MP Configuration Table checksum mismatch\n",
  365                     self->dv_xname);
  366                 goto err;
  367         }
  368         return (10);
  369 
  370  err:
  371         if (mp_fps) {
  372                 mp_fps = NULL;
  373                 mpbios_unmap(&mp_fp_map);
  374         }
  375         if (mp_cth) {
  376                 mp_cth = NULL;
  377                 mpbios_unmap(&mp_cfg_table_map);
  378         }
  379         return (0);
  380 }
  381 
  382 
  383 /*
  384  * Simple byte checksum used on config tables.
  385  */
  386 
  387 static __inline int
  388 mpbios_cksum(const void *start, int len)
  389 {
  390         unsigned char res=0;
  391         const char *p = start;
  392         const char *end = p + len;
  393 
  394         while (p < end)
  395                 res += *p++;
  396 
  397         return res;
  398 }
  399 
  400 
  401 /*
  402  * Look for the MP floating pointer signature in the given physical
  403  * address range.
  404  *
  405  * We map the memory, scan through it, and unmap it.
  406  * If we find it, remap the floating pointer structure and return it.
  407  */
  408 
  409 const void *
  410 mpbios_search(struct device *self, paddr_t start, int count, struct mp_map *map)
  411 {
  412         struct mp_map t;
  413 
  414         int i, len;
  415         const struct mpbios_fps *m;
  416         int end = count - sizeof(*m);
  417         const u_int8_t *base = mpbios_map(start, count, &t);
  418 
  419         if (mp_verbose)
  420                 printf("%s: scanning 0x%lx to 0x%lx for MP signature\n",
  421                     self->dv_xname, start, start + count - sizeof(*m));
  422 
  423         for (i = 0; i <= end; i += 4) {
  424                 m = (struct mpbios_fps *)&base[i];
  425 
  426                 if ((m->signature == MP_FP_SIG) &&
  427                     ((len = m->length << 4) != 0) &&
  428                     mpbios_cksum(m, (m->length << 4)) == 0) {
  429                         mpbios_unmap(&t);
  430 
  431                         return (mpbios_map(start + i, len, map));
  432                 }
  433         }
  434         mpbios_unmap(&t);
  435 
  436         return (0);
  437 }
  438 
  439 /*
  440  * MP configuration table parsing.
  441  */
  442 
  443 static struct mpbios_baseentry mp_conf[] =
  444 {
  445         {0, 20, 0, "cpu"},
  446         {1, 8, 0, "bus"},
  447         {2, 8, 0, "ioapic"},
  448         {3, 8, 0, "ioint"},
  449         {4, 8, 0, "lint"},
  450 };
  451 
  452 struct mp_bus *mp_busses;
  453 int mp_nbus;
  454 struct mp_intr_map *mp_intrs;
  455 int mp_nintrs;
  456 
  457 struct mp_bus *mp_isa_bus;
  458 struct mp_bus *mp_eisa_bus;
  459 
  460 static struct mp_bus extint_bus = {
  461         "ExtINT",
  462         -1,
  463         mp_print_special_intr,
  464         mp_cfg_special_intr,
  465         0
  466 };
  467 static struct mp_bus smi_bus = {
  468         "SMI",
  469         -1,
  470         mp_print_special_intr,
  471         mp_cfg_special_intr,
  472         0
  473 };
  474 static struct mp_bus nmi_bus = {
  475         "NMI",
  476         -1,
  477         mp_print_special_intr,
  478         mp_cfg_special_intr,
  479         0
  480 };
  481 
  482 
  483 /*
  484  * 1st pass on BIOS's Intel MP specification table.
  485  *
  486  * initializes:
  487  *      mp_ncpus = 1
  488  *
  489  * determines:
  490  *      cpu_apic_address (common to all CPUs)
  491  *      ioapic_address[N]
  492  *      mp_naps
  493  *      mp_nbusses
  494  *      mp_napics
  495  *      nintrs
  496  */
  497 void
  498 mpbios_scan(struct device *self)
  499 {
  500         const u_int8_t  *position, *end;
  501         int             count;
  502         int             type;
  503         int             intr_cnt;
  504         paddr_t         lapic_base;
  505 
  506         printf("%s: Intel MP Specification ", self->dv_xname);
  507 
  508         switch (mp_fps->spec_rev) {
  509         case 1:
  510                 printf("(Version 1.1)\n");
  511                 break;
  512         case 4:
  513                 printf("(Version 1.4)\n");
  514                 break;
  515         default:
  516                 printf("(unrecognized rev %d)\n", mp_fps->spec_rev);
  517         }
  518 
  519         /*
  520          * looks like we've got a MP system.  start setting up
  521          * infrastructure..
  522          * XXX is this the right place??
  523          */
  524 
  525         lapic_base = LAPIC_BASE;
  526         if (mp_cth != NULL)
  527                 lapic_base = (paddr_t)mp_cth->apic_address;
  528 
  529         lapic_boot_init(lapic_base);
  530 
  531         /* check for use of 'default' configuration */
  532         if (mp_fps->mpfb1 != 0) {
  533                 struct mpbios_proc pe;
  534 
  535                 printf("\n%s: MP default configuration %d\n",
  536                     self->dv_xname, mp_fps->mpfb1);
  537 
  538                 /* use default addresses */
  539                 pe.apic_id = cpu_number();
  540                 pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP;
  541                 pe.cpu_signature = cpu_info_primary.ci_signature;
  542                 pe.feature_flags = cpu_info_primary.ci_feature_flags;
  543 
  544                 mpbios_cpu((u_int8_t *)&pe, self);
  545 
  546                 pe.apic_id = 1 - cpu_number();
  547                 pe.cpu_flags = PROCENTRY_FLAG_EN;
  548 
  549                 mpbios_cpu((u_int8_t *)&pe, self);
  550 
  551                 mpbios_ioapic((u_int8_t *)&default_ioapic, self);
  552 
  553                 /* XXX */
  554                 printf("%s: WARNING: interrupts not configured\n",
  555                     self->dv_xname);
  556                 panic("lazy bum");
  557                 return;
  558         } else {
  559                 /*
  560                  * should not happen; mp_probe returns 0 in this case,
  561                  * but..
  562                  */
  563                 if (mp_cth == NULL)
  564                         panic("mpbios_scan: no config (can't happen?)");
  565 
  566                 /*
  567                  * Walk the table once, counting items
  568                  */
  569                 for (count = mp_cth->entry_count,
  570                     position = (const u_int8_t *)mp_cth + sizeof(*mp_cth),
  571                     end = position + mp_cth->base_len;
  572                     count-- && position < end;
  573                     position += mp_conf[type].length) {
  574 
  575                         type = *position;
  576                         if (type >= MPS_MCT_NTYPES) {
  577                                 printf("%s: unknown entry type %x"
  578                                     " in MP config table\n",
  579                                     self->dv_xname, type);
  580                                 end = position;
  581                                 break;
  582                         }
  583                         mp_conf[type].count++;
  584                 }
  585 
  586                 /*
  587                  * Walk the table twice, counting int and bus entries
  588                  */
  589                 for (count = mp_cth->entry_count,
  590                     intr_cnt = 15,      /* presume all isa irqs missing */
  591                     position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
  592                     count-- && position < end;
  593                     position += mp_conf[type].length) {
  594                         type = *position;
  595                         if (type == MPS_MCT_BUS) {
  596                                 const struct mpbios_bus *bp =
  597                                     (const struct mpbios_bus *)position;
  598                                 if (bp->bus_id >= mp_nbus)
  599                                         mp_nbus = bp->bus_id + 1;
  600                         }
  601 
  602                         /*
  603                          * Count actual interrupt instances.
  604                          * dst_apic_id of MPS_ALL_APICS means "wired to all
  605                          * apics of this type".
  606                          */
  607                         if ((type == MPS_MCT_IOINT) ||
  608                             (type == MPS_MCT_LINT)) {
  609                                 const struct mpbios_int *ie =
  610                                     (const struct mpbios_int *)position;
  611                                 if (ie->dst_apic_id != MPS_ALL_APICS)
  612                                         intr_cnt++;
  613                                 else if (type == MPS_MCT_IOINT)
  614                                         intr_cnt +=
  615                                             mp_conf[MPS_MCT_IOAPIC].count;
  616                                 else
  617                                         intr_cnt += mp_conf[MPS_MCT_CPU].count;
  618                         }
  619                 }
  620 
  621                 mp_busses = malloc(sizeof(struct mp_bus) * mp_nbus,
  622                     M_DEVBUF, M_NOWAIT);
  623                 memset(mp_busses, 0, sizeof(struct mp_bus) * mp_nbus);
  624                 mp_intrs = malloc(sizeof(struct mp_intr_map) * intr_cnt,
  625                     M_DEVBUF, M_NOWAIT);
  626 
  627                 /* re-walk the table, recording info of interest */
  628                 position = (const u_int8_t *)mp_cth + sizeof(*mp_cth);
  629                 count = mp_cth->entry_count;
  630                 mp_nintrs = 0;
  631 
  632                 while ((count--) && (position < end)) {
  633                         switch (type = *(u_char *)position) {
  634                         case MPS_MCT_CPU:
  635                                 mpbios_cpu(position, self);
  636                                 break;
  637                         case MPS_MCT_BUS:
  638                                 mpbios_bus(position, self);
  639                                 break;
  640                         case MPS_MCT_IOAPIC:
  641                                 mpbios_ioapic(position, self);
  642                                 break;
  643                         case MPS_MCT_IOINT:
  644                         case MPS_MCT_LINT:
  645                                 if (mpbios_int(position,
  646                                     &mp_intrs[mp_nintrs]) == 0)
  647                                         mp_nintrs++;
  648                                 break;
  649                         default:
  650                                 printf("%s: unknown entry type %x "
  651                                     "in MP config table\n",
  652                                     self->dv_xname, type);
  653                                 /* NOTREACHED */
  654                                 return;
  655                         }
  656 
  657                         (u_char*)position += mp_conf[type].length;
  658                 }
  659                 if (mp_verbose && mp_cth->ext_len)
  660                         printf("%s: MP WARNING: %d "
  661                             "bytes of extended entries not examined\n",
  662                             self->dv_xname, mp_cth->ext_len);
  663         }
  664         /* Clean up. */
  665         mp_fps = NULL;
  666         mpbios_unmap(&mp_fp_map);
  667         if (mp_cth != NULL) {
  668                 mp_cth = NULL;
  669                 mpbios_unmap(&mp_cfg_table_map);
  670         }
  671 
  672 #if NPCI > 0
  673         if (pci_mode_detect() != 0)
  674                 mpbios_intr_fixup();
  675 #endif
  676 }
  677 
  678 int
  679 mpbios_invent(int irq, int type, int bus)
  680 {
  681         struct mp_intr_map *mip;
  682         struct mpbios_int e;
  683 
  684         e.type = MPS_MCT_IOINT;
  685         e.int_type = MPS_INTTYPE_INT;
  686         switch (type) {
  687         case IST_EDGE:
  688                 e.int_flags = MPS_INT(MPS_INTPO_ACTHI, MPS_INTTR_EDGE);
  689                 break;
  690 
  691         case IST_LEVEL:
  692                 e.int_flags = MPS_INT(MPS_INTPO_ACTLO, MPS_INTTR_LEVEL);
  693                 break;
  694 
  695         case IST_NONE:
  696         case IST_PULSE:
  697                 e.int_flags = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
  698                 break;
  699         }
  700         e.src_bus_id = bus;
  701         e.src_bus_irq = irq;
  702         e.dst_apic_id = mp_busses[bus].mb_intrs->ioapic->sc_apicid;
  703         e.dst_apic_int = irq;
  704 
  705         if (mpbios_int((const u_int8_t *)&e, &mp_intrs[mp_nintrs]) == 0) {
  706                 mip = &mp_intrs[mp_nintrs++];
  707                 return (mip->ioapic_ih | irq);
  708         }
  709 
  710         return irq;
  711 }
  712 
  713 void
  714 mpbios_cpu(const u_int8_t *ent, struct device *self)
  715 {
  716         const struct mpbios_proc *entry = (const struct mpbios_proc *)ent;
  717         struct cpu_attach_args caa;
  718 
  719         /* XXX move this into the CPU attachment goo. */
  720         /* check for usability */
  721         if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
  722                 return;
  723 
  724         /* check for BSP flag */
  725         if (entry->cpu_flags & PROCENTRY_FLAG_BP)
  726                 caa.cpu_role = CPU_ROLE_BP;
  727         else
  728                 caa.cpu_role = CPU_ROLE_AP;
  729 
  730         caa.caa_name = "cpu";
  731         caa.cpu_number = entry->apic_id;
  732         caa.cpu_func = &mp_cpu_funcs;
  733 #if 1 /* XXX Will be removed when the real stuff is probed */
  734         caa.cpu_signature = entry->cpu_signature;
  735 
  736         /*
  737          * XXX this is truncated to just contain the low-order 16 bits
  738          * of the flags on at least some MP bioses
  739          */
  740         caa.feature_flags = entry->feature_flags;
  741 
  742         /*
  743          * XXX some MP bioses don't specify a valid CPU signature; use
  744          * the result of the 'cpuid' instruction for the processor
  745          * we're running on
  746          */
  747         if ((caa.cpu_signature & 0x00000fff) == 0) {
  748                 caa.cpu_signature = cpu_id;
  749                 caa.feature_flags = cpu_feature;
  750         }
  751 #endif
  752 
  753         config_found_sm(self, &caa, mp_print, mp_match);
  754 }
  755 
  756 /*
  757  * The following functions conspire to compute base ioapic redirection
  758  * table entry for a given interrupt line.
  759  *
  760  * Fill in: trigger mode, polarity, and possibly delivery mode.
  761  */
  762 void
  763 mp_cfg_special_intr(const struct mpbios_int *entry, u_int32_t *redir)
  764 {
  765 
  766         /*
  767          * All of these require edge triggered, zero vector,
  768          * appropriate delivery mode.
  769          * see page 13 of the 82093AA datasheet.
  770          */
  771         *redir &= ~IOAPIC_REDLO_DEL_MASK;
  772         *redir &= ~IOAPIC_REDLO_VECTOR_MASK;
  773         *redir &= ~IOAPIC_REDLO_LEVEL;
  774 
  775         switch (entry->int_type) {
  776         case MPS_INTTYPE_NMI:
  777                 *redir |= (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
  778                 break;
  779 
  780         case MPS_INTTYPE_SMI:
  781                 *redir |= (IOAPIC_REDLO_DEL_SMI<<IOAPIC_REDLO_DEL_SHIFT);
  782                 break;
  783         case MPS_INTTYPE_ExtINT:
  784                 /*
  785                  * We are using the ioapic in "native" mode.
  786                  * This indicates where the 8259 is wired to the ioapic
  787                  * and/or local apic..
  788                  */
  789                 *redir |= (IOAPIC_REDLO_DEL_EXTINT<<IOAPIC_REDLO_DEL_SHIFT);
  790                 *redir |= (IOAPIC_REDLO_MASK);
  791                 break;
  792         default:
  793                 panic("unknown MPS interrupt type %d", entry->int_type);
  794         }
  795 }
  796 
  797 /* XXX too much duplicated code here. */
  798 
  799 void
  800 mp_cfg_pci_intr(const struct mpbios_int *entry, u_int32_t *redir)
  801 {
  802         int mpspo = entry->int_flags & 0x03; /* XXX magic */
  803         int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
  804 
  805         *redir &= ~IOAPIC_REDLO_DEL_MASK;
  806         switch (mpspo) {
  807         case MPS_INTPO_ACTHI:
  808                 *redir &= ~IOAPIC_REDLO_ACTLO;
  809                 break;
  810         case MPS_INTPO_DEF:
  811         case MPS_INTPO_ACTLO:
  812                 *redir |= IOAPIC_REDLO_ACTLO;
  813                 break;
  814         default:
  815                 panic("unknown MPS interrupt polarity %d", mpspo);
  816         }
  817 
  818         if (entry->int_type != MPS_INTTYPE_INT) {
  819                 mp_cfg_special_intr(entry, redir);
  820                 return;
  821         }
  822         *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
  823 
  824         switch (mpstrig) {
  825         case MPS_INTTR_DEF:
  826         case MPS_INTTR_LEVEL:
  827                 *redir |= IOAPIC_REDLO_LEVEL;
  828                 break;
  829         case MPS_INTTR_EDGE:
  830                 *redir &= ~IOAPIC_REDLO_LEVEL;
  831                 break;
  832         default:
  833                 panic("unknown MPS interrupt trigger %d", mpstrig);
  834         }
  835 }
  836 
  837 void
  838 mp_cfg_eisa_intr (const struct mpbios_int *entry, u_int32_t *redir)
  839 {
  840         int mpspo = entry->int_flags & 0x03; /* XXX magic */
  841         int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
  842 
  843         *redir &= ~IOAPIC_REDLO_DEL_MASK;
  844         switch (mpspo) {
  845         case MPS_INTPO_DEF:
  846         case MPS_INTPO_ACTHI:
  847                 *redir &= ~IOAPIC_REDLO_ACTLO;
  848                 break;
  849         case MPS_INTPO_ACTLO:
  850                 *redir |= IOAPIC_REDLO_ACTLO;
  851                 break;
  852         default:
  853                 panic("unknown MPS interrupt polarity %d", mpspo);
  854         }
  855 
  856         if (entry->int_type != MPS_INTTYPE_INT) {
  857                 mp_cfg_special_intr(entry, redir);
  858                 return;
  859         }
  860         *redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
  861 
  862         switch (mpstrig) {
  863         case MPS_INTTR_LEVEL:
  864                 *redir |= IOAPIC_REDLO_LEVEL;
  865                 break;
  866         case MPS_INTTR_EDGE:
  867                 *redir &= ~IOAPIC_REDLO_LEVEL;
  868                 break;
  869         case MPS_INTTR_DEF:
  870                 /*
  871                  * Set "default" setting based on ELCR value snagged
  872                  * earlier.
  873                  */
  874                 if (mp_busses[entry->src_bus_id].mb_data &
  875                     (1<<entry->src_bus_irq)) {
  876                         *redir |= IOAPIC_REDLO_LEVEL;
  877                 } else {
  878                         *redir &= ~IOAPIC_REDLO_LEVEL;
  879                 }
  880                 break;
  881         default:
  882                 panic("unknown MPS interrupt trigger %d", mpstrig);
  883         }
  884 }
  885 
  886 
  887 void
  888 mp_cfg_isa_intr(const struct mpbios_int *entry, u_int32_t *redir)
  889 {
  890         int mpspo = entry->int_flags & 0x03; /* XXX magic */
  891         int mpstrig = (entry->int_flags >> 2) & 0x03; /* XXX magic */
  892 
  893         *redir &= ~IOAPIC_REDLO_DEL_MASK;
  894         switch (mpspo) {
  895         case MPS_INTPO_DEF:
  896         case MPS_INTPO_ACTHI:
  897                 *redir &= ~IOAPIC_REDLO_ACTLO;
  898                 break;
  899         case MPS_INTPO_ACTLO:
  900                 *redir |= IOAPIC_REDLO_ACTLO;
  901                 break;
  902         default:
  903                 panic("unknown MPS interrupt polarity %d", mpspo);
  904         }
  905 
  906         if (entry->int_type != MPS_INTTYPE_INT) {
  907                 mp_cfg_special_intr(entry, redir);
  908                 return;
  909         }
  910         *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
  911 
  912         switch (mpstrig) {
  913         case MPS_INTTR_LEVEL:
  914                 *redir |= IOAPIC_REDLO_LEVEL;
  915                 break;
  916         case MPS_INTTR_DEF:
  917         case MPS_INTTR_EDGE:
  918                 *redir &= ~IOAPIC_REDLO_LEVEL;
  919                 break;
  920         default:
  921                 panic("unknown MPS interrupt trigger %d", mpstrig);
  922         }
  923 }
  924 
  925 
  926 void
  927 mp_print_special_intr(int intr)
  928 {
  929 }
  930 
  931 void
  932 mp_print_pci_intr(int intr)
  933 {
  934         printf(" device %d INT_%c", (intr >> 2) & 0x1f, 'A' + (intr & 0x3));
  935 }
  936 
  937 void
  938 mp_print_isa_intr(int intr)
  939 {
  940         printf(" irq %d", intr);
  941 }
  942 
  943 void
  944 mp_print_eisa_intr(int intr)
  945 {
  946         printf(" EISA irq %d", intr);
  947 }
  948 
  949 
  950 
  951 #define TAB_UNIT        4
  952 #define TAB_ROUND(a)    _TAB_ROUND(a, TAB_UNIT)
  953 
  954 #define _TAB_ROUND(a,u) (((a) + (u - 1)) & ~(u - 1))
  955 #define EXTEND_TAB(a,u) (!(_TAB_ROUND(a, u) == _TAB_ROUND((a + 1), u)))
  956 
  957 void
  958 mpbios_bus(const u_int8_t *ent, struct device *self)
  959 {
  960         const struct mpbios_bus *entry = (const struct mpbios_bus *)ent;
  961         int bus_id = entry->bus_id;
  962 
  963         printf("%s: bus %d is type %6.6s\n", self->dv_xname,
  964             bus_id, entry->bus_type);
  965 
  966 #ifdef DIAGNOSTIC
  967         /*
  968          * This "should not happen" unless the table changes out
  969          * from underneath us
  970          */
  971         if (bus_id >= mp_nbus) {
  972                 panic("%s: bus number %d out of range?? (type %6.6s)",
  973                     self->dv_xname, bus_id, entry->bus_type);
  974         }
  975 #endif
  976 
  977         mp_busses[bus_id].mb_intrs = NULL;
  978 
  979         if (memcmp(entry->bus_type, "PCI   ", 6) == 0) {
  980                 mp_busses[bus_id].mb_name = "pci";
  981                 mp_busses[bus_id].mb_idx = bus_id;
  982                 mp_busses[bus_id].mb_intr_print = mp_print_pci_intr;
  983                 mp_busses[bus_id].mb_intr_cfg = mp_cfg_pci_intr;
  984         } else if (memcmp(entry->bus_type, "EISA  ", 6) == 0) {
  985                 mp_busses[bus_id].mb_name = "eisa";
  986                 mp_busses[bus_id].mb_idx = bus_id;
  987                 mp_busses[bus_id].mb_intr_print = mp_print_eisa_intr;
  988                 mp_busses[bus_id].mb_intr_cfg = mp_cfg_eisa_intr;
  989 
  990                 mp_busses[bus_id].mb_data = inb(ELCR0) | (inb(ELCR1) << 8);
  991 
  992                 if (mp_eisa_bus)
  993                         printf("%s: multiple eisa busses?\n",
  994                             self->dv_xname);
  995                 else
  996                         mp_eisa_bus = &mp_busses[bus_id];
  997         } else if (memcmp(entry->bus_type, "ISA   ", 6) == 0) {
  998                 mp_busses[bus_id].mb_name = "isa";
  999                 mp_busses[bus_id].mb_idx = bus_id;
 1000                 mp_busses[bus_id].mb_intr_print = mp_print_isa_intr;
 1001                 mp_busses[bus_id].mb_intr_cfg = mp_cfg_isa_intr;
 1002                 if (mp_isa_bus)
 1003                         printf("%s: multiple isa busses?\n",
 1004                             self->dv_xname);
 1005                 else
 1006                         mp_isa_bus = &mp_busses[bus_id];
 1007         } else {
 1008                 printf("%s: unsupported bus type %6.6s\n", self->dv_xname,
 1009                     entry->bus_type);
 1010         }
 1011 }
 1012 
 1013 
 1014 void
 1015 mpbios_ioapic(const u_int8_t *ent, struct device *self)
 1016 {
 1017         const struct mpbios_ioapic *entry = (const struct mpbios_ioapic *)ent;
 1018         struct apic_attach_args aaa;
 1019 
 1020         /* XXX let flags checking happen in ioapic driver.. */
 1021         if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN))
 1022                 return;
 1023 
 1024         aaa.aaa_name = "ioapic";
 1025         aaa.apic_id = entry->apic_id;
 1026         aaa.apic_version = entry->apic_version;
 1027         aaa.apic_address = (u_int32_t)entry->apic_address;
 1028         aaa.apic_vecbase = -1;
 1029         aaa.flags = (mp_fps->mpfb2 & 0x80) ? IOAPIC_PICMODE : IOAPIC_VWIRE;
 1030 
 1031         config_found_sm(self, &aaa, mp_print, mp_match);
 1032 }
 1033 
 1034 int
 1035 mpbios_int(const u_int8_t *ent, struct mp_intr_map *mpi)
 1036 {
 1037         const struct mpbios_int *entry = (const struct mpbios_int *)ent;
 1038         struct mpbios_int rw_entry = *entry;
 1039         struct ioapic_softc *sc = NULL, *sc2;
 1040 
 1041         struct mp_intr_map *altmpi;
 1042         struct mp_bus *mpb;
 1043 
 1044         u_int32_t id = IOAPIC_REMAPPED_ID(entry->dst_apic_id);
 1045         u_int32_t pin = entry->dst_apic_int;
 1046         u_int32_t bus = entry->src_bus_id;
 1047         u_int32_t dev = entry->src_bus_irq;
 1048         u_int32_t type = entry->int_type;
 1049         u_int32_t flags = entry->int_flags;
 1050 
 1051         rw_entry.dst_apic_id = id;
 1052 
 1053         switch (type) {
 1054         case MPS_INTTYPE_INT:
 1055                 mpb = &(mp_busses[bus]);
 1056                 break;
 1057         case MPS_INTTYPE_ExtINT:
 1058                 mpb = &extint_bus;
 1059                 break;
 1060         case MPS_INTTYPE_SMI:
 1061                 mpb = &smi_bus;
 1062                 break;
 1063         case MPS_INTTYPE_NMI:
 1064                 mpb = &nmi_bus;
 1065                 break;
 1066         }
 1067         mpi->bus = mpb;
 1068         mpi->bus_pin = dev;
 1069 
 1070         mpi->ioapic_ih = APIC_INT_VIA_APIC |
 1071             ((id << APIC_INT_APIC_SHIFT) | ((pin << APIC_INT_PIN_SHIFT)));
 1072 
 1073         mpi->type = type;
 1074         mpi->flags = flags;
 1075         mpi->redir = 0;
 1076         if (mpb->mb_intr_cfg == NULL) {
 1077                 printf("mpbios: can't find bus %d for apic %d pin %d\n",
 1078                     bus, id, pin);
 1079                 return (1);
 1080         }
 1081 
 1082         (*mpb->mb_intr_cfg)(&rw_entry, &mpi->redir);
 1083 
 1084         if (entry->type == MPS_MCT_IOINT) {
 1085                 sc = ioapic_find(id);
 1086                 if (sc == NULL) {
 1087                         printf("mpbios: can't find ioapic %d\n", id);
 1088                         return (1);
 1089                 }
 1090 
 1091                 /*
 1092                  * XXX workaround for broken BIOSs that put the ACPI
 1093                  * global interrupt number in the entry, not the pin
 1094                  * number.
 1095                  */
 1096                 if (pin >= sc->sc_apic_sz) {
 1097                         sc2 = ioapic_find_bybase(pin);
 1098                         if (sc2 != sc) {
 1099                                 printf("mpbios: bad pin %d for apic %d\n",
 1100                                     pin, id);
 1101                                 return (1);
 1102                         }
 1103                         printf("mpbios: WARNING: pin %d for apic %d too high; "
 1104                                "assuming ACPI global int value\n", pin, id);
 1105                         pin -= sc->sc_apic_vecbase;
 1106                 }
 1107 
 1108                 mpi->ioapic = sc;
 1109                 mpi->ioapic_pin = pin;
 1110 
 1111                 altmpi = sc->sc_pins[pin].ip_map;
 1112 
 1113                 if (altmpi != NULL) {
 1114                         if ((altmpi->type != type) ||
 1115                             (altmpi->flags != flags)) {
 1116                                 printf(
 1117                                     "%s: conflicting map entries for pin %d\n",
 1118                                     sc->sc_dev.dv_xname, pin);
 1119                         }
 1120                 } else {
 1121                         sc->sc_pins[pin].ip_map = mpi;
 1122                 }
 1123         } else {
 1124                 if (pin >= 2)
 1125                         printf("pin %d of local apic doesn't exist!\n", pin);
 1126                 else {
 1127                         mpi->ioapic = NULL;
 1128                         mpi->ioapic_pin = pin;
 1129                         mpi->cpu_id = id;
 1130                 }
 1131         }
 1132 
 1133         if (mp_verbose) {
 1134                 printf("%s: int%d attached to %s",
 1135                     sc ? sc->sc_dev.dv_xname : "local apic", pin,
 1136                     mpb->mb_name);
 1137                 if (mpb->mb_idx != -1)
 1138                         printf("%d", mpb->mb_idx);
 1139 
 1140                 (*(mpb->mb_intr_print))(dev);
 1141 
 1142                 printf(" (type 0x%x flags 0x%x)\n", type, flags);
 1143         }
 1144 
 1145         mpi->next = mpb->mb_intrs;
 1146         mpb->mb_intrs = mpi;
 1147 
 1148         return (0);
 1149 }

/* [<][>][^][v][top][bottom][index][help] */