summaryrefslogtreecommitdiff
path: root/arch/x86/cpu/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/cpu/irq.c')
-rw-r--r--arch/x86/cpu/irq.c65
1 files changed, 56 insertions, 9 deletions
diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c
index df4300c..97dd000 100644
--- a/arch/x86/cpu/irq.c
+++ b/arch/x86/cpu/irq.c
@@ -58,17 +58,28 @@ void pirq_assign_irq(int link, u8 irq)
writeb(irq, irq_router.ibase + LINK_N2V(link, base));
}
-static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus,
- u8 device, u8 pin, u8 pirq)
+static struct irq_info *check_dup_entry(struct irq_info *slot_base,
+ int entry_num, int bus, int device)
{
- struct irq_info *slot = *slotp;
+ struct irq_info *slot = slot_base;
+ int i;
+
+ for (i = 0; i < entry_num; i++) {
+ if (slot->bus == bus && slot->devfn == (device << 3))
+ break;
+ slot++;
+ }
+ return (i == entry_num) ? NULL : slot;
+}
+
+static inline void fill_irq_info(struct irq_info *slot, int bus, int device,
+ int pin, int pirq)
+{
slot->bus = bus;
slot->devfn = (device << 3) | 0;
slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base);
slot->irq[pin - 1].bitmap = irq_router.irq_mask;
- (*entries)++;
- (*slotp)++;
}
__weak void cpu_irq_init(void)
@@ -84,7 +95,7 @@ static int create_pirq_routing_table(void)
int len, count;
const u32 *cell;
struct irq_routing_table *rt;
- struct irq_info *slot;
+ struct irq_info *slot, *slot_base;
int irq_entries = 0;
int i;
int ret;
@@ -167,7 +178,7 @@ static int create_pirq_routing_table(void)
rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
- slot = rt->slots;
+ slot_base = rt->slots;
/* Now fill in the irq_info entries in the PIRQ table */
for (i = 0; i < count; i++) {
@@ -181,8 +192,44 @@ static int create_pirq_routing_table(void)
i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
PCI_FUNC(pr.bdf), 'A' + pr.pin - 1,
'A' + pr.pirq);
- fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf),
- PCI_DEV(pr.bdf), pr.pin, pr.pirq);
+
+ slot = check_dup_entry(slot_base, irq_entries,
+ PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
+ if (slot) {
+ debug("found entry for bus %d device %d, ",
+ PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
+
+ if (slot->irq[pr.pin - 1].link) {
+ debug("skipping\n");
+
+ /*
+ * Sanity test on the routed PIRQ pin
+ *
+ * If they don't match, show a warning to tell
+ * there might be something wrong with the PIRQ
+ * routing information in the device tree.
+ */
+ if (slot->irq[pr.pin - 1].link !=
+ LINK_N2V(pr.pirq, irq_router.link_base))
+ debug("WARNING: Inconsistent PIRQ routing information\n");
+
+ cell += sizeof(struct pirq_routing) /
+ sizeof(u32);
+ continue;
+ } else {
+ debug("writing INT%c\n", 'A' + pr.pin - 1);
+ fill_irq_info(slot, PCI_BUS(pr.bdf),
+ PCI_DEV(pr.bdf), pr.pin, pr.pirq);
+ cell += sizeof(struct pirq_routing) /
+ sizeof(u32);
+ continue;
+ }
+ }
+
+ slot = slot_base + irq_entries;
+ fill_irq_info(slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
+ pr.pin, pr.pirq);
+ irq_entries++;
cell += sizeof(struct pirq_routing) / sizeof(u32);
}