#include #include #include #include #include #include #include "acpi.h" #include "acpi_bus.h" #define PREFIX "ACPI: " struct acpi_prt_entry { struct list_head list; ACPI_PCI_ID id; u8 pin; ACPI_HANDLE link; u32 index; /* GSI, or link _CRS index */ }; static LIST_HEAD(acpi_prt_list); static DEFINE_SPINLOCK(acpi_prt_lock); static inline char pin_name(int pin) { return 'A' + pin - 1; } static int acpi_pci_irq_add_entry(ACPI_HANDLE handle, struct pci_bus *bus, struct acpi_pci_routing_table *prt) { struct acpi_prt_entry *entry; entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) return -ENOMEM; /* * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert * it here. */ entry->id.Segment = pci_domain_nr(bus); entry->id.Bus = bus->number; entry->id.Device = (prt->Address >> 16) & 0xFFFF; entry->pin = prt->Pin + 1; // do_prt_fixups(entry, prt); entry->index = prt->SourceIndex; /* * Type 1: Dynamic * --------------- * The 'source' field specifies the PCI interrupt link device used to * configure the IRQ assigned to this slot|dev|pin. The 'source_index' * indicates which resource descriptor in the resource template (of * the link device) this interrupt is allocated from. * * NOTE: Don't query the Link Device for IRQ information at this time * because Link Device enumeration may not have occurred yet * (e.g. exists somewhere 'below' this _PRT entry in the ACPI * namespace). */ if (prt->Source[0]) AcpiGetHandle(handle, prt->Source, &entry->link); /* * Type 2: Static * -------------- * The 'source' field is NULL, and the 'source_index' field specifies * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ dbgprintf(PREFIX " %04x:%02x:%02x[%c] -> %s[%d]\n", entry->id.Segment, entry->id.Bus, entry->id.Device, pin_name(entry->pin), prt->Source, entry->index); spin_lock(&acpi_prt_lock); list_add_tail(&entry->list, &acpi_prt_list); spin_unlock(&acpi_prt_lock); return 0; } int acpi_pci_irq_add_prt(ACPI_HANDLE handle, struct pci_bus *bus) { ACPI_STATUS status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_pci_routing_table *entry; /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ status = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) return -ENODEV; printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", (char *) buffer.Pointer); kfree(buffer.Pointer); buffer.Length = ACPI_ALLOCATE_BUFFER; buffer.Pointer = NULL; status = AcpiGetIrqRoutingTable(handle, &buffer); if (ACPI_FAILURE(status)) { dbgprintf("AcpiGetIrqRoutingTable failed " "evaluating _PRT [%s]\n",AcpiFormatException(status)); kfree(buffer.Pointer); return -ENODEV; } entry = buffer.Pointer; while (entry && (entry->Length > 0)) { acpi_pci_irq_add_entry(handle, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->Length); } kfree(buffer.Pointer); return 0; }