root/dev/acpi/acpiprt.c

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

DEFINITIONS

This source file includes following definitions.
  1. acpiprt_match
  2. acpiprt_attach
  3. acpiprt_getirq
  4. acpiprt_prt_add
  5. acpiprt_getminbus
  6. acpiprt_getpcibus

    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 }

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