Annotation of sys/dev/acpi/acpiprt.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: acpiprt.c,v 1.16 2007/02/23 00:04:40 jordan 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/proc.h>
! 20: #include <sys/signalvar.h>
! 21: #include <sys/systm.h>
! 22: #include <sys/device.h>
! 23: #include <sys/malloc.h>
! 24:
! 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 <dev/pci/pcivar.h>
! 34: #include <dev/pci/ppbreg.h>
! 35:
! 36: #include <machine/i82093reg.h>
! 37: #include <machine/i82093var.h>
! 38:
! 39: #include <machine/mpbiosvar.h>
! 40:
! 41: #include "ioapic.h"
! 42:
! 43: int acpiprt_match(struct device *, void *, void *);
! 44: void acpiprt_attach(struct device *, struct device *, void *);
! 45: int acpiprt_getirq(union acpi_resource *crs, void *arg);
! 46: int acpiprt_getminbus(union acpi_resource *, void *);
! 47:
! 48:
! 49: struct acpiprt_softc {
! 50: struct device sc_dev;
! 51:
! 52: struct acpi_softc *sc_acpi;
! 53: struct aml_node *sc_devnode;
! 54:
! 55: int sc_bus;
! 56: };
! 57:
! 58: struct cfattach acpiprt_ca = {
! 59: sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach
! 60: };
! 61:
! 62: struct cfdriver acpiprt_cd = {
! 63: NULL, "acpiprt", DV_DULL
! 64: };
! 65:
! 66: void acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *);
! 67: int acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *);
! 68:
! 69: int
! 70: acpiprt_match(struct device *parent, void *match, void *aux)
! 71: {
! 72: struct acpi_attach_args *aa = aux;
! 73: struct cfdata *cf = match;
! 74:
! 75: /* sanity */
! 76: if (aa->aaa_name == NULL ||
! 77: strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
! 78: aa->aaa_table != NULL)
! 79: return (0);
! 80:
! 81: return (1);
! 82: }
! 83:
! 84: void
! 85: acpiprt_attach(struct device *parent, struct device *self, void *aux)
! 86: {
! 87: struct acpiprt_softc *sc = (struct acpiprt_softc *)self;
! 88: struct acpi_attach_args *aa = aux;
! 89: struct aml_value res;
! 90: int i;
! 91:
! 92: sc->sc_acpi = (struct acpi_softc *)parent;
! 93: sc->sc_devnode = aa->aaa_node;
! 94: sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode);
! 95:
! 96: printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name);
! 97:
! 98: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PRT", 0, NULL, &res)) {
! 99: printf(": no PCI interrupt routing table\n");
! 100: return;
! 101: }
! 102:
! 103: if (res.type != AML_OBJTYPE_PACKAGE) {
! 104: printf(": _PRT is not a package\n");
! 105: aml_freevalue(&res);
! 106: return;
! 107: }
! 108:
! 109: printf("\n");
! 110:
! 111: if (sc->sc_bus == -1)
! 112: return;
! 113:
! 114: for (i = 0; i < res.length; i++)
! 115: acpiprt_prt_add(sc, res.v_package[i]);
! 116:
! 117: aml_freevalue(&res);
! 118: }
! 119:
! 120: int
! 121: acpiprt_getirq(union acpi_resource *crs, void *arg)
! 122: {
! 123: int *irq = (int *)arg;
! 124: int typ;
! 125:
! 126: typ = AML_CRSTYPE(crs);
! 127: switch (typ) {
! 128: case SR_IRQ:
! 129: *irq = ffs(aml_letohost16(crs->sr_irq.irq_mask)) - 1;
! 130: break;
! 131: case LR_EXTIRQ:
! 132: *irq = aml_letohost32(crs->lr_extirq.irq[0]);
! 133: break;
! 134: default:
! 135: printf("Unknown interrupt : %x\n", typ);
! 136: }
! 137: return (0);
! 138: }
! 139:
! 140: void
! 141: acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v)
! 142: {
! 143: struct aml_node *node;
! 144: struct aml_value res, *pp;
! 145: u_int64_t addr;
! 146: int pin, irq, sta;
! 147: #if NIOAPIC > 0
! 148: struct mp_intr_map *map;
! 149: struct ioapic_softc *apic;
! 150: #endif
! 151: pci_chipset_tag_t pc = NULL;
! 152: pcitag_t tag;
! 153: pcireg_t reg;
! 154: int bus, dev, func, nfuncs;
! 155:
! 156: if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) {
! 157: printf("invalid mapping object\n");
! 158: return;
! 159: }
! 160:
! 161: addr = aml_val2int(v->v_package[0]);
! 162: pin = aml_val2int(v->v_package[1]);
! 163: if (pin > 3) {
! 164: return;
! 165: }
! 166:
! 167: pp = v->v_package[2];
! 168: if (pp->type == AML_OBJTYPE_NAMEREF) {
! 169: node = aml_searchname(sc->sc_devnode, pp->v_nameref);
! 170: if (node == NULL) {
! 171: printf("Invalid device!\n");
! 172: return;
! 173: }
! 174: pp = node->value;
! 175: }
! 176: if (pp->type == AML_OBJTYPE_OBJREF) {
! 177: pp = pp->v_objref.ref;
! 178: }
! 179: if (pp->type == AML_OBJTYPE_DEVICE) {
! 180: node = pp->node;
! 181: if (aml_evalname(sc->sc_acpi, node, "_STA", 0, NULL, &res))
! 182: printf("no _STA method\n");
! 183:
! 184: sta = aml_val2int(&res) & STA_ENABLED;
! 185: aml_freevalue(&res);
! 186: if (sta == 0)
! 187: return;
! 188:
! 189: if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res))
! 190: printf("no _CRS method\n");
! 191:
! 192: if (res.type != AML_OBJTYPE_BUFFER || res.length < 6) {
! 193: printf("invalid _CRS object\n");
! 194: aml_freevalue(&res);
! 195: return;
! 196: }
! 197: aml_parse_resource(res.length, res.v_buffer,
! 198: acpiprt_getirq, &irq);
! 199: aml_freevalue(&res);
! 200: } else {
! 201: irq = aml_val2int(v->v_package[3]);
! 202: }
! 203:
! 204: #ifdef ACPI_DEBUG
! 205: printf("%s: %s addr 0x%llx pin %d irq %d\n",
! 206: DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq);
! 207: #endif
! 208:
! 209: #if NIOAPIC > 0
! 210: if (nioapics > 0) {
! 211: apic = ioapic_find_bybase(irq);
! 212: if (apic == NULL) {
! 213: printf("%s: no apic found for irq %d\n", DEVNAME(sc), irq);
! 214: return;
! 215: }
! 216:
! 217: map = malloc(sizeof (struct mp_intr_map), M_DEVBUF, M_NOWAIT);
! 218: if (map == NULL)
! 219: return;
! 220:
! 221: memset(map, 0, sizeof *map);
! 222: map->ioapic = apic;
! 223: map->ioapic_pin = irq - apic->sc_apic_vecbase;
! 224: map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3);
! 225: map->redir = IOAPIC_REDLO_ACTLO | IOAPIC_REDLO_LEVEL;
! 226: map->redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
! 227:
! 228: map->ioapic_ih = APIC_INT_VIA_APIC |
! 229: ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
! 230: (map->ioapic_pin << APIC_INT_PIN_SHIFT));
! 231:
! 232: apic->sc_pins[map->ioapic_pin].ip_map = map;
! 233:
! 234: map->next = mp_busses[sc->sc_bus].mb_intrs;
! 235: mp_busses[sc->sc_bus].mb_intrs = map;
! 236:
! 237: return;
! 238: }
! 239: #endif
! 240:
! 241: bus = sc->sc_bus;
! 242: dev = ACPI_PCI_DEV(addr << 16);
! 243: tag = pci_make_tag(pc, bus, dev, 0);
! 244:
! 245: reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
! 246: if (PCI_HDRTYPE_MULTIFN(reg))
! 247: nfuncs = 8;
! 248: else
! 249: nfuncs = 1;
! 250:
! 251: for (func = 0; func < nfuncs; func++) {
! 252: tag = pci_make_tag(pc, bus, dev, func);
! 253: reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
! 254: if (PCI_INTERRUPT_PIN(reg) == pin + 1) {
! 255: reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
! 256: reg |= irq << PCI_INTERRUPT_LINE_SHIFT;
! 257: pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
! 258: }
! 259: }
! 260: }
! 261:
! 262: int
! 263: acpiprt_getminbus(union acpi_resource *crs, void *arg)
! 264: {
! 265: int *bbn = arg;
! 266: int typ = AML_CRSTYPE(crs);
! 267:
! 268: /* Check for embedded bus number */
! 269: if (typ == LR_WORD && crs->lr_word.type == 2)
! 270: *bbn = crs->lr_word._min;
! 271: return 0;
! 272: }
! 273:
! 274: int
! 275: acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node)
! 276: {
! 277: struct aml_node *parent = node->parent;
! 278: struct aml_value res;
! 279: pci_chipset_tag_t pc = NULL;
! 280: pcitag_t tag;
! 281: pcireg_t reg;
! 282: int bus, dev, func, rv;
! 283:
! 284: if (parent == NULL)
! 285: return 0;
! 286:
! 287: if (aml_evalname(sc->sc_acpi, parent, "_ADR", 0, NULL, &res) == 0) {
! 288: bus = acpiprt_getpcibus(sc, parent);
! 289: dev = ACPI_PCI_DEV(aml_val2int(&res) << 16);
! 290: func = ACPI_PCI_FN(aml_val2int(&res) << 16);
! 291: aml_freevalue(&res);
! 292:
! 293: /*
! 294: * Some systems return 255 as the device number for
! 295: * devices that are not really there.
! 296: */
! 297: if (dev >= pci_bus_maxdevs(pc, bus))
! 298: return (-1);
! 299:
! 300: tag = pci_make_tag(pc, bus, dev, func);
! 301: reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
! 302: if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
! 303: PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI) {
! 304: reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
! 305: return (PPB_BUSINFO_SECONDARY(reg));
! 306: }
! 307: }
! 308:
! 309: if (aml_evalname(sc->sc_acpi, parent, "_CRS", 0, NULL, &res) == 0) {
! 310: rv = -1;
! 311: if (res.type == AML_OBJTYPE_BUFFER)
! 312: aml_parse_resource(res.length, res.v_buffer,
! 313: acpiprt_getminbus, &rv);
! 314: aml_freevalue(&res);
! 315: if (rv != -1)
! 316: return rv;
! 317: }
! 318: if (aml_evalname(sc->sc_acpi, parent, "_BBN", 0, NULL, &res) == 0) {
! 319: rv = aml_val2int(&res);
! 320: aml_freevalue(&res);
! 321: return (rv);
! 322: }
! 323:
! 324: return (0);
! 325: }
CVSweb