Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/acpi Add code to perform PCI interrupt routing fixup.



details:   https://anonhg.NetBSD.org/src/rev/1c1f65a2b7c2
branches:  trunk
changeset: 534532:1c1f65a2b7c2
user:      augustss <augustss%NetBSD.org@localhost>
date:      Mon Jul 29 03:06:56 2002 +0000

description:
Add code to perform PCI interrupt routing fixup.

diffstat:

 sys/dev/acpi/acpi.c |  292 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 290 insertions(+), 2 deletions(-)

diffs (truncated from 331 to 300 lines):

diff -r ffa64edddc89 -r 1c1f65a2b7c2 sys/dev/acpi/acpi.c
--- a/sys/dev/acpi/acpi.c       Mon Jul 29 03:05:52 2002 +0000
+++ b/sys/dev/acpi/acpi.c       Mon Jul 29 03:06:56 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: acpi.c,v 1.12 2002/07/18 12:05:11 kanaoka Exp $        */
+/*     $NetBSD: acpi.c,v 1.13 2002/07/29 03:06:56 augustss Exp $       */
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.12 2002/07/18 12:05:11 kanaoka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.13 2002/07/29 03:06:56 augustss Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -53,6 +53,15 @@
 #include <dev/acpi/acpivar.h>
 #include <dev/acpi/acpi_osd.h>
 
+#ifndef ACPI_PCI_FIXUP
+#define ACPI_PCI_FIXUP 1
+#endif
+
+#if ACPI_PCI_FIXUP
+#include <dev/acpi/acpica/Subsystem/acnamesp.h> /* AcpiNsGetNodeByPath() */
+#include <dev/pci/pcidevs.h>
+#endif
+
 #include <machine/acpi_machdep.h>
 
 #ifdef ENABLE_DEBUGGER
@@ -95,6 +104,10 @@
 ACPI_STATUS    acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **);
 
 void           acpi_enable_fixed_events(struct acpi_softc *);
+#if ACPI_PCI_FIXUP
+void           acpi_pci_fixup(struct acpi_softc *);
+ACPI_STATUS    acpi_allocate_resources(ACPI_HANDLE handle);
+#endif
 
 /*
  * acpi_probe:
@@ -266,6 +279,13 @@
        acpi_enable_fixed_events(sc);
 
        /*
+        * Fix up PCI devices.
+        */
+#if ACPI_PCI_FIXUP
+       acpi_pci_fixup(sc);
+#endif
+ 
+       /*
         * Scan the namespace and build our device tree.
         */
 #ifdef ENABLE_DEBUGGER
@@ -791,3 +811,271 @@
 
        return (ret);
 }
+
+#if ACPI_PCI_FIXUP
+ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **);
+/*
+ * acpi_pci_fixup:
+ *
+ *     Set up PCI devices that BIOS didn't handle right.
+ *     Iterate through all devices and try to get the _PTR
+ *     (PCI Routing Table).  If it exists then make sure all
+ *     interrupt links that it uses are working.
+ */
+void
+acpi_pci_fixup(struct acpi_softc *sc)
+{
+       ACPI_HANDLE parent;
+
+#ifdef ACPI_DEBUG
+       printf("acpi_pci_fixup starts:\n");
+#endif
+       if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK)
+               return;
+       sc->sc_pci_bus = 0;
+       AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
+           acpi_pci_fixup_bus, sc, NULL);
+}
+
+static ACPI_HANDLE
+acpi_get_node(char *name)
+{
+       ACPI_NAMESPACE_NODE *ObjDesc;
+       ACPI_STATUS Status;
+
+       Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc);
+       if (ACPI_FAILURE (Status)) {
+               printf("acpi_get_node: could not find: %s\n",
+                      AcpiFormatException (Status));
+               return NULL;
+       }
+       return ObjDesc;
+}
+
+static uint
+acpi_get_intr(ACPI_HANDLE handle)
+{
+       ACPI_BUFFER ret;
+       ACPI_STATUS rv;
+       ACPI_RESOURCE *res;
+       ACPI_RESOURCE_IRQ *irq;
+       uint intr;
+
+       intr = -1;
+       rv = acpi_get(handle, &ret, AcpiGetCurrentResources);
+       if (ACPI_FAILURE(rv))
+               return (intr);
+       for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG;
+            res = ACPI_NEXT_RESOURCE(res)) {
+               if (res->Id == ACPI_RSTYPE_IRQ) {
+                       irq = (ACPI_RESOURCE_IRQ *)&res->Data;
+                       if (irq->NumberOfInterrupts == 1)
+                               intr = irq->Interrupts[0];
+                       break;
+               }
+       }
+       free(ret.Pointer, M_DEVBUF);
+       return (intr);
+}
+
+static void
+acpi_pci_set_line(int bus, int dev, int pin, int line)
+{
+       ACPI_STATUS err;
+       ACPI_PCI_ID pid;
+       UINT32 intr, id, bhlc;
+       int func, nfunc;
+
+       pid.Bus = bus;
+       pid.Device = dev;
+       pid.Function = 0;
+       
+       err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32);
+       if (err)
+               return;
+       if (PCI_HDRTYPE_MULTIFN(bhlc))
+               nfunc = 8;
+       else
+               nfunc = 1;
+
+       for (func = 0; func < nfunc; func++) {
+               pid.Function = func;
+
+               err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32);
+               if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
+                   PCI_VENDOR(id) == 0)
+                       continue;
+
+               err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG,
+                         &intr, 32);
+               if (err) {
+                       printf("AcpiOsReadPciConfiguration failed %d\n", err);
+                       return;
+               }
+               if (pin == PCI_INTERRUPT_PIN(intr) &&
+                   line != PCI_INTERRUPT_LINE(intr)) {
+#ifdef ACPI_DEBUG
+                       printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n",
+                              bus, dev, func,
+                              pin + '@', PCI_INTERRUPT_LINE(intr),
+                              line);
+#endif
+                       intr &= ~(PCI_INTERRUPT_LINE_MASK <<
+                                 PCI_INTERRUPT_LINE_SHIFT);
+                       intr |= line << PCI_INTERRUPT_LINE_SHIFT;
+                       err = AcpiOsWritePciConfiguration(&pid,
+                                 PCI_INTERRUPT_REG, intr, 32);
+                       if (err) {
+                               printf("AcpiOsWritePciConfiguration failed"
+                                      " %d\n", err);
+                               return;
+                       }
+               }
+       }
+}
+
+ACPI_STATUS
+acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context,
+                  void **status)
+{
+       struct acpi_softc *sc = context;
+       ACPI_STATUS rv;
+       ACPI_BUFFER buf;
+       UINT8 *Buffer;
+       ACPI_PCI_ROUTING_TABLE *PrtElement;
+       ACPI_HANDLE link;
+       uint line;
+
+       rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
+       if (ACPI_FAILURE(rv))
+               return (AE_OK);
+
+#ifdef ACPI_DEBUG
+       printf("%s: fixing up PCI\n", sc->sc_dev.dv_xname);
+#endif
+
+        for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) {
+               PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer;
+               if (PrtElement->Length == 0)
+                       break;
+               if (PrtElement->Source == NULL)
+                       continue;
+
+               link = acpi_get_node(PrtElement->Source);
+               if (link == NULL)
+                       continue;
+               line = acpi_get_intr(link);
+               if (line == -1) {
+#ifdef ACPI_DEBUG
+                       printf("%s: fixing up link %s\n", sc->sc_dev.dv_xname,
+                           PrtElement->Source);
+#endif
+                       rv = acpi_allocate_resources(link);
+                       if (ACPI_FAILURE(rv)) {
+                               printf("%s: interrupt allocation failed %s\n",
+                                   sc->sc_dev.dv_xname, PrtElement->Source);
+                               continue;
+                       }
+                       line = acpi_get_intr(link);
+                       if (line == -1) {
+                               printf("%s: get intr failed %s\n",
+                                   sc->sc_dev.dv_xname, PrtElement->Source);
+                               continue;
+                       }
+               }
+
+               acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16,
+                   PrtElement->Pin + 1, line);
+       }
+
+       sc->sc_pci_bus++;
+
+       free(buf.Pointer, M_DEVBUF);
+       return (AE_OK);
+}
+
+/* XXX This very incomplete */
+ACPI_STATUS
+acpi_allocate_resources(ACPI_HANDLE handle)
+{
+       ACPI_BUFFER bufp, bufc, bufn;
+       ACPI_RESOURCE *resp, *resc, *resn;
+       ACPI_RESOURCE_IRQ *irq;
+       ACPI_STATUS rv;
+       uint delta;
+
+       rv = acpi_get(handle, &bufp, AcpiGetPossibleResources);
+       if (ACPI_FAILURE(rv))
+               goto out;
+       rv = acpi_get(handle, &bufc, AcpiGetCurrentResources);
+       if (ACPI_FAILURE(rv)) {
+               goto out1;
+       }
+
+       bufn.Length = 1000;
+       bufn.Pointer = resn = malloc(bufn.Length, M_DEVBUF, M_WAITOK);
+       resp = bufp.Pointer;
+       resc = bufc.Pointer;
+       while (resc->Id != ACPI_RSTYPE_END_TAG &&
+              resp->Id != ACPI_RSTYPE_END_TAG) {
+               while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG)
+                       resp = ACPI_NEXT_RESOURCE(resp);
+               if (resp->Id == ACPI_RSTYPE_END_TAG)
+                       break;
+               /* Found identical Id */
+               resn->Id = resc->Id;
+               switch (resc->Id) {
+               case ACPI_RSTYPE_IRQ:
+                       memcpy(&resn->Data, &resp->Data,
+                              sizeof(ACPI_RESOURCE_IRQ));
+                       irq = (ACPI_RESOURCE_IRQ *)&resn->Data;
+                       irq->Interrupts[0] =
+                           ((ACPI_RESOURCE_IRQ *)&resp->Data)->
+                               Interrupts[irq->NumberOfInterrupts-1];
+                       irq->NumberOfInterrupts = 1;
+                       resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
+                       break;
+               case ACPI_RSTYPE_IO:
+                       memcpy(&resn->Data, &resp->Data,
+                              sizeof(ACPI_RESOURCE_IO));
+                       resn->Length = resp->Length;
+                       break;
+               default:
+                       printf("acpi_allocate_resources: res=%d\n", resc->Id);
+                       rv = AE_BAD_DATA;
+                       goto out2;
+               }
+               resc = ACPI_NEXT_RESOURCE(resc);
+               resn = ACPI_NEXT_RESOURCE(resn);
+               delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer;



Home | Main Index | Thread Index | Old Index