Commit e7d76343 authored by Len Brown's avatar Len Brown

[ACPI] PCI IRQ update (Bjorn Helgaas)

http://bugme.osdl.org/show_bug.cgi?id=2574

mp_parse_prt() and iosapic_parse_prt() used to allocate all
IRQs, whether devices needed them or not.  Some devices
failed because the this method enabled unused PCI Interrupt
Link Devices, which disrupted active link devices.

Now the PRT knowledge is pulled out of the arch
code and the IRQ allocation and IO-APIC programming
is done by pci_enable_device().
This is also a step toward allowing the addition
of new root bridges and PRTs at run-time.

The architecture supplies

 unsigned int
 acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)

which is called by acpi_pci_irq_enable().  ACPI supplies
all the information from the PRT, and the arch sets up
the routing and returns the IRQ it allocated.
parent c72113b5
......@@ -437,6 +437,34 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
return 0;
}
#ifdef CONFIG_ACPI_PCI
unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
{
static u16 irq_mask;
unsigned int irq;
extern void eisa_set_level_irq(unsigned int irq);
/*
* Make sure all (legacy) PCI IRQs are set as level-triggered.
*/
if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
if ((gsi < 16) && !((1 << gsi) & irq_mask)) {
Dprintk(KERN_DEBUG PREFIX "Setting GSI %u as level-triggered\n", gsi);
irq_mask |= (1 << gsi);
eisa_set_level_irq(gsi);
}
}
#ifdef CONFIG_X86_IO_APIC
if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
mp_register_gsi(gsi, edge_level, active_high_low);
}
#endif
acpi_gsi_to_irq(gsi, &irq);
return irq;
}
#endif /* CONFIG_ACPI_PCI */
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
......
......@@ -1025,96 +1025,56 @@ void __init mp_config_acpi_legacy_irqs (void)
}
}
extern FADT_DESCRIPTOR acpi_fadt;
#ifdef CONFIG_ACPI_PCI
int (*platform_rename_gsi)(int ioapic, int gsi);
void __init mp_parse_prt (void)
void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
{
struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL;
int ioapic = -1;
int ioapic_pin = 0;
int gsi = 0;
int idx, bit = 0;
int edge_level = 0;
int active_high_low = 0;
/*
* Parsing through the PCI Interrupt Routing Table (PRT) and program
* routing for all entries.
*/
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
/* Need to get gsi for dynamic entry */
if (entry->link.handle) {
gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
if (!gsi)
continue;
}
else {
/* Hardwired GSI. Assume PCI standard settings */
gsi = entry->link.index;
edge_level = 1;
active_high_low = 1;
}
#ifdef CONFIG_ACPI_BUS
/* Don't set up the ACPI SCI because it's already set up */
if (acpi_fadt.sci_int == gsi)
return;
#endif
/* Don't set up the ACPI SCI because it's already set up */
if (acpi_fadt.sci_int == gsi) {
/* we still need to set entry's irq */
acpi_gsi_to_irq(gsi, &entry->irq);
continue;
}
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0)
continue;
ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
if (platform_rename_gsi)
gsi = platform_rename_gsi(ioapic, gsi);
/*
* Avoid pin reprogramming. PRTs typically include entries
* with redundant pin->gsi mappings (but unique PCI devices);
* we only only program the IOAPIC on the first.
*/
bit = ioapic_pin % 32;
idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
if (idx > 3) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
continue;
}
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
acpi_gsi_to_irq(gsi, &entry->irq);
continue;
}
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0) {
printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
return;
}
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
acpi_gsi_to_irq(gsi, &entry->irq);
}
printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d %s %s\n",
entry->id.segment, entry->id.bus,
entry->id.device, ('A' + entry->pin),
mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
entry->irq, edge_level ? "level" : "edge",
active_high_low ? "low" : "high");
if (platform_rename_gsi)
gsi = platform_rename_gsi(ioapic, gsi);
/*
* Avoid pin reprogramming. PRTs typically include entries
* with redundant pin->gsi mappings (but unique PCI devices);
* we only program the IOAPIC on the first.
*/
bit = ioapic_pin % 32;
idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
if (idx > 3) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
return;
}
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
return;
}
print_IO_APIC();
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
return;
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
}
#endif /*CONFIG_ACPI_PCI*/
#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
#endif /*CONFIG_ACPI_BOOT*/
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/hw_irq.h>
#include "pci.h"
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
......@@ -15,18 +17,31 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
static int __init pci_acpi_init(void)
{
struct pci_dev *dev = NULL;
if (pcibios_scanned)
return 0;
if (!acpi_noirq) {
if (!acpi_pci_irq_init()) {
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable;
} else
printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
if (acpi_noirq)
return 0;
}
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
acpi_irq_penalty_init();
pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable;
/*
* PCI IRQ routing is set up by pci_enable_device(), but we
* also do it here in case there are still broken drivers that
* don't use pci_enable_device().
*/
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
acpi_pci_irq_enable(dev);
#ifdef CONFIG_X86_IO_APIC
if (acpi_ioapic)
print_IO_APIC();
#endif
return 0;
}
......
......@@ -521,9 +521,14 @@ acpi_numa_arch_fixup (void)
#endif /* CONFIG_ACPI_NUMA */
unsigned int
acpi_register_gsi (u32 gsi, int polarity, int trigger)
acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
{
return acpi_register_irq(gsi, polarity, trigger);
if (has_8259 && gsi < 16)
return isa_irq_to_vector(gsi);
return iosapic_register_intr(gsi,
(active_high_low == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
(edge_level == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
}
EXPORT_SYMBOL(acpi_register_gsi);
......@@ -548,7 +553,7 @@ acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
acpi_legacy_devices = 1;
acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
return 0;
}
......@@ -662,16 +667,4 @@ acpi_gsi_to_irq (u32 gsi, unsigned int *irq)
return 0;
}
int
acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
{
if (has_8259 && gsi < 16)
return isa_irq_to_vector(gsi);
return iosapic_register_intr(gsi,
(polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
(trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
}
EXPORT_SYMBOL(acpi_register_irq);
#endif /* CONFIG_ACPI_BOOT */
......@@ -483,7 +483,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
index = find_iosapic(gsi);
if (index < 0) {
printk(KERN_WARNING "%s: No IOSAPIC for GSI 0x%x\n", __FUNCTION__, gsi);
printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
return;
}
......@@ -512,6 +512,42 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
}
}
static unsigned int
get_target_cpu (void)
{
#ifdef CONFIG_SMP
static int cpu = -1;
/*
* If the platform supports redirection via XTP, let it
* distribute interrupts.
*/
if (smp_int_redirect & SMP_IRQ_REDIRECTION)
return hard_smp_processor_id();
/*
* Some interrupts (ACPI SCI, for instance) are registered
* before the BSP is marked as online.
*/
if (!cpu_online(smp_processor_id()))
return hard_smp_processor_id();
/*
* Otherwise, round-robin interrupt vectors across all the
* processors. (It'd be nice if we could be smarter in the
* case of NUMA.)
*/
do {
if (++cpu >= NR_CPUS)
cpu = 0;
} while (!cpu_online(cpu));
return cpu_physical_id(cpu);
#else
return hard_smp_processor_id();
#endif
}
/*
* ACPI can describe IOSAPIC interrupts via static tables and namespace
* methods. This provides an interface to register those interrupts and
......@@ -522,21 +558,35 @@ iosapic_register_intr (unsigned int gsi,
unsigned long polarity, unsigned long trigger)
{
int vector;
unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
unsigned int dest;
unsigned long flags;
vector = gsi_to_vector(gsi);
if (vector < 0)
vector = assign_irq_vector(AUTO_ASSIGN);
/*
* If this GSI has already been registered (i.e., it's a
* shared interrupt, or we lost a race to register it),
* don't touch the RTE.
*/
spin_lock_irqsave(&iosapic_lock, flags);
{
vector = gsi_to_vector(gsi);
if (vector > 0) {
spin_unlock_irqrestore(&iosapic_lock, flags);
return vector;
}
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
polarity, trigger);
vector = assign_irq_vector(AUTO_ASSIGN);
dest = get_target_cpu();
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
polarity, trigger);
}
spin_unlock_irqrestore(&iosapic_lock, flags);
printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
(trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector);
/* program the IOSAPIC routing table */
set_rte(vector, dest, 0);
set_rte(vector, dest, 1);
return vector;
}
......@@ -549,8 +599,9 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
int iosapic_vector, u16 eid, u16 id,
unsigned long polarity, unsigned long trigger)
{
static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
unsigned char delivery;
int vector;
int vector, mask = 0;
unsigned int dest = ((id << 8) | eid) & 0xffff;
switch (int_type) {
......@@ -570,21 +621,22 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
case ACPI_INTERRUPT_CPEI:
vector = IA64_CPE_VECTOR;
delivery = IOSAPIC_LOWEST_PRIORITY;
mask = 1;
break;
default:
printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type\n");
printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
return -1;
}
register_intr(gsi, vector, delivery, polarity,
trigger);
register_intr(gsi, vector, delivery, polarity, trigger);
printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
(trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector);
/* program the IOSAPIC routing table */
set_rte(vector, dest, 0);
set_rte(vector, dest, mask);
return vector;
}
......@@ -599,18 +651,18 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
unsigned long trigger)
{
int vector;
unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
unsigned int dest = hard_smp_processor_id();
vector = isa_irq_to_vector(isa_irq);
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
polarity == IOSAPIC_POL_HIGH ? "high" : "low",
cpu_logical_id(dest), dest, vector);
/* program the IOSAPIC routing table */
set_rte(vector, dest, 0);
set_rte(vector, dest, 1);
}
void __init
......@@ -665,104 +717,3 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
}
}
void
iosapic_enable_intr (unsigned int vector)
{
unsigned int dest;
irq_desc_t *desc;
/*
* In the case of a shared interrupt, do not re-route the vector, and
* especially do not mask a running interrupt (startup will not get
* called for a shared interrupt).
*/
desc = irq_descp(vector);
if (desc->action)
return;
#ifdef CONFIG_SMP
/*
* For platforms that do not support interrupt redirect via the XTP interface, we
* can round-robin the PCI device interrupts to the processors
*/
if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
static int cpu_index = -1;
do
if (++cpu_index >= NR_CPUS)
cpu_index = 0;
while (!cpu_online(cpu_index));
dest = cpu_physical_id(cpu_index) & 0xffff;
} else {
/*
* Direct the interrupt vector to the current cpu, platform redirection
* will distribute them.
*/
dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
}
#else
/* direct the interrupt vector to the running cpu id */
dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
#endif
set_rte(vector, dest, 1);
printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
vector, dest);
}
#ifdef CONFIG_ACPI_PCI
void __init
iosapic_parse_prt (void)
{
struct acpi_prt_entry *entry;
struct list_head *node;
unsigned int gsi;
int vector;
char pci_id[16];
struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
irq_desc_t *idesc;
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
/* We're only interested in static (non-link) entries. */
if (entry->link.handle)
continue;
gsi = entry->link.index;
vector = gsi_to_vector(gsi);
if (vector < 0) {
if (find_iosapic(gsi) < 0)
continue;
/* allocate a vector for this interrupt line */
if (pcat_compat && (gsi < 16))
vector = isa_irq_to_vector(gsi);
else
/* new GSI; allocate a vector for it */
vector = assign_irq_vector(AUTO_ASSIGN);
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
IOSAPIC_LEVEL);
}
entry->irq = vector;
snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
/*
* If vector was previously initialized to a different
* handler, re-initialize.
*/
idesc = irq_descp(vector);
if (idesc->handler != irq_type)
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
IOSAPIC_LEVEL);
}
}
#endif /* CONFIG_ACPI */
......@@ -134,10 +134,18 @@ static struct pci_ops pci_root_ops = {
static int __init
pci_acpi_init (void)
{
if (!acpi_pci_irq_init())
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
else
printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
struct pci_dev *dev = NULL;
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
/*
* PCI IRQ routing is set up by pci_enable_device(), but we
* also do it here in case there are still broken drivers that
* don't use pci_enable_device().
*/
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
acpi_pci_irq_enable(dev);
return 0;
}
......
......@@ -884,91 +884,54 @@ void __init mp_config_acpi_legacy_irqs (void)
return;
}
extern FADT_DESCRIPTOR acpi_fadt;
#ifdef CONFIG_ACPI_PCI
void __init mp_parse_prt (void)
void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
{
struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL;
int ioapic = -1;
int ioapic_pin = 0;
int gsi = 0;
int idx, bit = 0;
int edge_level = 0;
int active_high_low = 0;
/*
* Parsing through the PCI Interrupt Routing Table (PRT) and program
* routing for all static (IOAPIC-direct) entries.
*/
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
/* Need to get gsi for dynamic entry */
if (entry->link.handle) {
gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
if (!gsi)
continue;
} else {
/* Hardwired GSI. Assume PCI standard settings */
gsi = entry->link.index;
edge_level = 1;
active_high_low = 1;
}
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
return;
/* Don't set up the ACPI SCI because it's already set up */
if (acpi_fadt.sci_int == gsi) {
/* we still need to set up the entry's irq */
acpi_gsi_to_irq(gsi, &entry->irq);
continue;
}
#ifdef CONFIG_ACPI_BUS
/* Don't set up the ACPI SCI because it's already set up */
if (acpi_fadt.sci_int == gsi)
return;
#endif
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0)
continue;
ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
ioapic = mp_find_ioapic(gsi);
if (ioapic < 0) {
printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
return;
}
/*
* Avoid pin reprogramming. PRTs typically include entries
* with redundant pin->gsi mappings (but unique PCI devices);
* we only only program the IOAPIC on the first.
*/
bit = ioapic_pin % 32;
idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
if (idx > 3) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
continue;
}
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
acpi_gsi_to_irq(gsi, &entry->irq);
continue;
}
ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
acpi_gsi_to_irq(gsi, &entry->irq);
}
printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
entry->id.segment, entry->id.bus,
entry->id.device, ('A' + entry->pin),
mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
entry->irq);
/*
* Avoid pin reprogramming. PRTs typically include entries
* with redundant pin->gsi mappings (but unique PCI devices);
* we only program the IOAPIC on the first.
*/
bit = ioapic_pin % 32;
idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
if (idx > 3) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
return;
}
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
return;
}
print_IO_APIC();
return;
}
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
#endif /*CONFIG_ACPI_PCI*/
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
}
#endif /*CONFIG_X86_IO_APIC*/
#endif /*CONFIG_ACPI_BOOT*/
......@@ -35,12 +35,6 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#ifdef CONFIG_X86_IO_APIC
#include <asm/mpspec.h>
#endif
#ifdef CONFIG_IOSAPIC
# include <asm/iosapic.h>
#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
......@@ -50,10 +44,6 @@ ACPI_MODULE_NAME ("pci_irq")
struct acpi_prt_list acpi_prt;
#ifdef CONFIG_X86
extern void eisa_set_level_irq(unsigned int irq);
#endif
/* --------------------------------------------------------------------------
PCI IRQ Routing Table (PRT) Support
......@@ -237,12 +227,18 @@ acpi_pci_irq_add_prt (
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
int
acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
static int
acpi_pci_irq_lookup (
struct pci_bus *bus,
int device,
int pin,
int *edge_level,
int *active_high_low)
{
struct acpi_prt_entry *entry = NULL;
int segment = pci_domain_nr(bus);
int bus_nr = bus->number;
int irq;
ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
......@@ -255,28 +251,30 @@ acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
return_VALUE(0);
}
if (!entry->irq && entry->link.handle) {
entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, NULL, NULL);
if (!entry->irq) {
if (entry->link.handle) {
irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, edge_level, active_high_low);
if (!irq) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
return_VALUE(0);
}
}
else if (!entry->irq) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n"));
return_VALUE(0);
} else {
irq = entry->link.index;
*edge_level = ACPI_LEVEL_SENSITIVE;
*active_high_low = ACPI_ACTIVE_LOW;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq));
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
return_VALUE(entry->irq);
return_VALUE(irq);
}
static int
acpi_pci_irq_derive (
struct pci_dev *dev,
int pin)
int pin,
int *edge_level,
int *active_high_low)
{
struct pci_dev *bridge = dev;
int irq = 0;
......@@ -308,8 +306,8 @@ acpi_pci_irq_derive (
pin = bridge_pin;
}
irq = acpi_pci_irq_lookup(bridge->bus,
PCI_SLOT(bridge->devfn), pin);
irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
pin, edge_level, active_high_low);
}
if (!irq) {
......@@ -330,6 +328,8 @@ acpi_pci_irq_enable (
{
int irq = 0;
u8 pin = 0;
int edge_level = ACPI_LEVEL_SENSITIVE;
int active_high_low = ACPI_ACTIVE_LOW;
ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
......@@ -352,21 +352,22 @@ acpi_pci_irq_enable (
* First we check the PCI IRQ routing table (PRT) for an IRQ. PRT
* values override any BIOS-assigned IRQs set during boot.
*/
irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin);
irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, &edge_level, &active_high_low);
/*
* If no PRT entry was found, we'll try to derive an IRQ from the
* device's parent bridge.
*/
if (!irq)
irq = acpi_pci_irq_derive(dev, pin);
irq = acpi_pci_irq_derive(dev, pin, &edge_level, &active_high_low);
/*
* No IRQ known to the ACPI subsystem - maybe the BIOS /
* driver reported one, then use it. Exit in any case.
*/
if (!irq) {
printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), pci_name(dev));
printk(KERN_WARNING PREFIX "PCI interrupt %s[%c]: no GSI",
pci_name(dev), ('A' + pin));
/* Interrupt Line values above 0xF are forbidden */
if (dev->irq && (dev->irq <= 0xF)) {
printk(" - using IRQ %d\n", dev->irq);
......@@ -378,62 +379,14 @@ acpi_pci_irq_enable (
}
}
dev->irq = irq;
dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", pci_name(dev), dev->irq));
/*
* Make sure all (legacy) PCI IRQs are set as level-triggered.
*/
#ifdef CONFIG_X86
{
static u16 irq_mask;
if ((dev->irq < 16) && !((1 << dev->irq) & irq_mask)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq));
irq_mask |= (1 << dev->irq);
eisa_set_level_irq(dev->irq);
}
}
#endif
#ifdef CONFIG_IOSAPIC
if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
iosapic_enable_intr(dev->irq);
#endif
printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI %u "
"(%s, %s) -> IRQ %d\n",
pci_name(dev), 'A' + pin, irq,
(edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
(active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high",
dev->irq);
return_VALUE(dev->irq);
}
int __init
acpi_pci_irq_init (void)
{
struct pci_dev *dev = NULL;
ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
if (!acpi_prt.count) {
printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ "
"routing entries\n");
return_VALUE(-ENODEV);
}
/* Make sure all link devices have a valid IRQ. */
if (acpi_pci_link_check()) {
return_VALUE(-ENODEV);
}
#ifdef CONFIG_X86_IO_APIC
/* Program IOAPICs using data from PRT entries. */
if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
mp_parse_prt();
#endif
#ifdef CONFIG_IOSAPIC
if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
iosapic_parse_prt();
#endif
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
acpi_pci_irq_enable(dev);
return_VALUE(0);
}
......@@ -487,13 +487,13 @@ static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = {
};
int
acpi_pci_link_check (void)
acpi_irq_penalty_init(void)
{
struct list_head *node = NULL;
struct acpi_pci_link *link = NULL;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_pci_link_check");
ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
/*
* Update penalties to facilitate IRQ balancing.
......
......@@ -131,7 +131,7 @@ acpi_table_print_madt_entry (
{
struct acpi_table_ioapic *p =
(struct acpi_table_ioapic*) header;
printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n",
printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
p->id, p->address, p->global_irq_base);
}
break;
......@@ -185,8 +185,8 @@ acpi_table_print_madt_entry (
{
struct acpi_table_iosapic *p =
(struct acpi_table_iosapic*) header;
printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n",
p->id, p->global_irq_base, (void *) (unsigned long) p->address);
printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
p->id, (void *) (unsigned long) p->address, p->global_irq_base);
}
break;
......
......@@ -57,28 +57,18 @@ static acpi_status acpi_serial_port(struct serial_struct *req,
static acpi_status acpi_serial_ext_irq(struct serial_struct *req,
struct acpi_resource_ext_irq *ext_irq)
{
if (ext_irq->number_of_interrupts > 0) {
#ifdef CONFIG_IA64
req->irq = acpi_register_irq(ext_irq->interrupts[0],
ext_irq->active_high_low, ext_irq->edge_level);
#else
req->irq = ext_irq->interrupts[0];
#endif
}
if (ext_irq->number_of_interrupts > 0)
req->irq = acpi_register_gsi(ext_irq->interrupts[0],
ext_irq->edge_level, ext_irq->active_high_low);
return AE_OK;
}
static acpi_status acpi_serial_irq(struct serial_struct *req,
struct acpi_resource_irq *irq)
{
if (irq->number_of_interrupts > 0) {
#ifdef CONFIG_IA64
req->irq = acpi_register_irq(irq->interrupts[0],
irq->active_high_low, irq->edge_level);
#else
req->irq = irq->interrupts[0];
#endif
}
if (irq->number_of_interrupts > 0)
req->irq = acpi_register_gsi(irq->interrupts[0],
irq->edge_level, irq->active_high_low);
return AE_OK;
}
......
......@@ -183,16 +183,12 @@ setup_serial_hcdp(void *tablep)
}
if (HCDP_IRQ_SUPPORTED(hcdp_dev)) {
#ifdef CONFIG_IA64
if (HCDP_PCI_UART(hcdp_dev))
port.irq = acpi_register_irq(gsi,
ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
port.irq = acpi_register_gsi(gsi,
ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
else
port.irq = acpi_register_irq(gsi,
ACPI_ACTIVE_HIGH, ACPI_EDGE_SENSITIVE);
#else
port.irq = gsi;
#endif
port.irq = acpi_register_gsi(gsi,
ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH);
port.flags |= UPF_AUTO_IRQ;
if (HCDP_PCI_UART(hcdp_dev))
......
......@@ -55,7 +55,7 @@
/* ACPI PCI Interrupt Link (pci_link.c) */
int acpi_pci_link_check (void);
int acpi_irq_penalty_init (void);
int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low);
/* ACPI PCI Interrupt Routing (pci_irq.c) */
......
......@@ -33,7 +33,7 @@ extern void mp_register_lapic_address (u64 address);
extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
extern void mp_config_acpi_legacy_irqs (void);
extern void mp_parse_prt (void);
extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
#endif /*CONFIG_ACPI_BOOT*/
#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS)
......
......@@ -60,7 +60,6 @@ extern void __init iosapic_init (unsigned long address,
unsigned int gsi_base);
extern int gsi_to_vector (unsigned int gsi);
extern int gsi_to_irq (unsigned int gsi);
extern void __init iosapic_parse_prt (void);
extern void iosapic_enable_intr (unsigned int vector);
extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
unsigned long trigger);
......
......@@ -189,7 +189,7 @@ extern void mp_register_lapic_address (u64 address);
extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
extern void mp_config_acpi_legacy_irqs (void);
extern void mp_parse_prt (void);
extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
#endif /*CONFIG_X86_IO_APIC*/
#endif
......
......@@ -437,7 +437,7 @@ extern struct acpi_prt_list acpi_prt;
struct pci_dev;
int acpi_pci_irq_enable (struct pci_dev *dev);
int acpi_pci_irq_init (void);
unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
struct acpi_pci_driver {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment