summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/acpica/acpi_pci_link.c1546
-rw-r--r--sys/dev/acpica/acpi_pcib.c170
-rw-r--r--sys/dev/acpica/acpi_pcib_acpi.c3
-rw-r--r--sys/dev/acpica/acpi_pcib_pci.c2
-rw-r--r--sys/dev/acpica/acpi_pcibvar.h36
5 files changed, 697 insertions, 1060 deletions
diff --git a/sys/dev/acpica/acpi_pci_link.c b/sys/dev/acpica/acpi_pci_link.c
index 5558946..8aa27a1 100644
--- a/sys/dev/acpica/acpi_pci_link.c
+++ b/sys/dev/acpica/acpi_pci_link.c
@@ -29,13 +29,18 @@ __FBSDID("$FreeBSD$");
#include "opt_acpi.h"
#include <sys/param.h>
-#include <sys/kernel.h>
#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
#include "acpi.h"
#include <dev/acpica/acpivar.h>
#include <dev/acpica/acpi_pcibvar.h>
+#include <machine/pci_cfgreg.h>
+#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include "pcib_if.h"
@@ -43,1119 +48,714 @@ __FBSDID("$FreeBSD$");
#define _COMPONENT ACPI_BUS
ACPI_MODULE_NAME("PCI_LINK")
-TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
-static struct acpi_pci_link_entries acpi_pci_link_entries;
ACPI_SERIAL_DECL(pci_link, "ACPI PCI link");
-TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
-static struct acpi_prt_entries acpi_prt_entries;
-
-static int irq_penalty[MAX_ACPI_INTERRUPTS];
-
-static int acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link,
- UINT8 irq);
-static void acpi_pci_link_update_irq_penalty(device_t dev, int busno);
-static void acpi_pci_link_set_bootdisabled_priority(void);
-static void acpi_pci_link_fixup_bootdisabled_link(void);
+#define NUM_ISA_INTERRUPTS 16
+#define NUM_ACPI_INTERRUPTS 256
/*
- * PCI link object management
+ * An ACPI PCI link device may contain multiple links. Each link has its
+ * own ACPI resource. _PRT entries specify which link is being used via
+ * the Source Index.
*/
-static void
-acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
-{
+struct link;
- switch (ActiveHighLow) {
- case ACPI_ACTIVE_HIGH:
- printf("high,");
- break;
- case ACPI_ACTIVE_LOW:
- printf("low,");
- break;
- default:
- printf("unknown,");
- break;
- }
-}
+struct acpi_pci_link_softc {
+ int pl_num_links;
+ struct link *pl_links;
+};
-static void
-acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
-{
+struct link {
+ struct acpi_pci_link_softc *l_sc;
+ uint8_t l_bios_irq;
+ uint8_t l_irq;
+ uint8_t l_initial_irq;
+ int l_res_index;
+ int l_num_irqs;
+ int *l_irqs;
+ int l_references;
+ int l_routed:1;
+ int l_isa_irq:1;
+ ACPI_RESOURCE l_prs_template;
+};
- switch (EdgeLevel) {
- case ACPI_EDGE_SENSITIVE:
- printf("edge,");
- break;
- case ACPI_LEVEL_SENSITIVE:
- printf("level,");
- break;
- default:
- printf("unknown,");
- break;
- }
-}
+struct link_res_request {
+ struct acpi_pci_link_softc *sc;
+ int count;
+};
-static void
-acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
-{
+MALLOC_DEFINE(M_PCI_LINK, "PCI Link", "ACPI PCI Link structures");
- switch (SharedExclusive) {
- case ACPI_EXCLUSIVE:
- printf("exclusive");
- break;
- case ACPI_SHARED:
- printf("sharable");
- break;
- default:
- printf("unknown");
- break;
- }
-}
+static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS];
+static int pci_link_bios_isa_irqs;
-static void
-acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
-{
- UINT8 i;
- ACPI_RESOURCE_IRQ *Irq;
- ACPI_RESOURCE_EXT_IRQ *ExtIrq;
- struct acpi_pci_link_entry *link;
+static char *pci_link_ids[] = { "PNP0C0F", NULL };
- if (entry == NULL || entry->pci_link == NULL)
- return;
- link = entry->pci_link;
+/*
+ * Fetch the short name associated with an ACPI handle and save it in the
+ * passed in buffer.
+ */
+static ACPI_STATUS
+acpi_short_name(ACPI_HANDLE handle, char *buffer, size_t buflen)
+{
+ ACPI_BUFFER buf;
- printf("%s irq%c%2d: ", acpi_name(link->handle),
- (link->flags & ACPI_LINK_ROUTED) ? '*' : ' ', link->current_irq);
+ buf.Length = buflen;
+ buf.Pointer = buffer;
+ return (AcpiGetName(handle, ACPI_SINGLE_NAME, &buf));
+}
- printf("[");
- if (link->number_of_interrupts)
- printf("%2d", link->interrupts[0]);
- for (i = 1; i < link->number_of_interrupts; i++)
- printf("%3d", link->interrupts[i]);
- printf("] %2d+ ", link->initial_irq);
+static int
+acpi_pci_link_probe(device_t dev)
+{
+ char descr[64], name[10];
- switch (link->possible_resources.Id) {
- case ACPI_RSTYPE_IRQ:
- Irq = &link->possible_resources.Data.Irq;
- acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
- acpi_pci_link_dump_trigger(Irq->EdgeLevel);
- acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
- break;
- case ACPI_RSTYPE_EXT_IRQ:
- ExtIrq = &link->possible_resources.Data.ExtendedIrq;
- acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
- acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
- acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
- break;
+ /*
+ * We explicitly do not check _STA since not all systems set it to
+ * sensible values.
+ */
+ if (!acpi_disabled("pci_link") &&
+ ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids) != NULL) {
+ if (ACPI_FAILURE(acpi_short_name(acpi_get_handle(dev), name,
+ sizeof(name))))
+ device_set_desc(dev, "ACPI PCI Link");
+ else {
+ snprintf(descr, sizeof(descr), "ACPI PCI Link %s",
+ name);
+ device_set_desc_copy(dev, descr);
+ }
+ return (0);
}
-
- printf(" %d.%d.%d\n", entry->busno,
- (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)),
- (int)entry->prt.Pin);
+ return (ENXIO);
}
static ACPI_STATUS
-acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
+acpi_count_resources(ACPI_RESOURCE *res, void *context)
{
- ACPI_DEVICE_INFO *devinfo;
- ACPI_BUFFER buf;
- ACPI_STATUS error;
-
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ int *count;
- if (handle == NULL || sta == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
- return_ACPI_STATUS (AE_BAD_PARAMETER);
- }
-
- buf.Pointer = NULL;
- buf.Length = ACPI_ALLOCATE_BUFFER;
- error = AcpiGetObjectInfo(handle, &buf);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "couldn't get object info %s - %s\n",
- acpi_name(handle), AcpiFormatException(error)));
- return_ACPI_STATUS (error);
- }
-
- devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
- if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
- strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
- acpi_name(handle)));
- AcpiOsFree(buf.Pointer);
- return_ACPI_STATUS (AE_TYPE);
- }
-
- if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
- *sta = devinfo->CurrentStatus;
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
- acpi_name(handle)));
- *sta = 0;
- }
-
- AcpiOsFree(buf.Pointer);
- return_ACPI_STATUS (AE_OK);
+ count = (int *)context;
+ (*count)++;
+ return (AE_OK);
}
static ACPI_STATUS
-acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
- UINT8 *number_of_interrupts, UINT8 interrupts[])
+link_add_crs(ACPI_RESOURCE *res, void *context)
{
- UINT8 count;
- UINT8 i;
- UINT32 NumberOfInterrupts;
- UINT32 *Interrupts;
+ struct link_res_request *req;
+ struct link *link;
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(pci_link);
+ req = (struct link_res_request *)context;
+ link = &req->sc->pl_links[req->count];
+ req->count++;
+ switch (res->Id) {
+ case ACPI_RSTYPE_IRQ:
+ case ACPI_RSTYPE_EXT_IRQ:
+ if (res->Id == ACPI_RSTYPE_IRQ) {
+ if (res->Data.Irq.NumberOfInterrupts > 0) {
+ KASSERT(res->Data.Irq.NumberOfInterrupts == 1,
+ ("%s: too many interrupts", __func__));
+ link->l_irq = res->Data.Irq.Interrupts[0];
+ }
+ } else if (res->Data.ExtendedIrq.NumberOfInterrupts > 0) {
+ KASSERT(res->Data.ExtendedIrq.NumberOfInterrupts == 1,
+ ("%s: too many interrupts", __func__));
+ link->l_irq = res->Data.ExtendedIrq.Interrupts[0];
+ }
- if (resources == NULL || number_of_interrupts == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
- return_ACPI_STATUS (AE_BAD_PARAMETER);
+ /*
+ * An IRQ of zero means that the link isn't routed.
+ */
+ if (link->l_irq == 0)
+ link->l_irq = PCI_INVALID_IRQ;
+ break;
}
+ return (AE_OK);
+}
- *number_of_interrupts = 0;
- NumberOfInterrupts = 0;
- Interrupts = NULL;
-
- if (resources->Id == ACPI_RSTYPE_START_DPF)
- resources = ACPI_NEXT_RESOURCE(resources);
-
- if (resources->Id != ACPI_RSTYPE_IRQ &&
- resources->Id != ACPI_RSTYPE_EXT_IRQ) {
- printf("acpi link get: resource %d is not an IRQ\n",
- resources->Id);
- return_ACPI_STATUS (AE_TYPE);
- }
+/*
+ * Populate the set of possible IRQs for each device.
+ */
+static ACPI_STATUS
+link_add_prs(ACPI_RESOURCE *res, void *context)
+{
+ struct link_res_request *req;
+ struct link *link;
+ UINT32 *irqs;
+ int i;
- switch (resources->Id) {
+ ACPI_SERIAL_ASSERT(pci_link);
+ req = (struct link_res_request *)context;
+ link = &req->sc->pl_links[req->count];
+ req->count++;
+ switch (res->Id) {
case ACPI_RSTYPE_IRQ:
- NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
- Interrupts = resources->Data.Irq.Interrupts;
- break;
case ACPI_RSTYPE_EXT_IRQ:
- NumberOfInterrupts =
- resources->Data.ExtendedIrq.NumberOfInterrupts;
- Interrupts = resources->Data.ExtendedIrq.Interrupts;
- break;
- }
-
- if (NumberOfInterrupts == 0)
- return_ACPI_STATUS (AE_NULL_ENTRY);
- count = 0;
- for (i = 0; i < NumberOfInterrupts; i++) {
- if (i >= MAX_POSSIBLE_INTERRUPTS) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs (%d)\n",
- i));
- break;
+ /*
+ * Stash a copy of the resource for later use when doing
+ * _SRS.
+ */
+ bcopy(res, &link->l_prs_template, sizeof(ACPI_RESOURCE));
+ if (res->Id == ACPI_RSTYPE_IRQ) {
+ link->l_num_irqs = res->Data.Irq.NumberOfInterrupts;
+ irqs = res->Data.Irq.Interrupts;
+ } else {
+ link->l_num_irqs =
+ res->Data.ExtendedIrq.NumberOfInterrupts;
+ irqs = res->Data.ExtendedIrq.Interrupts;
}
- if (Interrupts[i] == 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid IRQ %d\n",
- Interrupts[i]));
- continue;
+ if (link->l_num_irqs == 0)
+ break;
+
+ /*
+ * Save a list of the valid IRQs. Also, if all of the
+ * valid IRQs are ISA IRQs, then mark this link as
+ * routed via an ISA interrupt.
+ */
+ link->l_isa_irq = 1;
+ link->l_irqs = malloc(sizeof(int) * link->l_num_irqs,
+ M_PCI_LINK, M_WAITOK | M_ZERO);
+ for (i = 0; i < link->l_num_irqs; i++) {
+ link->l_irqs[i] = irqs[i];
+ if (irqs[1] >= NUM_ISA_INTERRUPTS)
+ link->l_isa_irq = 0;
}
- interrupts[count] = Interrupts[i];
- count++;
+ break;
}
- *number_of_interrupts = count;
-
- return_ACPI_STATUS (AE_OK);
+ return (AE_OK);
}
-static ACPI_STATUS
-acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
+static int
+link_valid_irq(struct link *link, int irq)
{
- ACPI_STATUS error;
- ACPI_BUFFER buf;
- ACPI_RESOURCE *resources;
- UINT8 number_of_interrupts;
- UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];;
-
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ int i;
- if (link == NULL || irq == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
- return_ACPI_STATUS (AE_BAD_PARAMETER);
- }
-
- *irq = 0;
- buf.Pointer = NULL;
- buf.Length = ACPI_ALLOCATE_BUFFER;
- error = AcpiGetCurrentResources(link->handle, &buf);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "couldn't get PCI interrupt link device _CRS %s - %s\n",
- acpi_name(link->handle), AcpiFormatException(error)));
- return_ACPI_STATUS (error);
- }
- if (buf.Pointer == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "couldn't allocate memory - %s\n",
- acpi_name(link->handle)));
- return_ACPI_STATUS (AE_NO_MEMORY);
- }
+ ACPI_SERIAL_ASSERT(pci_link);
- resources = (ACPI_RESOURCE *) buf.Pointer;
- number_of_interrupts = 0;
- bzero(interrupts, sizeof(interrupts));
- error = acpi_pci_link_get_irq_resources(resources,
- &number_of_interrupts, interrupts);
- AcpiOsFree(buf.Pointer);
-
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't get current IRQ from interrupt link %s - %s\n",
- acpi_name(link->handle), AcpiFormatException(error)));
- return_ACPI_STATUS (error);
- }
+ /* Invalid interrupts are never valid. */
+ if (!PCI_INTERRUPT_VALID(irq))
+ return (0);
- if (number_of_interrupts == 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "PCI interrupt link device _CRS data is corrupted - %s\n",
- acpi_name(link->handle)));
- return_ACPI_STATUS (AE_NULL_ENTRY);
- }
+ /* Any interrupt in the list of possible interrupts is valid. */
+ for (i = 0; i < link->l_num_irqs; i++)
+ if (link->l_irqs[i] == irq)
+ return (1);
- *irq = interrupts[0];
+ /*
+ * For links routed via an ISA interrupt, if the SCI is routed via
+ * an ISA interrupt, the SCI is always treated as a valid IRQ.
+ */
+ if (link->l_isa_irq && AcpiGbl_FADT->SciInt == irq &&
+ irq < NUM_ISA_INTERRUPTS)
+ return (1);
- return_ACPI_STATUS (AE_OK);
+ /* If the interrupt wasn't found in the list it is not valid. */
+ return (0);
}
-static ACPI_STATUS
-acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
+static void
+acpi_pci_link_dump(struct acpi_pci_link_softc *sc)
{
- ACPI_STATUS error;
- ACPI_BUFFER buf;
- ACPI_RESOURCE *resources;
- struct acpi_pci_link_entry *link;
+ struct link *link;
+ int i, j;
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
ACPI_SERIAL_ASSERT(pci_link);
-
- entry->pci_link = NULL;
- TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
- if (link->handle == handle) {
- entry->pci_link = link;
- link->references++;
- return_ACPI_STATUS (AE_OK);
- }
- }
-
- link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
- if (link == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "couldn't allocate memory - %s\n", acpi_name(handle)));
- return_ACPI_STATUS (AE_NO_MEMORY);
+ printf("Index IRQ Rtd Ref IRQs\n");
+ for (i = 0; i < sc->pl_num_links; i++) {
+ link = &sc->pl_links[i];
+ printf("%5d %3d %c %3d ", i, link->l_irq,
+ link->l_routed ? 'Y' : 'N', link->l_references);
+ if (link->l_num_irqs == 0)
+ printf(" none");
+ else for (j = 0; j < link->l_num_irqs; j++)
+ printf(" %d", link->l_irqs[j]);
+ printf("\n");
}
+}
- buf.Pointer = NULL;
- buf.Length = ACPI_ALLOCATE_BUFFER;
+static int
+acpi_pci_link_attach(device_t dev)
+{
+ struct acpi_pci_link_softc *sc;
+ struct link_res_request req;
+ ACPI_STATUS status;
+ int i;
- bzero(link, sizeof(struct acpi_pci_link_entry));
- link->handle = handle;
+ sc = device_get_softc(dev);
+ ACPI_SERIAL_BEGIN(pci_link);
/*
- * Get the IRQ configured at boot-time. If successful, set this
- * as the initial IRQ.
+ * Count the number of current resources so we know how big of
+ * a link array to allocate.
*/
- error = acpi_pci_link_get_current_irq(link, &link->current_irq);
- if (ACPI_SUCCESS(error)) {
- link->initial_irq = link->current_irq;
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't get current IRQ from interrupt link %s - %s\n",
- acpi_name(handle), AcpiFormatException(error)));
- link->initial_irq = 0;
- }
-
- error = AcpiGetPossibleResources(handle, &buf);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't get interrupt link device _PRS data %s - %s\n",
- acpi_name(handle), AcpiFormatException(error)));
- goto out;
- }
- if (buf.Pointer == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "_PRS buffer is empty - %s\n", acpi_name(handle)));
- error = AE_NO_MEMORY;
- goto out;
+ status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+ acpi_count_resources, &sc->pl_num_links);
+ if (ACPI_FAILURE(status))
+ return (ENXIO);
+ if (sc->pl_num_links == 0)
+ return (0);
+ sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links,
+ M_PCI_LINK, M_WAITOK | M_ZERO);
+
+ /* Initialize the child links. */
+ for (i = 0; i < sc->pl_num_links; i++) {
+ sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+ sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
+ sc->pl_links[i].l_res_index = i;
+ sc->pl_links[i].l_sc = sc;
+ sc->pl_links[i].l_isa_irq = 0;
+ }
+ req.count = 0;
+ req.sc = sc;
+ status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
+ link_add_crs, &req);
+ if (ACPI_FAILURE(status))
+ goto fail;
+ req.count = 0;
+ status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
+ link_add_prs, &req);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ goto fail;
+ if (bootverbose) {
+ device_printf(dev, "Links after initial probe:\n");
+ acpi_pci_link_dump(sc);
}
- /* Skip any DPF descriptors. XXX We should centralize this code. */
- resources = (ACPI_RESOURCE *) buf.Pointer;
- if (resources->Id == ACPI_RSTYPE_START_DPF)
- resources = ACPI_NEXT_RESOURCE(resources);
-
- /* XXX This only handles one resource, ignoring SourceIndex. */
- bcopy(resources, &link->possible_resources,
- sizeof(link->possible_resources));
-
- error = acpi_pci_link_get_irq_resources(resources,
- &link->number_of_interrupts, link->interrupts);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't get possible IRQs from interrupt link %s - %s\n",
- acpi_name(handle), AcpiFormatException(error)));
- goto out;
+ /* Verify initial IRQs if we have _PRS. */
+ if (status != AE_NOT_FOUND)
+ for (i = 0; i < sc->pl_num_links; i++)
+ if (!link_valid_irq(&sc->pl_links[i],
+ sc->pl_links[i].l_irq))
+ sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+ if (bootverbose) {
+ device_printf(dev, "Links after initial validation:\n");
+ acpi_pci_link_dump(sc);
}
- if (link->number_of_interrupts == 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "interrupt link device _PRS data is corrupted - %s\n",
- acpi_name(handle)));
- error = AE_NULL_ENTRY;
- goto out;
- }
+ /* Save initial IRQs. */
+ for (i = 0; i < sc->pl_num_links; i++)
+ sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;
/*
* Try to disable this link. If successful, set the current IRQ to
* zero and flags to indicate this link is not routed. If we can't
* run _DIS (i.e., the method doesn't exist), assume the initial
* IRQ was routed by the BIOS.
- *
- * XXX Since we detect link devices via _PRT entries but run long
- * after APIC mode has been enabled, we don't get a chance to
- * disable links that will be unused (especially in APIC mode).
- * Leaving them enabled can cause duplicate interrupts for some
- * devices. The right fix is to probe links via their PNPID, so we
- * see them no matter what the _PRT says.
*/
- if (ACPI_SUCCESS(AcpiEvaluateObject(handle, "_DIS", NULL, NULL))) {
- link->current_irq = 0;
- link->flags = ACPI_LINK_NONE;
- } else
- link->flags = ACPI_LINK_ROUTED;
-
- /*
- * If the initial IRQ is invalid (not in _PRS), set it to 0 and
- * mark this link as not routed. We won't use it as the preferred
- * interrupt later when we route.
- */
- if (!acpi_pci_link_is_valid_irq(link, link->initial_irq) &&
- link->initial_irq != 0) {
- printf("ACPI link %s has invalid initial irq %d, ignoring\n",
- acpi_name(handle), link->initial_irq);
- link->initial_irq = 0;
- link->flags = ACPI_LINK_NONE;
+ if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL,
+ NULL)))
+ for (i = 0; i < sc->pl_num_links; i++)
+ sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
+ else
+ for (i = 0; i < sc->pl_num_links; i++)
+ if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
+ sc->pl_links[i].l_routed = 1;
+ if (bootverbose) {
+ device_printf(dev, "Links after disable:\n");
+ acpi_pci_link_dump(sc);
}
-
- link->references++;
-
- TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
- entry->pci_link = link;
-
- error = AE_OK;
-out:
- if (buf.Pointer != NULL)
- AcpiOsFree(buf.Pointer);
- if (error != AE_OK && link != NULL)
- AcpiOsFree(link);
-
- return_ACPI_STATUS (error);
+ ACPI_SERIAL_END(pci_link);
+ return (0);
+fail:
+ ACPI_SERIAL_END(pci_link);
+ for (i = 0; i < sc->pl_num_links; i++)
+ if (sc->pl_links[i].l_irqs != NULL)
+ free(sc->pl_links[i].l_irqs, M_PCI_LINK);
+ free(sc->pl_links, M_PCI_LINK);
+ return (ENXIO);
}
-static ACPI_STATUS
-acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
-{
- ACPI_HANDLE handle;
- ACPI_STATUS error;
- UINT32 sta;
- struct acpi_prt_entry *entry;
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
- ACPI_SERIAL_ASSERT(pci_link);
-
- if (prt == NULL) {
- device_printf(pcidev, "NULL PRT entry\n");
- return_ACPI_STATUS (AE_BAD_PARAMETER);
- }
-
- /* Bail out if attempting to add a duplicate PRT entry. */
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- if (entry->busno == busno &&
- entry->prt.Address == prt->Address &&
- entry->prt.Pin == prt->Pin) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "PRT entry already exists\n"));
- return_ACPI_STATUS (AE_ALREADY_EXISTS);
- }
- }
-
- /* Allocate and initialize our new PRT entry. */
- entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
- if (entry == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "can't allocate memory\n"));
- return_ACPI_STATUS (AE_NO_MEMORY);
- }
- bzero(entry, sizeof(struct acpi_prt_entry));
-
- /*
- * If the source link is NULL, then this IRQ is hardwired so skip
- * initializing the link but still add it to the list.
- */
- if (prt->Source[0] != '\0') {
- /* Get a handle for the link source. */
- error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source,
- &handle);
- if (ACPI_FAILURE(error)) {
- device_printf(pcidev, "get handle for %s - %s\n",
- prt->Source, AcpiFormatException(error));
- goto out;
- }
-
- error = acpi_pci_link_get_object_status(handle, &sta);
- if (ACPI_FAILURE(error)) {
- device_printf(pcidev, "can't get status for %s - %s\n",
- acpi_name(handle), AcpiFormatException(error));
- goto out;
- }
+/* XXX: Note that this is identical to pci_pir_search_irq(). */
+static uint8_t
+acpi_pci_link_search_irq(int bus, int device, int pin)
+{
+ uint32_t value;
+ uint8_t func, maxfunc;
+
+ /* See if we have a valid device at function 0. */
+ value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
+ if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
+ return (PCI_INVALID_IRQ);
+ if (value & PCIM_MFDEV)
+ maxfunc = PCI_FUNCMAX;
+ else
+ maxfunc = 0;
+
+ /* Scan all possible functions at this device. */
+ for (func = 0; func <= maxfunc; func++) {
+ value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
+ if (value == 0xffffffff)
+ continue;
+ value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
- /* Probe/initialize the link. */
- error = acpi_pci_link_add_link(handle, entry);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "couldn't add _PRT entry to link %s - %s\n",
- acpi_name(handle), AcpiFormatException(error)));
- goto out;
- }
+ /*
+ * See if it uses the pin in question. Note that the passed
+ * in pin uses 0 for A, .. 3 for D whereas the intpin
+ * register uses 0 for no interrupt, 1 for A, .. 4 for D.
+ */
+ if (value != pin + 1)
+ continue;
+ value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
+ if (bootverbose)
+ printf(
+ "ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n",
+ bus, device, pin + 'A', func, value);
+ if (value != PCI_INVALID_IRQ)
+ return (value);
}
-
- entry->pcidev = pcidev;
- entry->busno = busno;
- bcopy(prt, &entry->prt, sizeof(entry->prt));
-
- /*
- * Make sure the Source value is null-terminated. It is really a
- * variable-length string (with a fixed size in the struct) so when
- * we copy the entire struct, we truncate the string. Instead of
- * trying to make a variable-sized PRT object to handle the string,
- * we store its handle in prt_source. Callers should use that to
- * look up the link object.
- */
- entry->prt.Source[sizeof(prt->Source) - 1] = '\0';
- entry->prt_source = handle;
-
- TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
- error = AE_OK;
-
-out:
- if (error != AE_OK && entry != NULL)
- AcpiOsFree(entry);
-
- return_ACPI_STATUS (error);
+ return (PCI_INVALID_IRQ);
}
-/*
- * Look up the given interrupt in the list of possible settings for
- * this link. We don't special-case the initial link setting. Some
- * systems return current settings that are outside the list of valid
- * settings so only allow choices explicitly specified in _PRS.
- */
-static int
-acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+void
+acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
+ int pin)
{
- UINT8 i;
+ struct acpi_pci_link_softc *sc;
+ struct link *link;
+ uint8_t bios_irq;
- if (irq == 0)
- return (FALSE);
-
- /*
- * Some systems have the initial irq set to the SCI but don't list
- * it in the valid IRQs. Add a special case to allow routing to the
- * SCI if the system really wants to. This is similar to how
- * Windows often stacks all PCI IRQs on the SCI (and this is vital
- * on some systems.)
- */
- if (irq == AcpiGbl_FADT->SciInt)
- return (TRUE);
-
- for (i = 0; i < link->number_of_interrupts; i++) {
- if (link->interrupts[i] == irq)
- return (TRUE);
+ /* Bump the reference count. */
+ ACPI_SERIAL_BEGIN(pci_link);
+ sc = device_get_softc(dev);
+ KASSERT(index >= 0 && index < sc->pl_num_links,
+ ("%s: invalid index %d", __func__, index));
+ link = &sc->pl_links[index];
+ link->l_references++;
+ if (link->l_routed)
+ pci_link_interrupt_weights[link->l_irq]++;
+
+ /* Try to find a BIOS IRQ setting from any matching devices. */
+ bios_irq = acpi_pci_link_search_irq(pcib_get_bus(pcib), slot, pin);
+ if (!PCI_INTERRUPT_VALID(bios_irq)) {
+ ACPI_SERIAL_END(pci_link);
+ return;
}
- return (FALSE);
+ /* Validate the BIOS IRQ. */
+ if (!link_valid_irq(link, bios_irq)) {
+ device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
+ bios_irq, pcib_get_bus(pcib), slot, pin + 'A');
+ } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
+ link->l_bios_irq = bios_irq;
+ if (bios_irq < NUM_ISA_INTERRUPTS)
+ pci_link_bios_isa_irqs |= (1 << bios_irq);
+ if (bios_irq != link->l_initial_irq &&
+ PCI_INTERRUPT_VALID(link->l_initial_irq))
+ device_printf(dev,
+ "BIOS IRQ %u does not match initial IRQ %u\n",
+ bios_irq, link->l_initial_irq);
+ } else if (bios_irq != link->l_bios_irq)
+ device_printf(dev,
+ "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
+ bios_irq, pcib_get_bus(pcib), slot, pin + 'A',
+ link->l_bios_irq);
+ ACPI_SERIAL_END(pci_link);
}
static ACPI_STATUS
-acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
+acpi_pci_link_route_irqs(device_t dev)
{
- ACPI_STATUS error;
- ACPI_RESOURCE resbuf;
- ACPI_BUFFER crsbuf;
+ struct acpi_pci_link_softc *sc;
+ ACPI_RESOURCE *resource, *end, newres, *resptr;
+ ACPI_BUFFER crsbuf, srsbuf;
+ ACPI_STATUS status;
+ struct link *link;
+ int i;
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ /* Fetch the _CRS. */
ACPI_SERIAL_ASSERT(pci_link);
-
- /* Make sure the new IRQ is valid before routing. */
- if (!acpi_pci_link_is_valid_irq(link, irq)) {
- printf("acpi link set: invalid IRQ %d on %s\n",
- irq, acpi_name(link->handle));
- return_ACPI_STATUS (AE_BAD_PARAMETER);
- }
-
- /* If this this link has already been routed, just return. */
- if (link->flags & ACPI_LINK_ROUTED) {
- printf("acpi link set: %s already routed to %d\n",
- acpi_name(link->handle), link->current_irq);
- return_ACPI_STATUS (AE_OK);
- }
-
- /* Set up the IRQ resource for _SRS. */
- bzero(&resbuf, sizeof(resbuf));
+ sc = device_get_softc(dev);
crsbuf.Pointer = NULL;
-
- switch (link->possible_resources.Id) {
- case ACPI_RSTYPE_IRQ:
- resbuf.Id = ACPI_RSTYPE_IRQ;
- resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
-
- /* structure copy other fields */
- resbuf.Data.Irq = link->possible_resources.Data.Irq;
- resbuf.Data.Irq.NumberOfInterrupts = 1;
- resbuf.Data.Irq.Interrupts[0] = irq;
- break;
- case ACPI_RSTYPE_EXT_IRQ:
- resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
- resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
-
- /* structure copy other fields */
- resbuf.Data.ExtendedIrq =
- link->possible_resources.Data.ExtendedIrq;
- resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
- resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
- break;
- default:
- printf("acpi link set: %s resource is not an IRQ (%d)\n",
- acpi_name(link->handle), link->possible_resources.Id);
- return_ACPI_STATUS (AE_TYPE);
- }
-
- error = acpi_AppendBufferResource(&crsbuf, &resbuf);
- if (ACPI_FAILURE(error)) {
- printf("acpi link set: AppendBuffer failed for %s\n",
- acpi_name(link->handle));
- return_ACPI_STATUS (error);
- }
- if (crsbuf.Pointer == NULL) {
- printf("acpi link set: AppendBuffer returned empty for %s\n",
- acpi_name(link->handle));
- return_ACPI_STATUS (AE_NO_MEMORY);
+ crsbuf.Length = ACPI_ALLOCATE_BUFFER;
+ status = AcpiGetCurrentResources(acpi_get_handle(dev), &crsbuf);
+ if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL)
+ status = AE_NO_MEMORY;
+ if (ACPI_FAILURE(status)) {
+ if (bootverbose)
+ device_printf(dev,
+ "Unable to fetch current resources: %s\n",
+ AcpiFormatException(status));
+ return (status);
+ }
+
+ /* Fill in IRQ resources via link structures. */
+ srsbuf.Pointer = NULL;
+ link = sc->pl_links;
+ i = 0;
+ resource = (ACPI_RESOURCE *)crsbuf.Pointer;
+ end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length);
+ for (;;) {
+ switch (resource->Id) {
+ case ACPI_RSTYPE_IRQ:
+ MPASS(i < sc->pl_num_links);
+ MPASS(link->l_prs_template.Id == ACPI_RSTYPE_IRQ);
+ newres = link->l_prs_template;
+ resptr = &newres;
+ resptr->Data.Irq.NumberOfInterrupts = 1;
+ if (PCI_INTERRUPT_VALID(link->l_irq))
+ resptr->Data.Irq.Interrupts[0] = link->l_irq;
+ else
+ resptr->Data.Irq.Interrupts[0] = 0;
+ break;
+ case ACPI_RSTYPE_EXT_IRQ:
+ MPASS(i < sc->pl_num_links);
+ MPASS(link->l_prs_template.Id == ACPI_RSTYPE_EXT_IRQ);
+ newres = link->l_prs_template;
+ resptr = &newres;
+ resptr->Data.ExtendedIrq.NumberOfInterrupts = 1;
+ if (PCI_INTERRUPT_VALID(link->l_irq))
+ resource->Data.ExtendedIrq.Interrupts[0] =
+ link->l_irq;
+ else
+ resource->Data.ExtendedIrq.Interrupts[0] = 0;
+ break;
+ default:
+ resptr = resource;
+ }
+ status = acpi_AppendBufferResource(&srsbuf, resptr);
+ if (ACPI_FAILURE(status)) {
+ device_printf(dev, "Unable to build reousrces: %s\n",
+ AcpiFormatException(status));
+ if (srsbuf.Pointer != NULL)
+ AcpiOsFree(srsbuf.Pointer);
+ AcpiOsFree(crsbuf.Pointer);
+ return (status);
+ }
+ if (resource->Id == ACPI_RSTYPE_END_TAG)
+ break;
+ resource = ACPI_NEXT_RESOURCE(resource);
+ link++;
+ i++;
+ if (resource >= end)
+ break;
}
- /* Make the new IRQ active via the link's _SRS method. */
- error = AcpiSetCurrentResources(link->handle, &crsbuf);
- if (ACPI_FAILURE(error)) {
- printf("acpi link set: _SRS failed for link %s - %s\n",
- acpi_name(link->handle), AcpiFormatException(error));
- goto out;
+ /* Write out new resources via _SRS. */
+ status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf);
+ if (ACPI_FAILURE(status)) {
+ device_printf(dev, "Unable to route IRQs: %s\n",
+ AcpiFormatException(status));
+ AcpiOsFree(crsbuf.Pointer);
+ AcpiOsFree(srsbuf.Pointer);
+ return (status);
}
- link->flags |= ACPI_LINK_ROUTED;
- link->current_irq = 0;
+ AcpiOsFree(crsbuf.Pointer);
/*
- * Many systems always return invalid values for current settings
- * (_CRS). Since we can't trust the value returned, we have to
- * assume we were successful.
+ * Perform acpi_config_intr() on each IRQ resource if it was just
+ * routed for the first time.
*/
- error = acpi_pci_link_get_current_irq(link, &link->current_irq);
- if (ACPI_FAILURE(error)) {
- if (bootverbose)
- printf("acpi link set: _CRS failed for link %s - %s\n",
- acpi_name(link->handle),
- AcpiFormatException(error));
- error = AE_OK;
- }
- if (link->current_irq != irq) {
- if (bootverbose)
- printf("acpi link set: curr irq %d != %d for %s\n",
- link->current_irq, irq, acpi_name(link->handle));
- link->current_irq = irq;
- }
-
-out:
- if (crsbuf.Pointer)
- AcpiOsFree(crsbuf.Pointer);
- return_ACPI_STATUS (error);
-}
-
-/*
- * Auto arbitration for boot-disabled devices
- */
-
-static void
-acpi_pci_link_bootdisabled_dump(void)
-{
- int i;
- int irq;
- struct acpi_pci_link_entry *link;
-
- ACPI_SERIAL_ASSERT(pci_link);
- TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
- /* boot-disabled link only. */
- if (link->current_irq != 0)
+ link = sc->pl_links;
+ i = 0;
+ resource = (ACPI_RESOURCE *)srsbuf.Pointer;
+ for (;;) {
+ if (resource->Id == ACPI_RSTYPE_END_TAG)
+ break;
+ MPASS(i < sc->pl_num_links);
+ if (link->l_routed || !PCI_INTERRUPT_VALID(link->l_irq))
continue;
-
- printf("%s (references %d, priority %d):\n",
- acpi_name(link->handle), link->references, link->priority);
- printf("\tinterrupts:\t");
- for (i = 0; i < link->number_of_interrupts; i++) {
- irq = link->sorted_irq[i];
- printf("%6d", irq);
- }
- printf("\n");
- printf("\tpenalty:\t");
- for (i = 0; i < link->number_of_interrupts; i++) {
- irq = link->sorted_irq[i];
- printf("%6d", irq_penalty[irq]);
+ switch (resource->Id) {
+ case ACPI_RSTYPE_IRQ:
+ case ACPI_RSTYPE_EXT_IRQ:
+ link->l_routed = 1;
+ acpi_config_intr(dev, resource);
+ pci_link_interrupt_weights[link->l_irq] +=
+ link->l_references;
+ break;
}
- printf("\n");
+ resource = ACPI_NEXT_RESOURCE(resource);
+ link++;
+ i++;
+ if (resource >= end)
+ break;
}
-}
-
-/*
- * Heuristics for choosing IRQs. We start with some static penalties,
- * update them based on what IRQs are currently in use, then sort the
- * result. This works ok but is not perfect.
- *
- * The PCI BIOS $PIR table offers "preferred PCI interrupts", but ACPI
- * doesn't seem to offer a similar mechanism, so picking a good
- * interrupt here is a difficult task.
- */
-static void
-acpi_pci_link_init_irq_penalty(void)
-{
-
- bzero(irq_penalty, sizeof(irq_penalty));
-
- /* 0, 1, 2, 8: timer, keyboard, cascade, RTC */
- irq_penalty[0] = 100000;
- irq_penalty[1] = 100000;
- irq_penalty[2] = 100000;
- irq_penalty[8] = 100000;
-
- /* 13, 14, 15: npx, ATA controllers */
- irq_penalty[13] = 50000;
- irq_penalty[14] = 50000;
- irq_penalty[15] = 50000;
-
- /* 3, 4, 6, 7, 12: typically used by legacy hardware */
- irq_penalty[3] = 5000;
- irq_penalty[4] = 5000;
- irq_penalty[6] = 5000;
- irq_penalty[7] = 5000;
- irq_penalty[12] = 5000;
-
- /* 5: sometimes legacy sound cards */
- irq_penalty[5] = 50;
+ AcpiOsFree(srsbuf.Pointer);
+ return (AE_OK);
}
static int
-link_exclusive(ACPI_RESOURCE *res)
+acpi_pci_link_resume(device_t dev)
{
+ ACPI_STATUS status;
- if (res == NULL ||
- (res->Id != ACPI_RSTYPE_IRQ &&
- res->Id != ACPI_RSTYPE_EXT_IRQ))
- return (FALSE);
-
- if ((res->Id == ACPI_RSTYPE_IRQ &&
- res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) ||
- (res->Id == ACPI_RSTYPE_EXT_IRQ &&
- res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE))
- return (TRUE);
-
- return (FALSE);
+ ACPI_SERIAL_BEGIN(pci_link);
+ status = acpi_pci_link_route_irqs(dev);
+ ACPI_SERIAL_END(pci_link);
+ if (ACPI_FAILURE(status))
+ return (ENXIO);
+ else
+ return (0);
}
-static void
-acpi_pci_link_update_irq_penalty(device_t dev, int busno)
+/*
+ * Pick an IRQ to use for this unrouted link.
+ */
+static uint8_t
+acpi_pci_link_choose_irq(device_t dev, struct link *link)
{
- int i;
- int irq;
- int rid;
- struct resource *res;
- struct acpi_prt_entry *entry;
- struct acpi_pci_link_entry *link;
-
- ACPI_SERIAL_ASSERT(pci_link);
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- if (entry->busno != busno)
- continue;
-
- /* Impossible? */
- link = entry->pci_link;
- if (link == NULL)
- continue;
-
- /* Update penalties for all possible settings of this link. */
- for (i = 0; i < link->number_of_interrupts; i++) {
- /* give 10 for each possible IRQs. */
- irq = link->interrupts[i];
- irq_penalty[irq] += 10;
-
- /* higher penalty if exclusive. */
- if (link_exclusive(&link->possible_resources))
- irq_penalty[irq] += 100;
-
- /* XXX try to get this IRQ in non-sharable mode. */
- rid = 0;
- res = bus_alloc_resource(dev, SYS_RES_IRQ,
- &rid, irq, irq, 1, 0);
- if (res != NULL) {
- bus_release_resource(dev, SYS_RES_IRQ,
- rid, res);
- } else {
- /* this is in use, give 10. */
- irq_penalty[irq] += 10;
- }
- }
-
- /* initialize `sorted' possible IRQs. */
- bcopy(link->interrupts, link->sorted_irq,
- sizeof(link->sorted_irq));
+ char tunable_buffer[64], link_name[5];
+ u_int8_t best_irq, pos_irq;
+ int best_weight, pos_weight, i;
+
+ KASSERT(link->l_routed == 0, ("%s: link already routed", __func__));
+ KASSERT(!PCI_INTERRUPT_VALID(link->l_irq),
+ ("%s: link already has an IRQ", __func__));
+
+ /* Check for a tunable override and use it if it is valid. */
+ if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), link_name,
+ sizeof(link_name)))) {
+ snprintf(tunable_buffer, sizeof(tunable_buffer),
+ "hw.pci.link.%s.%d.irq", link_name, link->l_res_index);
+ if (getenv_int(tunable_buffer, &i) &&
+ PCI_INTERRUPT_VALID(i) && link_valid_irq(link, i))
+ return (i);
+ snprintf(tunable_buffer, sizeof(tunable_buffer),
+ "hw.pci.link.%s.irq", link_name);
+ if (getenv_int(tunable_buffer, &i) &&
+ PCI_INTERRUPT_VALID(i) && link_valid_irq(link, i))
+ return (i);
}
-}
-static void
-acpi_pci_link_set_bootdisabled_priority(void)
-{
- int sum_penalty;
- int i;
- int irq;
- struct acpi_pci_link_entry *link, *link_pri;
- TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
-
- ACPI_SERIAL_ASSERT(pci_link);
+ /*
+ * If we have a valid BIOS IRQ, use that. We trust what the BIOS
+ * says it routed over what _CRS says the link thinks is routed.
+ */
+ if (PCI_INTERRUPT_VALID(link->l_bios_irq))
+ return (link->l_bios_irq);
- /* reset priority for all links. */
- TAILQ_FOREACH(link, &acpi_pci_link_entries, links)
- link->priority = 0;
+ /*
+ * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS,
+ * then use that.
+ */
+ if (PCI_INTERRUPT_VALID(link->l_initial_irq))
+ return (link->l_initial_irq);
- TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
- /* If already routed, don't include in arbitration. */
- if (link->flags & ACPI_LINK_ROUTED) {
- link->priority = 0;
+ /*
+ * Ok, we have no useful hints, so we have to pick from the
+ * possible IRQs. For ISA IRQs we only use interrupts that
+ * have already been used by the BIOS.
+ */
+ best_irq = PCI_INVALID_IRQ;
+ best_weight = INT_MAX;
+ for (i = 0; i < link->l_num_irqs; i++) {
+ pos_irq = link->l_irqs[i];
+ if (pos_irq < NUM_ISA_INTERRUPTS &&
+ (pci_link_bios_isa_irqs & 1 << pos_irq) == 0)
continue;
+ pos_weight = pci_link_interrupt_weights[pos_irq];
+ if (pos_weight < best_weight) {
+ best_weight = pos_weight;
+ best_irq = pos_irq;
}
-
- /*
- * Calculate the priority for each boot-disabled links.
- * o IRQ penalty indicates difficulty to use.
- * o #references for devices indicates importance of the link.
- * o #interrupts indicates flexibility of the link.
- */
- sum_penalty = 0;
- for (i = 0; i < link->number_of_interrupts; i++) {
- irq = link->interrupts[i];
- sum_penalty += irq_penalty[irq];
- }
-
- link->priority = (sum_penalty * link->references) /
- link->number_of_interrupts;
}
/*
- * Sort PCI links based on the priority.
- * XXX Any other better ways rather than using work list?
+ * If this is an ISA IRQ, try using the SCI if it is also an ISA
+ * interrupt as a fallback.
*/
- TAILQ_INIT(&sorted_list);
- while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
- link = TAILQ_FIRST(&acpi_pci_link_entries);
- /* find an entry which has the highest priority. */
- TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links)
- if (link->priority < link_pri->priority)
- link = link_pri;
-
- /* move to work list. */
- TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
- TAILQ_INSERT_TAIL(&sorted_list, link, links);
- }
-
- while (!TAILQ_EMPTY(&sorted_list)) {
- /* move them back to the list, one by one... */
- link = TAILQ_FIRST(&sorted_list);
- TAILQ_REMOVE(&sorted_list, link, links);
- TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
- }
-}
-
-static void
-acpi_pci_link_fixup_bootdisabled_link(void)
-{
- int i, j;
- int irq1, irq2;
- struct acpi_pci_link_entry *link;
-
- ACPI_SERIAL_ASSERT(pci_link);
-
- TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
- /* Ignore links that have been routed already. */
- if (link->flags & ACPI_LINK_ROUTED)
- continue;
-
- /* sort IRQs based on their penalty descending. */
- for (i = 0; i < link->number_of_interrupts; i++) {
- irq1 = link->sorted_irq[i];
- for (j = i + 1; j < link->number_of_interrupts; j++) {
- irq2 = link->sorted_irq[j];
- if (irq_penalty[irq1] < irq_penalty[irq2]) {
- continue;
- }
- link->sorted_irq[i] = irq2;
- link->sorted_irq[j] = irq1;
- irq1 = irq2;
- }
+ if (link->l_isa_irq) {
+ pos_irq = AcpiGbl_FADT->SciInt;
+ pos_weight = pci_link_interrupt_weights[pos_irq];
+ if (pos_weight < best_weight) {
+ best_weight = pos_weight;
+ best_irq = pos_irq;
}
}
-
+
if (bootverbose) {
- printf("ACPI PCI link arbitrated settings:\n");
- acpi_pci_link_bootdisabled_dump();
- }
+ if (PCI_INTERRUPT_VALID(best_irq))
+ device_printf(dev, "Picked IRQ %u with weight %d\n",
+ best_irq, best_weight);
+ } else
+ device_printf(dev, "Unable to choose an IRQ\n");
+ return (best_irq);
}
-/*
- * Public interface
- */
-
int
-acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
+acpi_pci_link_route_interrupt(device_t dev, int index)
{
- struct acpi_prt_entry *entry;
- ACPI_PCI_ROUTING_TABLE *prt;
- u_int8_t *prtp;
- ACPI_STATUS error;
- int ret;
- static int first_time = 1;
+ struct acpi_pci_link_softc *sc;
+ struct link *link;
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
- if (acpi_disabled("pci_link"))
- return (0);
-
- ret = -1;
ACPI_SERIAL_BEGIN(pci_link);
- if (first_time) {
- TAILQ_INIT(&acpi_prt_entries);
- TAILQ_INIT(&acpi_pci_link_entries);
- acpi_pci_link_init_irq_penalty();
- first_time = 0;
- }
-
- if (prtbuf == NULL)
- goto out;
+ sc = device_get_softc(dev);
+ KASSERT(index >= 0 && index < sc->pl_num_links,
+ ("%s: invalid index %d", __func__, index));
+ link = &sc->pl_links[index];
- prtp = prtbuf->Pointer;
- if (prtp == NULL) /* didn't get routing table */
- goto out;
-
- /* scan the PCI Routing Table */
- for (;;) {
- prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
-
- if (prt->Length == 0) /* end of table */
- break;
-
- error = acpi_pci_link_add_prt(dev, prt, busno);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't add PCI interrupt link entry - %s\n",
- AcpiFormatException(error)));
- }
-
- /* skip to next entry */
- prtp += prt->Length;
- }
-
- if (bootverbose) {
- printf("ACPI PCI link initial configuration:\n");
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- if (entry->busno != busno)
- continue;
- acpi_pci_link_entry_dump(entry);
- }
+ /*
+ * If this link device is already routed to an interrupt, just return
+ * the interrupt it is routed to.
+ */
+ if (link->l_routed) {
+ KASSERT(PCI_INTERRUPT_VALID(link->l_irq),
+ ("%s: link is routed but has an invalid IRQ", __func__));
+ ACPI_SERIAL_END(pci_link);
+ return (link->l_irq);
}
- /* manual configuration. */
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- int irq;
- char prthint[32];
-
- if (entry->busno != busno)
- continue;
-
- snprintf(prthint, sizeof(prthint),
- "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
- (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)),
- (int)entry->prt.Pin);
-
- if (getenv_int(prthint, &irq) == 0)
- continue;
-
- if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
- error = acpi_pci_link_set_irq(entry->pci_link, irq);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't set IRQ to link entry %s - %s\n",
- acpi_name(entry->pci_link->handle),
- AcpiFormatException(error)));
- }
- continue;
- }
+ /* Choose an IRQ if we need one. */
+ if (!PCI_INTERRUPT_VALID(link->l_irq)) {
+ link->l_irq = acpi_pci_link_choose_irq(dev, link);
/*
- * Do auto arbitration for this device's PCI link
- * if hint value 0 is specified.
+ * Try to route the interrupt we picked. If it fails, then
+ * assume the interrupt is not routed.
*/
- if (irq == 0)
- entry->pci_link->current_irq = 0;
- }
- ret = 0;
-
-out:
- ACPI_SERIAL_END(pci_link);
- return (ret);
-}
-
-int
-acpi_pci_link_resume(device_t dev)
-{
- struct acpi_prt_entry *entry;
- struct acpi_pci_link_entry *link;
- ACPI_STATUS error;
-
- ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
-
- if (acpi_disabled("pci_link"))
- return (0);
-
- /* Walk through all PRT entries for this PCI bridge. */
- ACPI_SERIAL_BEGIN(pci_link);
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- if (entry->pcidev != dev || entry->pci_link == NULL)
- continue;
- link = entry->pci_link;
-
- /* If it's not routed, skip re-programming. */
- if ((link->flags & ACPI_LINK_ROUTED) == 0)
- continue;
- link->flags &= ~ACPI_LINK_ROUTED;
-
- /* Program it to the same setting as before suspend. */
- error = acpi_pci_link_set_irq(link, link->current_irq);
- if (ACPI_FAILURE(error)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "couldn't set IRQ to link entry %s - %s\n",
- acpi_name(link->handle),
- AcpiFormatException(error)));
+ if (PCI_INTERRUPT_VALID(link->l_irq)) {
+ acpi_pci_link_route_irqs(dev);
+ if (!link->l_routed)
+ link->l_irq = PCI_INVALID_IRQ;
}
}
ACPI_SERIAL_END(pci_link);
- return (0);
+ return (link->l_irq);
}
/*
- * Look up a PRT entry for the given device. We match based on the slot
- * number (high word of Address) and pin number (note that ACPI uses 0
- * for INTA).
- *
- * Note that the low word of the Address field (function number) is
- * required by the specification to be 0xffff. We don't risk checking
- * it here.
+ * This is gross, but we abuse the identify routine to perform one-time
+ * SYSINIT() style initialization for the driver.
*/
-struct acpi_prt_entry *
-acpi_pci_find_prt(device_t pcibdev, device_t dev, int pin)
+static void
+acpi_pci_link_identify(driver_t *driver, device_t parent)
{
- struct acpi_prt_entry *entry;
- ACPI_PCI_ROUTING_TABLE *prt;
- ACPI_SERIAL_BEGIN(pci_link);
- TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
- prt = &entry->prt;
- if (entry->busno == pci_get_bus(dev) &&
- ACPI_ADR_PCI_SLOT(prt->Address) == pci_get_slot(dev) &&
- prt->Pin == pin)
- break;
- }
- ACPI_SERIAL_END(pci_link);
- return (entry);
+ /*
+ * If the SCI is an ISA IRQ, add it to the bitmask of known good
+ * ISA IRQs.
+ *
+ * XXX: If we are using the APIC, the SCI might have been
+ * rerouted to an APIC pin in which case this is invalid. However,
+ * if we are using the APIC, we also shouldn't be having any PCI
+ * interrupts routed via ISA IRQs, so this is probably ok.
+ */
+ if (AcpiGbl_FADT->SciInt < NUM_ISA_INTERRUPTS)
+ pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT->SciInt);
}
-/*
- * Perform the actual programming for this link. We attempt to route an
- * IRQ, first the one set by the BIOS, and then a priority-sorted list.
- * Only do the programming once per link.
- */
-int
-acpi_pci_link_route(device_t dev, struct acpi_prt_entry *prt)
-{
- struct acpi_pci_link_entry *link;
- int busno, i, irq;
- ACPI_RESOURCE crsres;
- ACPI_STATUS status;
-
- busno = pci_get_bus(dev);
- link = prt->pci_link;
- irq = PCI_INVALID_IRQ;
- ACPI_SERIAL_BEGIN(pci_link);
- if (link == NULL || link->number_of_interrupts == 0)
- goto out;
-
- /* If already routed, just return the current setting. */
- if (link->flags & ACPI_LINK_ROUTED) {
- irq = link->current_irq;
- goto out;
- }
+static device_method_t acpi_pci_link_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, acpi_pci_link_identify),
+ DEVMETHOD(device_probe, acpi_pci_link_probe),
+ DEVMETHOD(device_attach, acpi_pci_link_attach),
+ DEVMETHOD(device_resume, acpi_pci_link_resume),
- /* Update all IRQ weights to determine our priority list. */
- acpi_pci_link_update_irq_penalty(prt->pcidev, busno);
- acpi_pci_link_set_bootdisabled_priority();
- acpi_pci_link_fixup_bootdisabled_link();
+ {0, 0}
+};
- /*
- * First, attempt to route the initial IRQ, if valid, since it was
- * the one set up by the BIOS. If this fails, route according to
- * our priority-sorted list of IRQs.
- */
- status = AE_NOT_FOUND;
- irq = link->initial_irq;
- if (irq)
- status = acpi_pci_link_set_irq(link, irq);
- for (i = 0; ACPI_FAILURE(status) && i < link->number_of_interrupts;
- i++) {
- irq = link->sorted_irq[i];
- status = acpi_pci_link_set_irq(link, irq);
- if (ACPI_FAILURE(status)) {
- device_printf(dev, "_SRS failed, irq %d via %s\n",
- irq, acpi_name(link->handle));
- }
- }
- if (ACPI_FAILURE(status)) {
- irq = PCI_INVALID_IRQ;
- goto out;
- }
+static driver_t acpi_pci_link_driver = {
+ "pci_link",
+ acpi_pci_link_methods,
+ sizeof(struct acpi_pci_link_softc),
+};
- /* Update the penalty now that there's another user for this IRQ. */
- irq_penalty[irq] += 10 * link->references;
-
- /* Configure trigger/polarity for the new IRQ. */
- bcopy(&link->possible_resources, &crsres, sizeof(crsres));
- if (crsres.Id == ACPI_RSTYPE_IRQ) {
- crsres.Data.Irq.NumberOfInterrupts = 1;
- crsres.Data.Irq.Interrupts[0] = irq;
- } else {
- crsres.Data.ExtendedIrq.NumberOfInterrupts = 1;
- crsres.Data.ExtendedIrq.Interrupts[0] = irq;
- }
- acpi_config_intr(dev, &crsres);
+static devclass_t pci_link_devclass;
-out:
- ACPI_SERIAL_END(pci_link);
- return (irq);
-}
+DRIVER_MODULE(acpi_pci_link, acpi, acpi_pci_link_driver, pci_link_devclass, 0,
+ 0);
+MODULE_DEPEND(acpi_pci_link, acpi, 1, 1, 1);
diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c
index 0a41ddc..51c3207 100644
--- a/sys/dev/acpica/acpi_pcib.c
+++ b/sys/dev/acpica/acpi_pcib.c
@@ -51,6 +51,73 @@ ACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods");
* For locking, we assume the caller is not concurrent since this is
* triggered by newbus methods.
*/
+
+struct prt_lookup_request {
+ ACPI_PCI_ROUTING_TABLE *pr_entry;
+ u_int pr_pin;
+ u_int pr_slot;
+};
+
+typedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
+
+static void prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
+static void prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg);
+static void prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler,
+ void *arg);
+
+static void
+prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg)
+{
+ ACPI_PCI_ROUTING_TABLE *entry;
+ char *prtptr;
+
+ /* First check to see if there is a table to walk. */
+ if (prt == NULL || prt->Pointer == NULL)
+ return;
+
+ /* Walk the table executing the handler function for each entry. */
+ prtptr = prt->Pointer;
+ entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
+ while (entry->Length != 0) {
+ handler(entry, arg);
+ prtptr += entry->Length;
+ entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
+ }
+}
+
+static void
+prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg)
+{
+ ACPI_HANDLE handle;
+ device_t child, pcib;
+ int error;
+
+ /* We only care about entries that reference a link device. */
+ if (entry->Source == NULL || entry->Source[0] == '\0')
+ return;
+
+ /* Lookup the associated handle and device. */
+ pcib = (device_t)arg;
+ if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(pcib), entry->Source,
+ &handle)))
+ return;
+ child = acpi_get_device(handle);
+ if (child == NULL)
+ return;
+
+ /* If the device hasn't been probed yet, force it to do so. */
+ error = device_probe_and_attach(child);
+ if (error != 0) {
+ device_printf((device_t)arg, "failed to force attach of %s\n",
+ acpi_name(handle));
+ return;
+ }
+
+ /* Add a reference for a specific bus/device/pin tuple. */
+ acpi_pci_link_add_reference(child, entry->SourceIndex, pcib,
+ ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin);
+}
+
int
acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno)
{
@@ -92,7 +159,7 @@ acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno)
/*
* Now go scan the bus.
*/
- acpi_pci_link_config(dev, prt, busno);
+ prt_walk_table(prt, prt_attach_devices, dev);
return_VALUE (bus_generic_attach(dev));
}
@@ -100,20 +167,43 @@ acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno)
int
acpi_pcib_resume(device_t dev)
{
- acpi_pci_link_resume(dev);
+
return (bus_generic_resume(dev));
}
+static void
+prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg)
+{
+ struct prt_lookup_request *pr;
+
+ pr = (struct prt_lookup_request *)arg;
+ if (pr->pr_entry != NULL)
+ return;
+
+ /*
+ * Compare the slot number (high word of Address) and pin number
+ * (note that ACPI uses 0 for INTA) to check for a match.
+ *
+ * Note that the low word of the Address field (function number)
+ * is required by the specification to be 0xffff. We don't risk
+ * checking it here.
+ */
+ if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot &&
+ entry->Pin == pr->pr_pin)
+ pr->pr_entry = entry;
+}
+
/*
* Route an interrupt for a child of the bridge.
*/
int
-acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
+acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
+ ACPI_BUFFER *prtbuf)
{
- struct acpi_prt_entry *entry;
- int i, interrupt;
- struct acpi_pci_link_entry *link;
- ACPI_PCI_ROUTING_TABLE *prt;
+ ACPI_PCI_ROUTING_TABLE *prt;
+ struct prt_lookup_request pr;
+ ACPI_HANDLE lnkdev;
+ int interrupt;
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -124,20 +214,20 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
ACPI_SERIAL_BEGIN(pcib);
- /* Look up the PRT entry for this device. */
- entry = acpi_pci_find_prt(pcib, dev, pin);
- if (entry == NULL) {
- device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev),
- pci_get_slot(dev), 'A' + pin);
- goto out;
- }
- prt = &entry->prt;
- link = entry->pci_link;
+ /* Search for a matching entry in the routing table. */
+ pr.pr_entry = NULL;
+ pr.pr_pin = pin;
+ pr.pr_slot = pci_get_slot(dev);
+ prt_walk_table(prtbuf, prt_lookup_device, &pr);
+ if (pr.pr_entry == NULL)
+ return (PCI_INVALID_IRQ);
+ prt = pr.pr_entry;
+
if (bootverbose) {
device_printf(pcib, "matched entry for %d.%d.INT%c",
pci_get_bus(dev), pci_get_slot(dev), 'A' + pin);
- if (prt->Source[0] != '\0')
- printf(" (src %s)", acpi_name(entry->prt_source));
+ if (prt->Source != NULL && prt->Source[0] != '\0')
+ printf(" (src %s:%u)", prt->Source, prt->SourceIndex);
printf("\n");
}
@@ -156,48 +246,20 @@ acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
goto out;
}
- /* XXX Support for multiple resources must be added to the link code. */
- if (prt->SourceIndex) {
- device_printf(pcib, "src index %d not yet supported\n",
- prt->SourceIndex);
- goto out;
- }
-
- /* There has to be at least one interrupt available. */
- if (link->number_of_interrupts == 0) {
- device_printf(pcib, "device has no interrupts\n");
- goto out;
- }
-
- /*
- * If the current interrupt has been routed, we're done. This is the
- * case when the BIOS initializes it and we didn't disable it.
+ /*
+ * We have to find the source device (PCI interrupt link device).
*/
- if (link->flags & ACPI_LINK_ROUTED) {
- interrupt = link->current_irq;
- if (bootverbose)
- device_printf(pcib, "slot %d INT%c is already routed to irq %d\n",
- pci_get_slot(dev), 'A' + pin, interrupt);
+ if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
+ device_printf(pcib, "couldn't find PCI interrupt link device %s\n",
+ prt->Source);
goto out;
}
-
- if (bootverbose) {
- device_printf(pcib, "possible interrupts:");
- for (i = 0; i < link->number_of_interrupts; i++)
- printf("%3d", link->interrupts[i]);
- printf("\n");
- }
-
- /*
- * Perform the link routing. The link code will pick the best IRQ
- * for this pin and configure it.
- */
- interrupt = acpi_pci_link_route(dev, entry);
+ interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev),
+ prt->SourceIndex);
if (bootverbose && PCI_INTERRUPT_VALID(interrupt))
device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n",
- pci_get_slot(dev), 'A' + pin, interrupt,
- acpi_name(entry->prt_source));
+ pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev));
out:
ACPI_SERIAL_END(pcib);
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c
index 5614f6c..b1d14ab 100644
--- a/sys/dev/acpica/acpi_pcib_acpi.c
+++ b/sys/dev/acpica/acpi_pcib_acpi.c
@@ -297,8 +297,9 @@ acpi_pcib_write_config(device_t dev, int bus, int slot, int func, int reg,
static int
acpi_pcib_acpi_route_interrupt(device_t pcib, device_t dev, int pin)
{
+ struct acpi_hpcib_softc *sc = device_get_softc(pcib);
- return (acpi_pcib_route_interrupt(pcib, dev, pin));
+ return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt));
}
static u_long acpi_host_mem_start = 0x80000000;
diff --git a/sys/dev/acpica/acpi_pcib_pci.c b/sys/dev/acpica/acpi_pcib_pci.c
index 8686cf7..a4c587f 100644
--- a/sys/dev/acpica/acpi_pcib_pci.c
+++ b/sys/dev/acpica/acpi_pcib_pci.c
@@ -170,5 +170,5 @@ acpi_pcib_pci_route_interrupt(device_t pcib, device_t dev, int pin)
if (sc->ap_prt.Pointer == NULL)
return (pcib_route_interrupt(pcib, dev, pin));
else
- return (acpi_pcib_route_interrupt(pcib, dev, pin));
+ return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt));
}
diff --git a/sys/dev/acpica/acpi_pcibvar.h b/sys/dev/acpica/acpi_pcibvar.h
index 2c59fae..d90bd45 100644
--- a/sys/dev/acpica/acpi_pcibvar.h
+++ b/sys/dev/acpica/acpi_pcibvar.h
@@ -31,42 +31,16 @@
#define _ACPI_PCIBVAR_H_
int acpi_pcib_attach(device_t bus, ACPI_BUFFER *prt, int busno);
-int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin);
+int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
+ ACPI_BUFFER *prtbuf);
int acpi_pcib_resume(device_t dev);
#define MAX_POSSIBLE_INTERRUPTS 16
#define MAX_ISA_INTERRUPTS 16
#define MAX_ACPI_INTERRUPTS 255
-struct acpi_pci_link_entry {
- TAILQ_ENTRY(acpi_pci_link_entry) links;
- ACPI_HANDLE handle;
- UINT8 current_irq;
- UINT8 initial_irq;
- ACPI_RESOURCE possible_resources;
- UINT8 number_of_interrupts;
- UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];
- UINT8 sorted_irq[MAX_POSSIBLE_INTERRUPTS];
- int references;
- int priority;
- int flags;
-#define ACPI_LINK_NONE 0
-#define ACPI_LINK_ROUTED (1 << 0)
-};
-
-struct acpi_prt_entry {
- TAILQ_ENTRY(acpi_prt_entry) links;
- device_t pcidev;
- int busno;
- ACPI_PCI_ROUTING_TABLE prt;
- ACPI_HANDLE prt_source;
- struct acpi_pci_link_entry *pci_link;
-};
-
-int acpi_pci_link_config(device_t pcib, ACPI_BUFFER *prt, int busno);
-int acpi_pci_link_resume(device_t pcib);
-struct acpi_prt_entry *acpi_pci_find_prt(device_t pcibdev, device_t dev,
- int pin);
-int acpi_pci_link_route(device_t dev, struct acpi_prt_entry *prt);
+void acpi_pci_link_add_reference(device_t dev, int index, device_t pcib,
+ int slot, int pin);
+int acpi_pci_link_route_interrupt(device_t dev, int index);
#endif
OpenPOWER on IntegriCloud