123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- /* $OpenBSD: acpimadt.c,v 1.32 2015/06/26 18:12:23 guenther Exp $ */
- /*
- * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/malloc.h>
- #include <machine/apicvar.h>
- #include <machine/cpuvar.h>
- #include <machine/bus.h>
- #include <dev/acpi/acpireg.h>
- #include <dev/acpi/acpivar.h>
- #include <dev/acpi/acpidev.h>
- #include <dev/acpi/amltypes.h>
- #include <dev/acpi/dsdt.h>
- #include <machine/i8259.h>
- #include <machine/i82093reg.h>
- #include <machine/i82093var.h>
- #include <machine/i82489reg.h>
- #include <machine/i82489var.h>
- #include <machine/mpbiosvar.h>
- #include "ioapic.h"
- u_int8_t acpi_lapic_flags[LAPIC_MAP_SIZE];
- int acpimadt_match(struct device *, void *, void *);
- void acpimadt_attach(struct device *, struct device *, void *);
- struct cfattach acpimadt_ca = {
- sizeof(struct device), acpimadt_match, acpimadt_attach
- };
- struct cfdriver acpimadt_cd = {
- NULL, "acpimadt", DV_DULL
- };
- int acpimadt_validate(struct acpi_madt *);
- int acpimadt_cfg_intr(int, u_int32_t *);
- int acpimadt_print(void *, const char *);
- int
- acpimadt_match(struct device *parent, void *match, void *aux)
- {
- struct acpi_attach_args *aaa = aux;
- struct acpi_table_header *hdr;
- /*
- * If we do not have a table, it is not us
- */
- if (aaa->aaa_table == NULL)
- return (0);
- /*
- * If it is an MADT table, we can attach
- */
- hdr = (struct acpi_table_header *)aaa->aaa_table;
- if (memcmp(hdr->signature, MADT_SIG, sizeof(MADT_SIG) - 1) != 0)
- return (0);
- return (1);
- }
- int
- acpimadt_validate(struct acpi_madt *madt)
- {
- caddr_t addr = (caddr_t)(madt + 1);
- while (addr < (caddr_t)madt + madt->hdr.length) {
- union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
- u_int8_t length = entry->madt_lapic.length;
- if (length < 2)
- return (0);
- if (addr + length > (caddr_t)madt + madt->hdr.length)
- return (0);
- switch (entry->madt_lapic.apic_type) {
- case ACPI_MADT_LAPIC:
- if (length != sizeof(entry->madt_lapic))
- return (0);
- break;
- case ACPI_MADT_IOAPIC:
- if (length != sizeof(entry->madt_ioapic))
- return (0);
- break;
- case ACPI_MADT_OVERRIDE:
- if (length != sizeof(entry->madt_override))
- return (0);
- break;
- case ACPI_MADT_NMI:
- if (length != sizeof(entry->madt_nmi))
- return (0);
- break;
- case ACPI_MADT_LAPIC_NMI:
- if (length != sizeof(entry->madt_lapic_nmi))
- return (0);
- break;
- case ACPI_MADT_LAPIC_OVERRIDE:
- if (length != sizeof(entry->madt_lapic_override))
- return (0);
- break;
- case ACPI_MADT_IO_SAPIC:
- if (length != sizeof(entry->madt_io_sapic))
- return (0);
- break;
- case ACPI_MADT_LOCAL_SAPIC:
- if (length != sizeof(entry->madt_local_sapic))
- return (0);
- break;
- case ACPI_MADT_PLATFORM_INT:
- if (length != sizeof(entry->madt_platform_int))
- return (0);
- break;
- case ACPI_MADT_X2APIC:
- if (length != sizeof(entry->madt_x2apic))
- return (0);
- break;
- case ACPI_MADT_X2APIC_NMI:
- if (length != sizeof(entry->madt_x2apic_nmi))
- return (0);
- break;
- }
- addr += length;
- }
- return (1);
- }
- struct mp_bus acpimadt_busses[256];
- struct mp_bus acpimadt_isa_bus;
- int
- acpimadt_cfg_intr(int flags, u_int32_t *redir)
- {
- int mpspo = (flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
- int mpstrig = (flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
- *redir &= ~IOAPIC_REDLO_DEL_MASK;
- switch (mpspo) {
- case MPS_INTPO_DEF:
- case MPS_INTPO_ACTHI:
- *redir &= ~IOAPIC_REDLO_ACTLO;
- break;
- case MPS_INTPO_ACTLO:
- *redir |= IOAPIC_REDLO_ACTLO;
- break;
- default:
- return (0);
- }
- *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
- switch (mpstrig) {
- case MPS_INTTR_LEVEL:
- *redir |= IOAPIC_REDLO_LEVEL;
- break;
- case MPS_INTTR_DEF:
- case MPS_INTTR_EDGE:
- *redir &= ~IOAPIC_REDLO_LEVEL;
- break;
- default:
- return (0);
- }
- return (1);
- }
- static u_int8_t lapic_map[256];
- void
- acpimadt_attach(struct device *parent, struct device *self, void *aux)
- {
- struct acpi_softc *acpi_sc = (struct acpi_softc *)parent;
- struct device *mainbus = parent->dv_parent->dv_parent;
- struct acpi_attach_args *aaa = aux;
- struct acpi_madt *madt = (struct acpi_madt *)aaa->aaa_table;
- caddr_t addr = (caddr_t)(madt + 1);
- struct aml_value arg;
- struct mp_intr_map *map;
- struct ioapic_softc *apic;
- int nlapic_nmis = 0;
- int pin;
- /* Do some sanity checks before committing to run in APIC mode. */
- if (!acpimadt_validate(madt)) {
- printf(": invalid, skipping\n");
- return;
- }
- printf(" addr 0x%x", madt->local_apic_address);
- if (madt->flags & ACPI_APIC_PCAT_COMPAT)
- printf(": PC-AT compat");
- printf("\n");
- /* Tell the BIOS we will be using APIC mode. */
- memset(&arg, 0, sizeof(arg));
- arg.type = AML_OBJTYPE_INTEGER;
- arg.v_integer = 1;
- aml_evalname(acpi_sc, NULL, "\\_PIC", 1, &arg, NULL);
- mp_busses = acpimadt_busses;
- mp_nbusses = nitems(acpimadt_busses);
- mp_isa_bus = &acpimadt_isa_bus;
- lapic_boot_init(madt->local_apic_address);
- /* 1st pass, get CPUs and IOAPICs */
- while (addr < (caddr_t)madt + madt->hdr.length) {
- union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
- struct cpu_attach_args caa;
- struct apic_attach_args aaa;
- switch (entry->madt_lapic.apic_type) {
- case ACPI_MADT_LAPIC:
- dprintf("%s: LAPIC: acpi_proc_id %x, apic_id %x, flags 0x%x\n",
- self->dv_xname, entry->madt_lapic.acpi_proc_id,
- entry->madt_lapic.apic_id,
- entry->madt_lapic.flags);
- if ((entry->madt_lapic.flags & ACPI_PROC_ENABLE) == 0)
- break;
- lapic_map[entry->madt_lapic.acpi_proc_id] =
- entry->madt_lapic.apic_id;
- acpi_lapic_flags[entry->madt_lapic.acpi_proc_id] =
- entry->madt_lapic.flags;
- memset(&caa, 0, sizeof(struct cpu_attach_args));
- if (lapic_cpu_number() == entry->madt_lapic.apic_id)
- caa.cpu_role = CPU_ROLE_BP;
- else {
- caa.cpu_role = CPU_ROLE_AP;
- ncpusfound++;
- }
- caa.caa_name = "cpu";
- caa.cpu_number = entry->madt_lapic.apic_id;
- #ifdef MULTIPROCESSOR
- caa.cpu_func = &mp_cpu_funcs;
- #endif
- #ifdef __i386__
- /*
- * XXX utterly wrong. These are the
- * cpu_feature/cpu_id from the BSP cpu, now
- * being given to another cpu. This is
- * bullshit.
- */
- extern int cpu_id, cpu_feature;
- caa.cpu_signature = cpu_id;
- caa.feature_flags = cpu_feature;
- #endif
- config_found(mainbus, &caa, acpimadt_print);
- break;
- case ACPI_MADT_IOAPIC:
- dprintf("%s: IOAPIC: acpi_ioapic_id %x, address 0x%x, global_int_base 0x%x\n",
- self->dv_xname, entry->madt_ioapic.acpi_ioapic_id,
- entry->madt_ioapic.address,
- entry->madt_ioapic.global_int_base);
- memset(&aaa, 0, sizeof(struct apic_attach_args));
- aaa.aaa_name = "ioapic";
- aaa.apic_id = entry->madt_ioapic.acpi_ioapic_id;
- aaa.apic_address = entry->madt_ioapic.address;
- aaa.apic_vecbase = entry->madt_ioapic.global_int_base;
- config_found(mainbus, &aaa, acpimadt_print);
- break;
- case ACPI_MADT_LAPIC_NMI:
- nlapic_nmis++;
- break;
- }
- addr += entry->madt_lapic.length;
- }
- mp_intrs = mallocarray(nlapic_nmis, sizeof(struct mp_intr_map),
- M_DEVBUF, M_NOWAIT);
- if (mp_intrs == NULL)
- return;
- /* 2nd pass, get interrupt overrides */
- addr = (caddr_t)(madt + 1);
- while (addr < (caddr_t)madt + madt->hdr.length) {
- union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
- switch (entry->madt_lapic.apic_type) {
- case ACPI_MADT_LAPIC:
- case ACPI_MADT_IOAPIC:
- break;
- case ACPI_MADT_OVERRIDE:
- dprintf("%s: OVERRIDE: bus %x, source %x, global_int %x, flags %x\n",
- self->dv_xname, entry->madt_override.bus,
- entry->madt_override.source,
- entry->madt_override.global_int,
- entry->madt_override.flags);
- pin = entry->madt_override.global_int;
- apic = ioapic_find_bybase(pin);
- map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (map == NULL)
- return;
- map->ioapic = apic;
- map->ioapic_pin = pin - apic->sc_apic_vecbase;
- map->bus_pin = entry->madt_override.source;
- map->flags = entry->madt_override.flags;
- if (!acpimadt_cfg_intr(entry->madt_override.flags, &map->redir)) {
- printf("%s: bogus override for pin %d\n",
- self->dv_xname, pin);
- free(map, M_DEVBUF, 0);
- break;
- }
- map->ioapic_ih = APIC_INT_VIA_APIC |
- ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
- (pin << APIC_INT_PIN_SHIFT));
- apic->sc_pins[pin].ip_map = map;
- map->next = mp_isa_bus->mb_intrs;
- mp_isa_bus->mb_intrs = map;
- break;
- case ACPI_MADT_LAPIC_NMI:
- dprintf("%s: LAPIC_NMI: acpi_proc_id %x, local_apic_lint %x, flags %x\n",
- self->dv_xname, entry->madt_lapic_nmi.acpi_proc_id,
- entry->madt_lapic_nmi.local_apic_lint,
- entry->madt_lapic_nmi.flags);
- pin = entry->madt_lapic_nmi.local_apic_lint;
- map = &mp_intrs[mp_nintrs++];
- memset(map, 0, sizeof *map);
- map->cpu_id = lapic_map[entry->madt_lapic_nmi.acpi_proc_id];
- map->ioapic_pin = pin;
- map->flags = entry->madt_lapic_nmi.flags;
- if ((pin != 0 && pin != 1) ||
- !acpimadt_cfg_intr(entry->madt_lapic_nmi.flags, &map->redir)) {
- printf("%s: bogus nmi for apid %d\n",
- self->dv_xname, map->cpu_id);
- mp_nintrs--;
- break;
- }
- map->redir &= ~IOAPIC_REDLO_DEL_MASK;
- map->redir |= (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
- break;
- case ACPI_MADT_X2APIC:
- case ACPI_MADT_X2APIC_NMI:
- break;
- default:
- printf("%s: unknown apic structure type %x\n",
- self->dv_xname, entry->madt_lapic.apic_type);
- }
- addr += entry->madt_lapic.length;
- }
- /*
- * ISA interrupts are supposed to be identity mapped unless
- * there is an override, in which case we will already have a
- * mapping for the interrupt.
- */
- for (pin = 0; pin < ICU_LEN; pin++) {
- /* Skip if we already have a mapping for this interrupt. */
- for (map = mp_isa_bus->mb_intrs; map != NULL; map = map->next)
- if (map->bus_pin == pin)
- break;
- if (map != NULL)
- continue;
- apic = ioapic_find_bybase(pin);
- map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (map == NULL)
- return;
- map->ioapic = apic;
- map->ioapic_pin = pin;
- map->bus_pin = pin;
- map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
- map->ioapic_ih = APIC_INT_VIA_APIC |
- ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
- (pin << APIC_INT_PIN_SHIFT));
- apic->sc_pins[pin].ip_map = map;
- map->next = mp_isa_bus->mb_intrs;
- mp_isa_bus->mb_intrs = map;
- }
- }
- int
- acpimadt_print(void *aux, const char *pnp)
- {
- struct apic_attach_args *aaa = aux;
- if (pnp)
- printf("%s at %s:", aaa->aaa_name, pnp);
- return (UNCONF);
- }
|