kolibrios-gitea/drivers/devman/pci_irq.c

132 lines
3.7 KiB
C
Raw Normal View History

#include <ddk.h>
#include <linux/errno.h>
#include <mutex.h>
#include <linux/spinlock.h>
#include <pci.h>
#include <syscall.h>
#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;
}