LCOV - code coverage report
Current view: top level - dev/acpi - acpiprt.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 244 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: acpiprt.c,v 1.48 2016/10/25 06:48:58 pirofti 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/signalvar.h>
      20             : #include <sys/systm.h>
      21             : #include <sys/device.h>
      22             : #include <sys/malloc.h>
      23             : 
      24             : #include <machine/bus.h>
      25             : 
      26             : #include <dev/acpi/acpireg.h>
      27             : #include <dev/acpi/acpivar.h>
      28             : #include <dev/acpi/acpidev.h>
      29             : #include <dev/acpi/amltypes.h>
      30             : #include <dev/acpi/dsdt.h>
      31             : 
      32             : #include <dev/pci/pcivar.h>
      33             : #include <dev/pci/ppbreg.h>
      34             : 
      35             : #include <machine/i82093reg.h>
      36             : #include <machine/i82093var.h>
      37             : 
      38             : #include <machine/mpbiosvar.h>
      39             : 
      40             : #include "ioapic.h"
      41             : 
      42             : struct acpiprt_irq {
      43             :         int _int;
      44             :         int _shr;
      45             :         int _ll;
      46             :         int _he;
      47             : };
      48             : 
      49             : struct acpiprt_map {
      50             :         int bus, dev;
      51             :         int pin;
      52             :         int irq;
      53             :         struct acpiprt_softc *sc;
      54             :         struct aml_node *node;
      55             :         SIMPLEQ_ENTRY(acpiprt_map) list;
      56             : };
      57             : 
      58             : SIMPLEQ_HEAD(, acpiprt_map) acpiprt_map_list =
      59             :     SIMPLEQ_HEAD_INITIALIZER(acpiprt_map_list);
      60             : 
      61             : int     acpiprt_match(struct device *, void *, void *);
      62             : void    acpiprt_attach(struct device *, struct device *, void *);
      63             : int     acpiprt_getirq(int, union acpi_resource *, void *);
      64             : int     acpiprt_chooseirq(int, union acpi_resource *, void *);
      65             : 
      66             : struct acpiprt_softc {
      67             :         struct device           sc_dev;
      68             : 
      69             :         struct acpi_softc       *sc_acpi;
      70             :         struct aml_node         *sc_devnode;
      71             : 
      72             :         int                     sc_bus;
      73             : };
      74             : 
      75             : struct cfattach acpiprt_ca = {
      76             :         sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach
      77             : };
      78             : 
      79             : struct cfdriver acpiprt_cd = {
      80             :         NULL, "acpiprt", DV_DULL
      81             : };
      82             : 
      83             : void    acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *);
      84             : int     acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *);
      85             : void    acpiprt_route_interrupt(int bus, int dev, int pin);
      86             : 
      87             : int
      88           0 : acpiprt_match(struct device *parent, void *match, void *aux)
      89             : {
      90           0 :         struct acpi_attach_args *aa = aux;
      91           0 :         struct cfdata  *cf = match;
      92             : 
      93             :         /* sanity */
      94           0 :         if (aa->aaa_name == NULL ||
      95           0 :             strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
      96           0 :             aa->aaa_table != NULL)
      97           0 :                 return (0);
      98             : 
      99           0 :         return (1);
     100           0 : }
     101             : 
     102             : void
     103           0 : acpiprt_attach(struct device *parent, struct device *self, void *aux)
     104             : {
     105           0 :         struct acpiprt_softc *sc = (struct acpiprt_softc *)self;
     106           0 :         struct acpi_attach_args *aa = aux;
     107           0 :         struct aml_value res;
     108             :         int i;
     109             : 
     110           0 :         sc->sc_acpi = (struct acpi_softc *)parent;
     111           0 :         sc->sc_devnode = aa->aaa_node;
     112           0 :         sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode);
     113           0 :         printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name);
     114             : 
     115           0 :         if (sc->sc_bus == -1) {
     116           0 :                 printf("\n");
     117           0 :                 return;
     118             :         }
     119             : 
     120           0 :         if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res)) {
     121           0 :                 printf(": no PCI interrupt routing table\n");
     122           0 :                 return;
     123             :         }
     124             : 
     125           0 :         if (res.type != AML_OBJTYPE_PACKAGE) {
     126           0 :                 printf(": _PRT is not a package\n");
     127           0 :                 aml_freevalue(&res);
     128           0 :                 return;
     129             :         }
     130             : 
     131           0 :         printf("\n");
     132             : 
     133           0 :         for (i = 0; i < res.length; i++)
     134           0 :                 acpiprt_prt_add(sc, res.v_package[i]);
     135             : 
     136           0 :         aml_freevalue(&res);
     137           0 : }
     138             : 
     139             : int
     140           0 : acpiprt_getirq(int crsidx, union acpi_resource *crs, void *arg)
     141             : {
     142           0 :         struct acpiprt_irq *irq = arg;
     143             :         int typ, len;
     144             : 
     145           0 :         irq->_shr = 0;
     146           0 :         irq->_ll = 0;
     147           0 :         irq->_he = 1;
     148             : 
     149           0 :         typ = AML_CRSTYPE(crs);
     150           0 :         len = AML_CRSLEN(crs);
     151           0 :         switch (typ) {
     152             :         case SR_IRQ:
     153           0 :                 irq->_int= ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
     154           0 :                 if (len > 2) {
     155           0 :                         irq->_shr = (crs->sr_irq.irq_flags & SR_IRQ_SHR);
     156           0 :                         irq->_ll = (crs->sr_irq.irq_flags & SR_IRQ_POLARITY);
     157           0 :                         irq->_he = (crs->sr_irq.irq_flags & SR_IRQ_MODE);
     158           0 :                 }
     159             :                 break;
     160             :         case LR_EXTIRQ:
     161           0 :                 irq->_int = letoh32(crs->lr_extirq.irq[0]);
     162           0 :                 irq->_shr = (crs->lr_extirq.flags & LR_EXTIRQ_SHR);
     163           0 :                 irq->_ll = (crs->lr_extirq.flags & LR_EXTIRQ_POLARITY);
     164           0 :                 irq->_he = (crs->lr_extirq.flags & LR_EXTIRQ_MODE);
     165           0 :                 break;
     166             :         default:
     167           0 :                 printf("unknown interrupt: %x\n", typ);
     168           0 :         }
     169           0 :         return (0);
     170             : }
     171             : 
     172             : int
     173             : acpiprt_pri[16] = {
     174             :         0,                      /* 8254 Counter 0 */
     175             :         1,                      /* Keyboard */
     176             :         0,                      /* 8259 Slave */
     177             :         2,                      /* Serial Port A */
     178             :         2,                      /* Serial Port B */
     179             :         5,                      /* Parallel Port / Generic */
     180             :         2,                      /* Floppy Disk */
     181             :         4,                      /* Parallel Port / Generic */
     182             :         1,                      /* RTC */
     183             :         6,                      /* Generic */
     184             :         7,                      /* Generic */
     185             :         7,                      /* Generic */
     186             :         1,                      /* Mouse */
     187             :         0,                      /* FPU */
     188             :         2,                      /* Primary IDE */
     189             :         3                       /* Secondary IDE */
     190             : };
     191             : 
     192             : int
     193           0 : acpiprt_chooseirq(int crsidx, union acpi_resource *crs, void *arg)
     194             : {
     195           0 :         struct acpiprt_irq *irq = arg;
     196             :         int typ, len, i, pri = -1;
     197             : 
     198           0 :         irq->_shr = 0;
     199           0 :         irq->_ll = 0;
     200           0 :         irq->_he = 1;
     201             : 
     202           0 :         typ = AML_CRSTYPE(crs);
     203           0 :         len = AML_CRSLEN(crs);
     204           0 :         switch (typ) {
     205             :         case SR_IRQ:
     206           0 :                 for (i = 0; i < sizeof(crs->sr_irq.irq_mask) * 8; i++) {
     207           0 :                         if (crs->sr_irq.irq_mask & (1 << i) &&
     208           0 :                             acpiprt_pri[i] > pri) {
     209           0 :                                 irq->_int = i;
     210           0 :                                 pri = acpiprt_pri[irq->_int];
     211           0 :                         }
     212             :                 }
     213           0 :                 if (len > 2) {
     214           0 :                         irq->_shr = (crs->sr_irq.irq_flags & SR_IRQ_SHR);
     215           0 :                         irq->_ll = (crs->sr_irq.irq_flags & SR_IRQ_POLARITY);
     216           0 :                         irq->_he = (crs->sr_irq.irq_flags & SR_IRQ_MODE);
     217           0 :                 }
     218             :                 break;
     219             :         case LR_EXTIRQ:
     220             :                 /* First try non-8259 interrupts. */
     221           0 :                 for (i = 0; i < crs->lr_extirq.irq_count; i++) {
     222           0 :                         if (crs->lr_extirq.irq[i] > 15) {
     223           0 :                                 irq->_int = crs->lr_extirq.irq[i];
     224           0 :                                 return (0);
     225             :                         }
     226             :                 }
     227             : 
     228           0 :                 for (i = 0; i < crs->lr_extirq.irq_count; i++) {
     229           0 :                         if (acpiprt_pri[crs->lr_extirq.irq[i]] > pri) {
     230           0 :                                 irq->_int = crs->lr_extirq.irq[i];
     231           0 :                                 pri = acpiprt_pri[irq->_int];
     232           0 :                         }
     233             :                 }
     234           0 :                 irq->_shr = (crs->lr_extirq.flags & LR_EXTIRQ_SHR);
     235           0 :                 irq->_ll = (crs->lr_extirq.flags & LR_EXTIRQ_POLARITY);
     236           0 :                 irq->_he = (crs->lr_extirq.flags & LR_EXTIRQ_MODE);
     237           0 :                 break;
     238             :         default:
     239           0 :                 printf("unknown interrupt: %x\n", typ);
     240           0 :         }
     241           0 :         return (0);
     242           0 : }
     243             : 
     244             : void
     245           0 : acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v)
     246             : {
     247             :         struct aml_node *node;
     248           0 :         struct aml_value res, *pp;
     249           0 :         struct acpiprt_irq irq;
     250             :         u_int64_t addr;
     251             :         int pin;
     252           0 :         int64_t sta;
     253             : #if NIOAPIC > 0
     254             :         struct mp_intr_map *map;
     255             :         struct ioapic_softc *apic;
     256             : #endif
     257             :         pci_chipset_tag_t pc = NULL;
     258             :         pcitag_t tag;
     259             :         pcireg_t reg;
     260             :         int bus, dev, func, nfuncs;
     261             :         struct acpiprt_map *p;
     262             : 
     263           0 :         if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) {
     264           0 :                 printf("invalid mapping object\n");
     265           0 :                 return;
     266             :         }
     267             : 
     268           0 :         addr = aml_val2int(v->v_package[0]);
     269           0 :         pin = aml_val2int(v->v_package[1]);
     270           0 :         if (pin > 3) {
     271           0 :                 return;
     272             :         }
     273             : 
     274           0 :         pp = v->v_package[2];
     275           0 :         if (pp->type == AML_OBJTYPE_STRING) {
     276           0 :                 node = aml_searchrel(sc->sc_devnode, pp->v_string);
     277           0 :                 if (node == NULL) {
     278           0 :                         printf("Invalid device\n");
     279           0 :                         return;
     280             :                 }
     281           0 :                 pp = node->value;
     282           0 :         }
     283           0 :         if (pp->type == AML_OBJTYPE_NAMEREF) {
     284           0 :                 node = aml_searchrel(sc->sc_devnode, pp->v_nameref);
     285           0 :                 if (node == NULL) {
     286           0 :                         printf("Invalid device\n");
     287           0 :                         return;
     288             :                 }
     289           0 :                 pp = node->value;
     290           0 :         }
     291           0 :         if (pp->type == AML_OBJTYPE_OBJREF) {
     292           0 :                 pp = pp->v_objref.ref;
     293           0 :         }
     294           0 :         if (pp->type == AML_OBJTYPE_DEVICE) {
     295           0 :                 node = pp->node;
     296           0 :                 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
     297           0 :                         printf("no _STA method\n");
     298           0 :                         return;
     299             :                 }
     300             : 
     301           0 :                 if ((sta & STA_PRESENT) == 0)
     302           0 :                         return;
     303             : 
     304           0 :                 if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
     305           0 :                         printf("no _CRS method\n");
     306           0 :                         return;
     307             :                 }
     308             : 
     309           0 :                 if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
     310           0 :                         printf("invalid _CRS object\n");
     311           0 :                         aml_freevalue(&res);
     312           0 :                         return;
     313             :                 }
     314           0 :                 aml_parse_resource(&res, acpiprt_getirq, &irq);
     315           0 :                 aml_freevalue(&res);
     316             : 
     317             :                 /* Pick a new IRQ if necessary. */
     318           0 :                 if ((irq._int == 0 || irq._int == 2 || irq._int == 13) &&
     319           0 :                     !aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)){
     320           0 :                         aml_parse_resource(&res, acpiprt_chooseirq, &irq);
     321           0 :                         aml_freevalue(&res);
     322           0 :                 }
     323             : 
     324           0 :                 if ((p = malloc(sizeof(*p), M_ACPI, M_NOWAIT)) == NULL)
     325           0 :                         return;
     326           0 :                 p->bus = sc->sc_bus;
     327           0 :                 p->dev = ACPI_PCI_DEV(addr << 16);
     328           0 :                 p->pin = pin;
     329           0 :                 p->irq = irq._int;
     330           0 :                 p->sc = sc;
     331           0 :                 p->node = node;
     332           0 :                 SIMPLEQ_INSERT_TAIL(&acpiprt_map_list, p, list);
     333           0 :         } else {
     334           0 :                 irq._int = aml_val2int(v->v_package[3]);
     335           0 :                 irq._shr = 1;
     336           0 :                 irq._ll = 1;
     337           0 :                 irq._he = 0;
     338             :         }
     339             : 
     340             : #ifdef ACPI_DEBUG
     341             :         printf("%s: %s addr 0x%llx pin %d irq %d\n",
     342             :             DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq._int);
     343             : #endif
     344             : 
     345             : #if NIOAPIC > 0
     346           0 :         if (nioapics > 0) {
     347           0 :                 apic = ioapic_find_bybase(irq._int);
     348           0 :                 if (apic == NULL) {
     349           0 :                         printf("%s: no apic found for irq %d\n",
     350           0 :                             DEVNAME(sc), irq._int);
     351           0 :                         return;
     352             :                 }
     353             : 
     354           0 :                 map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
     355           0 :                 if (map == NULL)
     356           0 :                         return;
     357             : 
     358           0 :                 map->ioapic = apic;
     359           0 :                 map->ioapic_pin = irq._int - apic->sc_apic_vecbase;
     360           0 :                 map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3);
     361           0 :                 if (irq._ll)
     362           0 :                         map->flags |= (MPS_INTPO_ACTLO << MPS_INTPO_SHIFT);
     363             :                 else
     364           0 :                         map->flags |= (MPS_INTPO_ACTHI << MPS_INTPO_SHIFT);
     365           0 :                 if (irq._he)
     366           0 :                         map->flags |= (MPS_INTTR_EDGE << MPS_INTTR_SHIFT);
     367             :                 else
     368           0 :                         map->flags |= (MPS_INTTR_LEVEL << MPS_INTTR_SHIFT);
     369             : 
     370           0 :                 map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
     371           0 :                 switch ((map->flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK) {
     372             :                 case MPS_INTPO_DEF:
     373             :                 case MPS_INTPO_ACTLO:
     374           0 :                         map->redir |= IOAPIC_REDLO_ACTLO;
     375           0 :                         break;
     376             :                 }
     377           0 :                 switch ((map->flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK) {
     378             :                 case MPS_INTTR_DEF:
     379             :                 case MPS_INTTR_LEVEL:
     380           0 :                         map->redir |= IOAPIC_REDLO_LEVEL;
     381           0 :                         break;
     382             :                 }
     383             : 
     384           0 :                 map->ioapic_ih = APIC_INT_VIA_APIC |
     385           0 :                     ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
     386           0 :                     (map->ioapic_pin << APIC_INT_PIN_SHIFT));
     387             : 
     388           0 :                 apic->sc_pins[map->ioapic_pin].ip_map = map;
     389             : 
     390           0 :                 map->next = mp_busses[sc->sc_bus].mb_intrs;
     391           0 :                 mp_busses[sc->sc_bus].mb_intrs = map;
     392             : 
     393           0 :                 return;
     394             :         }
     395             : #endif
     396             : 
     397           0 :         bus = sc->sc_bus;
     398           0 :         dev = ACPI_PCI_DEV(addr << 16);
     399           0 :         tag = pci_make_tag(pc, bus, dev, 0);
     400             : 
     401           0 :         reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
     402           0 :         if (PCI_HDRTYPE_MULTIFN(reg))
     403           0 :                 nfuncs = 8;
     404             :         else
     405             :                 nfuncs = 1;
     406             : 
     407           0 :         for (func = 0; func < nfuncs; func++) {
     408           0 :                 tag = pci_make_tag(pc, bus, dev, func);
     409           0 :                 reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
     410           0 :                 if (PCI_INTERRUPT_PIN(reg) == pin + 1) {
     411           0 :                         reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
     412           0 :                         reg |= irq._int << PCI_INTERRUPT_LINE_SHIFT;
     413           0 :                         pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
     414           0 :                 }
     415             :         }
     416           0 : }
     417             : 
     418             : int
     419           0 : acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node)
     420             : {
     421             :         /* Check if parent device has PCI mapping */
     422           0 :         return (node->parent && node->parent->pci) ?
     423           0 :                 node->parent->pci->sub : -1;
     424             : }
     425             : 
     426             : void
     427           0 : acpiprt_route_interrupt(int bus, int dev, int pin)
     428             : {
     429             :         struct acpiprt_softc *sc;
     430             :         struct acpiprt_map *p;
     431           0 :         struct acpiprt_irq irq;
     432             :         struct aml_node *node = NULL;
     433           0 :         struct aml_value res, res2;
     434             :         union acpi_resource *crs;
     435             :         int newirq;
     436           0 :         int64_t sta;
     437             : 
     438           0 :         SIMPLEQ_FOREACH(p, &acpiprt_map_list, list) {
     439           0 :                 if (p->bus == bus && p->dev == dev && p->pin == (pin - 1)) {
     440           0 :                         newirq = p->irq;
     441           0 :                         sc = p->sc;
     442           0 :                         node = p->node;
     443           0 :                         break;
     444             :                 }
     445             :         }
     446           0 :         if (node == NULL)
     447           0 :                 return;
     448             : 
     449           0 :         if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
     450           0 :                 printf("no _STA method\n");
     451           0 :                 return;
     452             :         }
     453             : 
     454           0 :         KASSERT(sta & STA_PRESENT);
     455             : 
     456           0 :         if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
     457           0 :                 printf("no _CRS method\n");
     458           0 :                 return;
     459             :         }
     460           0 :         if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
     461           0 :                 printf("invalid _CRS object\n");
     462           0 :                 aml_freevalue(&res);
     463           0 :                 return;
     464             :         }
     465           0 :         aml_parse_resource(&res, acpiprt_getirq, &irq);
     466             : 
     467             :         /* Only re-route interrupts when necessary. */
     468           0 :         if ((sta & STA_ENABLED) && irq._int == newirq) {
     469           0 :                 aml_freevalue(&res);
     470           0 :                 return;
     471             :         }
     472             : 
     473           0 :         crs = (union acpi_resource *)res.v_buffer;
     474           0 :         switch (AML_CRSTYPE(crs)) {
     475             :         case SR_IRQ:
     476           0 :                 crs->sr_irq.irq_mask = htole16(1 << newirq);
     477           0 :                 break;
     478             :         case LR_EXTIRQ:
     479           0 :                 crs->lr_extirq.irq[0] = htole32(newirq);
     480           0 :                 break;
     481             :         }
     482             : 
     483           0 :         if (aml_evalname(sc->sc_acpi, node, "_SRS", 1, &res, &res2)) {
     484           0 :                 printf("no _SRS method\n");
     485           0 :                 aml_freevalue(&res);
     486           0 :                 return;
     487             :         }
     488           0 :         aml_freevalue(&res);
     489           0 :         aml_freevalue(&res2);
     490           0 : }

Generated by: LCOV version 1.13