root/dev/acpi/acpimadt.c

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

DEFINITIONS

This source file includes following definitions.
  1. acpimadt_match
  2. acpimadt_cfg_intr
  3. acpimadt_attach
  4. acpimadt_print

    1 /*      $OpenBSD: acpimadt.c,v 1.10 2007/02/21 19:17:23 kettenis Exp $  */
    2 /*
    3  * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org>
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 #include <sys/param.h>
   19 #include <sys/systm.h>
   20 #include <sys/device.h>
   21 #include <sys/malloc.h>
   22 
   23 #include <machine/apicvar.h>
   24 #include <machine/cpuvar.h>
   25 #include <machine/bus.h>
   26 
   27 #include <dev/acpi/acpireg.h>
   28 #include <dev/acpi/acpivar.h>
   29 #include <dev/acpi/acpidev.h>
   30 #include <dev/acpi/amltypes.h>
   31 #include <dev/acpi/dsdt.h>
   32 
   33 #include <machine/i8259.h>
   34 #include <machine/i82093reg.h>
   35 #include <machine/i82093var.h>
   36 
   37 #include <machine/mpbiosvar.h>
   38 
   39 #include "ioapic.h"
   40 
   41 #ifdef __amd64__ /* XXX */
   42 #define mp_nintrs mp_nintr
   43 #endif
   44 
   45 int acpimadt_match(struct device *, void *, void *);
   46 void acpimadt_attach(struct device *, struct device *, void *);
   47 
   48 struct cfattach acpimadt_ca = {
   49         sizeof(struct device), acpimadt_match, acpimadt_attach
   50 };
   51 
   52 struct cfdriver acpimadt_cd = {
   53         NULL, "acpimadt", DV_DULL
   54 };
   55 
   56 void acpimadt_cfg_intr(int, u_int32_t *);
   57 int acpimadt_print(void *, const char *);
   58 
   59 int
   60 acpimadt_match(struct device *parent, void *match, void *aux)
   61 {
   62         struct acpi_attach_args *aaa = aux;
   63         struct acpi_table_header *hdr;
   64 
   65         /*
   66          * If we do not have a table, it is not us
   67          */
   68         if (aaa->aaa_table == NULL)
   69                 return (0);
   70 
   71         /*
   72          * If it is an MADT table, we can attach
   73          */
   74         hdr = (struct acpi_table_header *)aaa->aaa_table;
   75         if (memcmp(hdr->signature, MADT_SIG, sizeof(MADT_SIG) - 1) != 0)
   76                 return (0);
   77 
   78         return (1);
   79 }
   80 
   81 struct mp_bus acpimadt_busses[256];
   82 struct mp_bus acpimadt_isa_bus;
   83 
   84 void
   85 acpimadt_cfg_intr(int flags, u_int32_t *redir)
   86 {
   87         int mpspo = flags & 0x03; /* XXX magic */
   88         int mpstrig = (flags >> 2) & 0x03; /* XXX magic */
   89 
   90         *redir &= ~IOAPIC_REDLO_DEL_MASK;
   91         switch (mpspo) {
   92         case MPS_INTPO_DEF:
   93         case MPS_INTPO_ACTHI:
   94                 *redir &= ~IOAPIC_REDLO_ACTLO;
   95                 break;
   96         case MPS_INTPO_ACTLO:
   97                 *redir |= IOAPIC_REDLO_ACTLO;
   98                 break;
   99         default:
  100                 panic("unknown MPS interrupt polarity %d", mpspo);
  101         }
  102 
  103         *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
  104 
  105         switch (mpstrig) {
  106         case MPS_INTTR_LEVEL:
  107                 *redir |= IOAPIC_REDLO_LEVEL;
  108                 break;
  109         case MPS_INTTR_DEF:
  110         case MPS_INTTR_EDGE:
  111                 *redir &= ~IOAPIC_REDLO_LEVEL;
  112                 break;
  113         default:
  114                 panic("unknown MPS interrupt trigger %d", mpstrig);
  115         }
  116 }
  117 
  118 static u_int8_t lapic_map[256];
  119 
  120 void
  121 acpimadt_attach(struct device *parent, struct device *self, void *aux)
  122 {
  123         struct acpi_softc *acpi_sc = (struct acpi_softc *)parent;
  124         struct device *mainbus = parent->dv_parent;
  125         struct acpi_attach_args *aaa = aux;
  126         struct acpi_madt *madt = (struct acpi_madt *)aaa->aaa_table;
  127         caddr_t addr = (caddr_t)(madt + 1);
  128         struct aml_node *node;
  129         struct aml_value arg;
  130         struct mp_intr_map *map;
  131         struct ioapic_softc *apic;
  132         int cpu_role = CPU_ROLE_BP;
  133         int nlapic_nmis = 0;
  134         int pin;
  135 
  136         printf(" addr 0x%x", madt->local_apic_address);
  137         if (madt->flags & ACPI_APIC_PCAT_COMPAT)
  138                 printf(": PC-AT compat");
  139         printf("\n");
  140 
  141         /* Tell the BIOS we will be using APIC mode. */
  142         node = aml_searchname(NULL, "\\_PIC");
  143         if (node == 0)
  144                 return;
  145         memset(&arg, 0, sizeof(arg));
  146         arg.type = AML_OBJTYPE_INTEGER;
  147         arg.v_integer = 1;
  148         aml_evalnode(acpi_sc, node, 1, &arg, NULL);
  149 
  150         mp_busses = acpimadt_busses;
  151         mp_isa_bus = &acpimadt_isa_bus;
  152 
  153         lapic_boot_init(madt->local_apic_address);
  154 
  155         /* 1st pass, get CPUs and IOAPICs */
  156         while (addr < (caddr_t)madt + madt->hdr.length) {
  157                 union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
  158 
  159                 switch (entry->madt_lapic.apic_type) {
  160                 case ACPI_MADT_LAPIC:
  161                         dprintf("%s: LAPIC: acpi_proc_id %x, apic_id %x, flags 0x%x\n",
  162                             self->dv_xname, entry->madt_lapic.acpi_proc_id,
  163                             entry->madt_lapic.apic_id,
  164                             entry->madt_lapic.flags);
  165 
  166                         lapic_map[entry->madt_lapic.acpi_proc_id] =
  167                             entry->madt_lapic.apic_id;
  168 
  169                         {
  170                                 struct cpu_attach_args caa;
  171 
  172                                 if ((entry->madt_lapic.flags & ACPI_PROC_ENABLE) == 0)
  173                                         break;
  174 
  175                                 memset(&caa, 0, sizeof(struct cpu_attach_args));
  176                                 caa.cpu_role = cpu_role;
  177                                 caa.caa_name = "cpu";
  178                                 caa.cpu_number = entry->madt_lapic.apic_id;
  179                                 caa.cpu_func = &mp_cpu_funcs;
  180 #ifdef __i386__
  181                                 extern int cpu_id, cpu_feature;
  182                                 caa.cpu_signature = cpu_id;
  183                                 caa.feature_flags = cpu_feature;
  184 #endif
  185 
  186                                 config_found(mainbus, &caa, acpimadt_print);
  187 
  188                                 cpu_role = CPU_ROLE_AP;
  189                         }
  190                         break;
  191                 case ACPI_MADT_IOAPIC:
  192                         dprintf("%s: IOAPIC: acpi_ioapic_id %x, address 0x%x, global_int_base 0x%x\n",
  193                             self->dv_xname, entry->madt_ioapic.acpi_ioapic_id,
  194                             entry->madt_ioapic.address,
  195                             entry->madt_ioapic.global_int_base);
  196 
  197                         {
  198                                 struct apic_attach_args aaa;
  199 
  200                                 memset(&aaa, 0, sizeof(struct apic_attach_args));
  201                                 aaa.aaa_name = "ioapic";
  202                                 aaa.apic_id = entry->madt_ioapic.acpi_ioapic_id;
  203                                 aaa.apic_address = entry->madt_ioapic.address;
  204                                 aaa.apic_vecbase = entry->madt_ioapic.global_int_base;
  205 
  206                                 config_found(mainbus, &aaa, acpimadt_print);
  207                         }
  208                         break;
  209                 case ACPI_MADT_LAPIC_NMI:
  210                         nlapic_nmis++;
  211                         break;
  212                 }
  213                 addr += entry->madt_lapic.length;
  214         }
  215 
  216         mp_intrs = malloc(nlapic_nmis * sizeof (struct mp_intr_map), M_DEVBUF, M_NOWAIT);
  217         if (mp_intrs == NULL)
  218                 return;
  219 
  220         /* 2nd pass, get interrupt overrides */
  221         addr = (caddr_t)(madt + 1);
  222         while (addr < (caddr_t)madt + madt->hdr.length) {
  223                 union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
  224 
  225                 switch (entry->madt_lapic.apic_type) {
  226                 case ACPI_MADT_LAPIC:
  227                 case ACPI_MADT_IOAPIC:
  228                         break;
  229 
  230                 case ACPI_MADT_OVERRIDE:
  231                         dprintf("%s: OVERRIDE: bus %x, source %x, global_int %x, flags %x\n",
  232                             self->dv_xname, entry->madt_override.bus,
  233                             entry->madt_override.source,
  234                             entry->madt_override.global_int,
  235                             entry->madt_override.flags);
  236 
  237                         pin = entry->madt_override.global_int;
  238                         apic = ioapic_find_bybase(pin);
  239 
  240                         map = malloc(sizeof (struct mp_intr_map), M_DEVBUF, M_NOWAIT);
  241                         if (map == NULL)
  242                                 return;
  243 
  244                         memset(map, 0, sizeof *map);
  245                         map->ioapic = apic;
  246                         map->ioapic_pin = pin - apic->sc_apic_vecbase;
  247                         map->bus_pin = entry->madt_override.source;
  248                         map->flags = entry->madt_override.flags;
  249 #ifdef __amd64__ /* XXX */
  250                         map->global_int = entry->madt_override.global_int;
  251 #endif
  252                         acpimadt_cfg_intr(entry->madt_override.flags, &map->redir);
  253 
  254                         map->ioapic_ih = APIC_INT_VIA_APIC |
  255                             ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
  256                             (pin << APIC_INT_PIN_SHIFT));
  257 
  258                         apic->sc_pins[pin].ip_map = map;
  259 
  260                         map->next = mp_isa_bus->mb_intrs;
  261                         mp_isa_bus->mb_intrs = map;
  262                         break;
  263 
  264                 case ACPI_MADT_LAPIC_NMI:
  265                         dprintf("%s: LAPIC_NMI: acpi_proc_id %x, local_apic_lint %x, flags %x\n",
  266                             self->dv_xname, entry->madt_lapic_nmi.acpi_proc_id,
  267                             entry->madt_lapic_nmi.local_apic_lint,
  268                             entry->madt_lapic_nmi.flags);
  269 
  270                         pin = entry->madt_lapic_nmi.local_apic_lint;
  271 
  272                         map = &mp_intrs[mp_nintrs++];
  273                         memset(map, 0, sizeof *map);
  274                         map->cpu_id = lapic_map[entry->madt_lapic_nmi.acpi_proc_id];
  275                         map->ioapic_pin = pin;
  276                         map->flags = entry->madt_lapic_nmi.flags;
  277 
  278                         acpimadt_cfg_intr(entry->madt_lapic_nmi.flags, &map->redir);
  279                         map->redir &= ~IOAPIC_REDLO_DEL_MASK;
  280                         map->redir |= (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
  281                         break;
  282 
  283                 default:
  284                         printf("%s: unknown apic structure type %x\n",
  285                             self->dv_xname, entry->madt_lapic.apic_type);
  286                 }
  287 
  288                 addr += entry->madt_lapic.length;
  289         }
  290 
  291         for (pin = 0; pin < ICU_LEN; pin++) {
  292                 apic = ioapic_find_bybase(pin);
  293                 if (apic->sc_pins[pin].ip_map != NULL)
  294                         continue;
  295 
  296                 map = malloc(sizeof (struct mp_intr_map), M_DEVBUF, M_NOWAIT);
  297                 if (map == NULL)
  298                         return;
  299 
  300                 memset(map, 0, sizeof *map);
  301                 map->ioapic = apic;
  302                 map->ioapic_pin = pin;
  303                 map->bus_pin = pin;
  304 #ifdef __amd64__ /* XXX */
  305                 map->global_int = -1;
  306 #endif
  307                 map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
  308 
  309                 map->ioapic_ih = APIC_INT_VIA_APIC |
  310                     ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
  311                     (pin << APIC_INT_PIN_SHIFT));
  312 
  313                 apic->sc_pins[pin].ip_map = map;
  314 
  315                 map->next = mp_isa_bus->mb_intrs;
  316                 mp_isa_bus->mb_intrs = map;
  317         }
  318 }
  319 
  320 int
  321 acpimadt_print(void *aux, const char *pnp)
  322 {
  323         struct apic_attach_args *aaa = aux;
  324 
  325         if (pnp)
  326                 printf("%s at %s:", aaa->aaa_name, pnp);
  327 
  328         return (UNCONF);
  329 }

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