patch-2.3.43 linux/arch/ia64/dig/iosapic.c
Next file: linux/arch/ia64/dig/machvec.c
Previous file: linux/arch/ia64/dig/Makefile
Back to the patch index
Back to the overall index
- Lines: 554
- Date:
Sun Feb 6 18:42:40 2000
- Orig file:
v2.3.42/linux/arch/ia64/dig/iosapic.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.42/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c
@@ -0,0 +1,553 @@
+/*
+ * Streamlined APIC support.
+ *
+ * Copyright (C) 1999 Intel Corp.
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999-2000 Hewlett-Packard Co.
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
+ */
+#include <linux/config.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/iosapic.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/delay.h>
+#include <asm/processor.h>
+
+#undef DEBUG_IRQ_ROUTING
+
+/*
+ * IRQ vectors 0..15 are treated as the legacy interrupts of the PC-AT
+ * platform. No new drivers should ever ask for specific irqs, but we
+ * provide compatibility here in case there is an old driver that does
+ * ask for specific irqs (serial, keyboard, stuff like that). Since
+ * IA-64 doesn't allow irq 0..15 to be used for external interrupts
+ * anyhow, this in no way prevents us from doing the Right Thing
+ * with new drivers.
+ */
+struct iosapic_vector iosapic_vector[NR_IRQS] = {
+ [0 ... NR_IRQS-1] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+};
+
+#ifndef CONFIG_IA64_IRQ_ACPI
+/*
+ * Defines the default interrupt routing information for the LION platform
+ * XXX - this information should be obtained from the ACPI and hardcoded since
+ * we do not have ACPI AML support.
+ */
+
+struct intr_routing_entry intr_routing[] = {
+ {0,0,0,2,0,0,0,0},
+ {0,0,1,1,0,0,0,0},
+ {0,0,2,0xff,0,0,0,0},
+ {0,0,3,3,0,0,0,0},
+ {0,0,4,4,0,0,0,0},
+ {0,0,5,5,0,0,0,0},
+ {0,0,6,6,0,0,0,0},
+ {0,0,7,7,0,0,0,0},
+ {0,0,8,8,0,0,0,0},
+ {0,0,9,9,0,0,0,0},
+ {0,0,10,10,0,0,0,0},
+ {0,0,11,11,0,0,0,0},
+ {0,0,12,12,0,0,0,0},
+ {0,0,13,13,0,0,0,0},
+ {0,0,14,14,0,0,0,0},
+ {0,0,15,15,0,0,0,0},
+#ifdef CONFIG_IA64_LION_HACKS
+ {1, 0, 0x04, 16, 0, 0, 1, 1}, /* bus 0, device id 1, INTA */
+ {1, 0, 0x05, 26, 0, 0, 1, 1}, /* bus 0, device id 1, INTB */
+ {1, 0, 0x06, 36, 0, 0, 1, 1}, /* bus 0, device id 1, INTC */
+ {1, 0, 0x07, 42, 0, 0, 1, 1}, /* bus 0, device id 1, INTD */
+
+ {1, 0, 0x08, 17, 0, 0, 1, 1}, /* bus 0, device id 2, INTA */
+ {1, 0, 0x09, 27, 0, 0, 1, 1}, /* bus 0, device id 2, INTB */
+ {1, 0, 0x0a, 37, 0, 0, 1, 1}, /* bus 0, device id 2, INTC */
+ {1, 0, 0x0b, 42, 0, 0, 1, 1}, /* bus 0, device id 2, INTD */
+
+ {1, 0, 0x0f, 50, 0, 0, 1, 1}, /* bus 0, device id 3, INTD */
+
+ {1, 0, 0x14, 51, 0, 0, 1, 1}, /* bus 0, device id 5, INTA */
+
+ {1, 0, 0x18, 49, 0, 0, 1, 1}, /* bus 0, device id 6, INTA */
+
+ {1, 1, 0x04, 18, 0, 0, 1, 1}, /* bus 1, device id 1, INTA */
+ {1, 1, 0x05, 28, 0, 0, 1, 1}, /* bus 1, device id 1, INTB */
+ {1, 1, 0x06, 38, 0, 0, 1, 1}, /* bus 1, device id 1, INTC */
+ {1, 1, 0x07, 43, 0, 0, 1, 1}, /* bus 1, device id 1, INTD */
+
+ {1, 1, 0x08, 48, 0, 0, 1, 1}, /* bus 1, device id 2, INTA */
+
+ {1, 1, 0x0c, 19, 0, 0, 1, 1}, /* bus 1, device id 3, INTA */
+ {1, 1, 0x0d, 29, 0, 0, 1, 1}, /* bus 1, device id 3, INTB */
+ {1, 1, 0x0e, 38, 0, 0, 1, 1}, /* bus 1, device id 3, INTC */
+ {1, 1, 0x0f, 44, 0, 0, 1, 1}, /* bus 1, device id 3, INTD */
+
+ {1, 1, 0x10, 20, 0, 0, 1, 1}, /* bus 1, device id 4, INTA */
+ {1, 1, 0x11, 30, 0, 0, 1, 1}, /* bus 1, device id 4, INTB */
+ {1, 1, 0x12, 39, 0, 0, 1, 1}, /* bus 1, device id 4, INTC */
+ {1, 1, 0x13, 45, 0, 0, 1, 1}, /* bus 1, device id 4, INTD */
+
+ {1, 2, 0x04, 21, 0, 0, 1, 1}, /* bus 2, device id 1, INTA */
+ {1, 2, 0x05, 31, 0, 0, 1, 1}, /* bus 2, device id 1, INTB */
+ {1, 2, 0x06, 39, 0, 0, 1, 1}, /* bus 2, device id 1, INTC */
+ {1, 2, 0x07, 45, 0, 0, 1, 1}, /* bus 2, device id 1, INTD */
+
+ {1, 2, 0x08, 22, 0, 0, 1, 1}, /* bus 2, device id 2, INTA */
+ {1, 2, 0x09, 32, 0, 0, 1, 1}, /* bus 2, device id 2, INTB */
+ {1, 2, 0x0a, 40, 0, 0, 1, 1}, /* bus 2, device id 2, INTC */
+ {1, 2, 0x0b, 46, 0, 0, 1, 1}, /* bus 2, device id 2, INTD */
+
+ {1, 2, 0x0c, 23, 0, 0, 1, 1}, /* bus 2, device id 3, INTA */
+ {1, 2, 0x0d, 33, 0, 0, 1, 1}, /* bus 2, device id 3, INTB */
+ {1, 2, 0x0e, 40, 0, 0, 1, 1}, /* bus 2, device id 3, INTC */
+ {1, 2, 0x0f, 46, 0, 0, 1, 1}, /* bus 2, device id 3, INTD */
+
+ {1, 3, 0x04, 24, 0, 0, 1, 1}, /* bus 3, device id 1, INTA */
+ {1, 3, 0x05, 34, 0, 0, 1, 1}, /* bus 3, device id 1, INTB */
+ {1, 3, 0x06, 41, 0, 0, 1, 1}, /* bus 3, device id 1, INTC */
+ {1, 3, 0x07, 47, 0, 0, 1, 1}, /* bus 3, device id 1, INTD */
+
+ {1, 3, 0x08, 25, 0, 0, 1, 1}, /* bus 3, device id 2, INTA */
+ {1, 3, 0x09, 35, 0, 0, 1, 1}, /* bus 3, device id 2, INTB */
+ {1, 3, 0x0a, 41, 0, 0, 1, 1}, /* bus 3, device id 2, INTC */
+ {1, 3, 0x0b, 47, 0, 0, 1, 1}, /* bus 3, device id 2, INTD */
+#else
+ /*
+ * BigSur platform, bus 0, device 1,2,4 and bus 1 device 0-3
+ */
+ {1,1,0x0,19,0,0,1,1}, /* bus 1, device id 0, INTA */
+ {1,1,0x1,18,0,0,1,1}, /* bus 1, device id 0, INTB */
+ {1,1,0x2,17,0,0,1,1}, /* bus 1, device id 0, INTC */
+ {1,1,0x3,16,0,0,1,1}, /* bus 1, device id 0, INTD */
+
+ {1,1,0x4,23,0,0,1,1}, /* bus 1, device id 1, INTA */
+ {1,1,0x5,22,0,0,1,1}, /* bus 1, device id 1, INTB */
+ {1,1,0x6,21,0,0,1,1}, /* bus 1, device id 1, INTC */
+ {1,1,0x7,20,0,0,1,1}, /* bus 1, device id 1, INTD */
+
+ {1,1,0x8,27,0,0,1,1}, /* bus 1, device id 2, INTA */
+ {1,1,0x9,26,0,0,1,1}, /* bus 1, device id 2, INTB */
+ {1,1,0xa,25,0,0,1,1}, /* bus 1, device id 2, INTC */
+ {1,1,0xb,24,0,0,1,1}, /* bus 1, device id 2, INTD */
+
+ {1,1,0xc,31,0,0,1,1}, /* bus 1, device id 3, INTA */
+ {1,1,0xd,30,0,0,1,1}, /* bus 1, device id 3, INTB */
+ {1,1,0xe,29,0,0,1,1}, /* bus 1, device id 3, INTC */
+ {1,1,0xf,28,0,0,1,1}, /* bus 1, device id 3, INTD */
+
+ {1,0,0x4,35,0,0,1,1}, /* bus 0, device id 1, INTA */
+ {1,0,0x5,34,0,0,1,1}, /* bus 0, device id 1, INTB */
+ {1,0,0x6,33,0,0,1,1}, /* bus 0, device id 1, INTC */
+ {1,0,0x7,32,0,0,1,1}, /* bus 0, device id 1, INTD */
+
+ {1,0,0x8,39,0,0,1,1}, /* bus 0, device id 2, INTA */
+ {1,0,0x9,38,0,0,1,1}, /* bus 0, device id 2, INTB */
+ {1,0,0xa,37,0,0,1,1}, /* bus 0, device id 2, INTC */
+ {1,0,0xb,36,0,0,1,1}, /* bus 0, device id 2, INTD */
+
+ {1,0,0x10,43,0,0,1,1}, /* bus 0, device id 4, INTA */
+ {1,0,0x11,42,0,0,1,1}, /* bus 0, device id 4, INTB */
+ {1,0,0x12,41,0,0,1,1}, /* bus 0, device id 4, INTC */
+ {1,0,0x13,40,0,0,1,1}, /* bus 0, device id 4, INTD */
+
+ {1,0,0x14,17,0,0,1,1}, /* bus 0, device id 5, INTA */
+ {1,0,0x18,18,0,0,1,1}, /* bus 0, device id 6, INTA */
+ {1,0,0x1c,19,0,0,1,1}, /* bus 0, device id 7, INTA */
+#endif
+ {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
+};
+
+int
+iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin)
+{
+ int i = -1;
+
+ while (intr_routing[++i].srcbus != 0xff) {
+ if (intr_routing[i].srcbus == BUS_PCI) {
+ if ((intr_routing[i].srcbusirq == ((slot << 2) | pci_pin))
+ && (intr_routing[i].srcbusno == bus)) {
+ return(intr_routing[i].iosapic_pin);
+ }
+ }
+ }
+ return -1;
+}
+
+#else /* CONFIG_IA64_IRQ_ACPI */
+
+/*
+ * find the IRQ in the IOSAPIC map for the PCI device on bus/slot/pin
+ */
+int
+iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin)
+{
+ int i;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ if ((iosapic_bustype(i) == BUS_PCI) &&
+ (iosapic_bus(i) == bus) &&
+ (iosapic_busdata(i) == ((slot << 16) | pci_pin))) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+#endif /* !CONFIG_IA64_IRQ_ACPI */
+
+static void
+set_rte (unsigned long iosapic_addr, int entry, int pol, int trigger, int delivery,
+ long dest, int vector)
+{
+ int low32;
+ int high32;
+
+ low32 = ((pol << IO_SAPIC_POLARITY_SHIFT) |
+ (trigger << IO_SAPIC_TRIGGER_SHIFT) |
+ (delivery << IO_SAPIC_DELIVERY_SHIFT) |
+ vector);
+
+ /* dest contains both id and eid */
+ high32 = (dest << IO_SAPIC_DEST_SHIFT);
+
+ /*
+ * program the rte
+ */
+ writel(IO_SAPIC_RTE_HIGH(entry), iosapic_addr + IO_SAPIC_REG_SELECT);
+ writel(high32, iosapic_addr + IO_SAPIC_WINDOW);
+ writel(IO_SAPIC_RTE_LOW(entry), iosapic_addr + IO_SAPIC_REG_SELECT);
+ writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+}
+
+
+static void
+enable_pin (unsigned int pin, unsigned long iosapic_addr)
+{
+ int low32;
+
+ writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT);
+ low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
+
+ low32 &= ~(1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */
+ writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+}
+
+
+static void
+disable_pin (unsigned int pin, unsigned long iosapic_addr)
+{
+ int low32;
+
+ writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT);
+ low32 = readl(iosapic_addr + IO_SAPIC_WINDOW);
+
+ low32 |= (1 << IO_SAPIC_MASK_SHIFT); /* Set only the mask bit */
+ writel(low32, iosapic_addr + IO_SAPIC_WINDOW);
+}
+
+#define iosapic_shutdown_irq iosapic_disable_irq
+
+static void
+iosapic_enable_irq (unsigned int irq)
+{
+ int pin = iosapic_pin(irq);
+
+ if (pin < 0)
+ /* happens during irq auto probing... */
+ return;
+ enable_pin(pin, iosapic_addr(irq));
+}
+
+static void
+iosapic_disable_irq (unsigned int irq)
+{
+ int pin = iosapic_pin(irq);
+
+ if (pin < 0)
+ return;
+ disable_pin(pin, iosapic_addr(irq));
+}
+
+unsigned int
+iosapic_version(unsigned long base_addr)
+{
+ /*
+ * IOSAPIC Version Register return 32 bit structure like:
+ * {
+ * unsigned int version : 8;
+ * unsigned int reserved1 : 8;
+ * unsigned int pins : 8;
+ * unsigned int reserved2 : 8;
+ * }
+ */
+ writel(IO_SAPIC_VERSION, base_addr + IO_SAPIC_REG_SELECT);
+ return readl(IO_SAPIC_WINDOW + base_addr);
+}
+
+static int
+iosapic_handle_irq (unsigned int irq, struct pt_regs *regs)
+{
+ struct irqaction *action = 0;
+ struct irq_desc *id = irq_desc + irq;
+ unsigned int status;
+ int retval;
+
+ spin_lock(&irq_controller_lock);
+ {
+ status = id->status;
+
+ /* do we need to do something IOSAPIC-specific to ACK the irq here??? */
+ /* Yes, but only level-triggered interrupts. We'll do that later */
+ if ((status & IRQ_INPROGRESS) == 0 && (status & IRQ_ENABLED) != 0) {
+ action = id->action;
+ status |= IRQ_INPROGRESS;
+ }
+ id->status = status & ~(IRQ_REPLAY | IRQ_WAITING);
+ }
+ spin_unlock(&irq_controller_lock);
+
+ if (!action) {
+ if (!(id->status & IRQ_AUTODETECT))
+ printk("iosapic_handle_irq: unexpected interrupt %u;"
+ "disabling it (status=%x)\n", irq, id->status);
+ /*
+ * If we don't have a handler, disable the pin so we
+ * won't get any further interrupts (until
+ * re-enabled). --davidm 99/12/17
+ */
+ iosapic_disable_irq(irq);
+ return 0;
+ }
+
+ retval = invoke_irq_handlers (irq, regs, action);
+
+ if (iosapic_trigger(irq) == IO_SAPIC_LEVEL) /* ACK Level trigger interrupts */
+ writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI);
+
+ spin_lock(&irq_controller_lock);
+ {
+ status = (id->status & ~IRQ_INPROGRESS);
+ id->status = status;
+ }
+ spin_unlock(&irq_controller_lock);
+
+ return retval;
+}
+
+void __init
+iosapic_init (unsigned long addr)
+{
+ int i;
+#ifdef CONFIG_IA64_IRQ_ACPI
+ struct pci_vector_struct *vectors;
+ int irq;
+#else
+ int vector;
+#endif
+
+ /*
+ * Disable all local interrupts
+ */
+
+ ia64_set_itv(0, 1);
+ ia64_set_lrr0(0, 1);
+ ia64_set_lrr1(0, 1);
+
+ /*
+ * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
+ * enabled.
+ */
+
+ outb(0xff, 0xA1);
+ outb(0xff, 0x21);
+
+#if defined(CONFIG_IA64_SOFTSDV_HACKS)
+ memset(iosapic_vector, 0x0, sizeof(iosapic_vector));
+ for (i = 0; i < NR_IRQS; i++) {
+ iosapic_pin(i) = 0xff;
+ iosapic_addr(i) = (unsigned long) ioremap(IO_SAPIC_DEFAULT_ADDR, 0);
+ }
+ /* XXX this should come from systab or some such: */
+ iosapic_pin(TIMER_IRQ) = 5; /* System Clock Interrupt */
+ iosapic_pin(0x40) = 3; /* Keyboard */
+ iosapic_pin(0x92) = 9; /* COM1 Serial Port */
+ iosapic_pin(0x80) = 4; /* Periodic Interrupt */
+ iosapic_pin(0xc0) = 2; /* Mouse */
+ iosapic_pin(0xe0) = 1; /* IDE Disk */
+ iosapic_pin(0xf0) = 6; /* E-IDE CDROM */
+ iosapic_pin(0xa0) = 10; /* Real PCI Interrupt */
+#elif !defined(CONFIG_IA64_IRQ_ACPI)
+ /*
+ * For systems where the routing info in ACPI is
+ * unavailable/wrong, use the intr_routing information to
+ * initialize the iosapic array
+ */
+ i = -1;
+ while (intr_routing[++i].srcbus != 0xff) {
+ if (intr_routing[i].srcbus == BUS_ISA) {
+ vector = map_legacy_irq(intr_routing[i].srcbusirq);
+ } else if (intr_routing[i].srcbus == BUS_PCI) {
+ vector = intr_routing[i].iosapic_pin;
+ } else {
+ printk("unknown bus type %d for intr_routing[%d]\n",
+ intr_routing[i].srcbus, i);
+ continue;
+ }
+ iosapic_pin(vector) = intr_routing[i].iosapic_pin;
+ iosapic_dmode(vector) = intr_routing[i].mode;
+ iosapic_polarity(vector) = intr_routing[i].polarity;
+ iosapic_trigger(vector) = intr_routing[i].trigger;
+# ifdef DEBUG_IRQ_ROUTING
+ printk("irq[0x%x(0x%x)]:0x%x, %d, %d, %d\n", vector, intr_routing[i].srcbusirq,
+ iosapic_pin(vector), iosapic_dmode(vector), iosapic_polarity(vector),
+ iosapic_trigger(vector));
+# endif
+ }
+#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && !defined(CONFIG_IA64_IRQ_ACPI) */
+ /*
+ * Map the legacy ISA devices into the IOAPIC data; We'll override these
+ * later with data from the ACPI Interrupt Source Override table.
+ *
+ * Huh, the Lion w/ FPSWA firmware has entries for _all_ of the legacy IRQs,
+ * including those that are not different from PC/AT standard. I don't know
+ * if this is a bug in the other firmware or not. I'm going to leave this code
+ * here, so that this works on BigSur but will go ask Intel. --wfd 2000-Jan-19
+ *
+ */
+ for (i =0 ; i < IA64_MIN_VECTORED_IRQ; i++) {
+ irq = map_legacy_irq(i);
+ iosapic_pin(irq) = i;
+ iosapic_bus(irq) = BUS_ISA;
+ iosapic_busdata(irq) = 0;
+ iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY;
+ iosapic_trigger(irq) = IO_SAPIC_EDGE;
+ iosapic_polarity(irq) = IO_SAPIC_POL_HIGH;
+#ifdef DEBUG_IRQ_ROUTING
+ printk("ISA: IRQ %02x -> Vector %02x IOSAPIC Pin %d\n", i, irq, iosapic_pin(irq));
+#endif
+ }
+
+ /*
+ * Map the PCI Interrupt data into the ACPI IOSAPIC data using
+ * the info that the bootstrap loader passed to us.
+ */
+ ia64_boot_param.pci_vectors = (__u64) __va(ia64_boot_param.pci_vectors);
+ vectors = (struct pci_vector_struct *) ia64_boot_param.pci_vectors;
+ for (i = 0; i < ia64_boot_param.num_pci_vectors; i++) {
+ irq = map_legacy_irq(vectors[i].irq);
+
+ iosapic_bustype(irq) = BUS_PCI;
+ iosapic_pin(irq) = irq - iosapic_baseirq(irq);
+ iosapic_bus(irq) = vectors[i].bus;
+ /*
+ * Map the PCI slot and pin data into iosapic_busdata()
+ */
+ iosapic_busdata(irq) = (vectors[i].pci_id & 0xffff0000) | vectors[i].pin;
+
+ /* Default settings for PCI */
+ iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY;
+ iosapic_trigger(irq) = IO_SAPIC_LEVEL;
+ iosapic_polarity(irq) = IO_SAPIC_POL_LOW;
+
+#ifdef DEBUG_IRQ_ROUTING
+ printk("PCI: BUS %d Slot %x Pin %x IRQ %02x --> Vector %02x IOSAPIC Pin %d\n",
+ vectors[i].bus, vectors[i].pci_id>>16, vectors[i].pin, vectors[i].irq,
+ irq, iosapic_pin(irq));
+#endif
+ }
+#endif /* !CONFIG_IA64_IRQ_ACPI */
+}
+
+static void
+iosapic_startup_irq (unsigned int irq)
+{
+ int pin;
+
+ if (irq == TIMER_IRQ)
+ return;
+ pin = iosapic_pin(irq);
+ if (pin < 0)
+ /* happens during irq auto probing... */
+ return;
+ set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq),
+ iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq);
+ enable_pin(pin, iosapic_addr(irq));
+}
+
+struct hw_interrupt_type irq_type_iosapic = {
+ "IOSAPIC",
+ iosapic_init,
+ iosapic_startup_irq,
+ iosapic_shutdown_irq,
+ iosapic_handle_irq,
+ iosapic_enable_irq,
+ iosapic_disable_irq
+};
+
+void
+dig_irq_init (struct irq_desc desc[NR_IRQS])
+{
+ int i;
+
+ /*
+ * Claim all non-legacy irq vectors as ours unless they're
+ * claimed by someone else already (e.g., timer or IPI are
+ * handled internally).
+ */
+ for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) {
+ if (irq_desc[i].handler == &irq_type_default)
+ irq_desc[i].handler = &irq_type_iosapic;
+ }
+}
+
+void
+dig_pci_fixup (void)
+{
+ struct pci_dev *dev;
+ int irq;
+ unsigned char pin;
+
+ pci_for_each_dev(dev) {
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ pin--; /* interrupt pins are numbered starting from 1 */
+ irq = iosapic_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn),
+ pin);
+ if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+ struct pci_dev * bridge = dev->bus->self;
+
+ /* do the bridge swizzle... */
+ pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+ irq = iosapic_get_PCI_irq_vector(bridge->bus->number,
+ PCI_SLOT(bridge->devfn), pin);
+ if (irq >= 0)
+ printk(KERN_WARNING
+ "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n",
+ bridge->bus->number, PCI_SLOT(bridge->devfn),
+ pin, irq);
+ }
+ if (irq >= 0) {
+ printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+ dev->irq = irq;
+ }
+ }
+ /*
+ * Nothing to fixup
+ * Fix out-of-range IRQ numbers
+ */
+ if (dev->irq >= NR_IRQS)
+ dev->irq = 15; /* Spurious interrupts */
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)