IO-APIC hack for Tyan Tomcat IV

Christer Weinigel (wingel@hog.ctrl-c.liu.se)
2 May 1999 01:00:06 -0000


Hi,

I finally got fed up with not having enough free interrupts on my Tyan
Tomcat IV system, and also got fed up with the MP-BIOS being buggy so
that PCI interrupt sharing won't work.

The following patch allows me to have four PCI cards in the machine,
and have the USB ports enabled, and have a Gravis Ultrasound (which
wants to IRQs) and a multi-IO serial/parallel card (which wants
another two IRQs) working at the same time.

I think I'll have some sleep now... have fun.

/Christer

--- linux/arch/i386/kernel/io_apic.c.orig Thu Apr 15 17:59:42 1999
+++ linux/arch/i386/kernel/io_apic.c Sun May 2 01:58:25 1999
@@ -680,6 +680,19 @@
struct IO_APIC_reg_02 reg_02;

printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
+#if 1
+ for (i = 0; i < mp_irq_entries; i++)
+ {
+ printk(" ...");
+ printk(" type = %d", mp_irqs[i].mpc_irqtype);
+ printk(" flag = %d", mp_irqs[i].mpc_irqflag);
+ printk(" bus = %d", mp_irqs[i].mpc_srcbus);
+ printk(" busirq = %d", mp_irqs[i].mpc_srcbusirq);
+ printk(" apic = %d", mp_irqs[i].mpc_dstapic);
+ printk(" apicirq = %d", mp_irqs[i].mpc_dstirq);
+ printk("\n");
+ }
+#endif
printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers);

*(int *)&reg_00 = io_apic_read(0);
@@ -1294,6 +1307,95 @@
printk(" see Documentation/IO-APIC.txt to enable them\n");
io_apic_irqs = 0;
}
+
+#if 1
+ /* This works around the buggy MP BIOS on a Tyan Tomcat IV
+ (BIOS version 1.02) and hardcodes all the PCI interrupt
+ assignments.
+
+ First of all, it seems as if the BIOS assigns multiple
+ PCI devices to a single IRQ it only puts the mappings
+ for one of the devices in the MPTABLE, so when the kernel
+ reprograms the IO-apic, none of the other PCI devices
+ will get any interrupts. To get around this, the
+ following code hardwires the mapping of PCI interrupt
+ sources to pins 16-19 on the IO-APIC.
+
+ Since all PCI devices are assigned "high IRQs", the low
+ IRQs are freed and can be re-used for ISA devices. */
+
+ if (1) {
+ static struct mpc_config_intsrc mp_hardwire[] = {
+ /* PCI Slot 20 */
+ { 3, 0, 15, 0, (20 << 2) | 0, 2, 16 }, /* 0/20/A -> PIN 16 */
+ { 3, 0, 15, 0, (20 << 2) | 1, 2, 17 }, /* 0/20/B -> PIN 17 */
+ { 3, 0, 15, 0, (20 << 2) | 2, 2, 18 }, /* 0/20/C -> PIN 18 */
+ { 3, 0, 15, 0, (20 << 2) | 3, 2, 19 }, /* 0/20/D -> PIN 19 */
+
+ /* PCI Slot 19 */
+ { 3, 0, 15, 0, (19 << 2) | 0, 2, 17 }, /* 0/19/A -> PIN 17 */
+ { 3, 0, 15, 0, (19 << 2) | 1, 2, 18 }, /* 0/19/B -> PIN 18 */
+ { 3, 0, 15, 0, (19 << 2) | 2, 2, 19 }, /* 0/19/C -> PIN 19 */
+ { 3, 0, 15, 0, (19 << 2) | 3, 2, 16 }, /* 0/19/D -> PIN 16 */
+
+ /* PCI Slot 18 */
+ { 3, 0, 15, 0, (18 << 2) | 0, 2, 18 }, /* 0/18/A -> PIN 18 */
+ { 3, 0, 15, 0, (18 << 2) | 1, 2, 19 }, /* 0/18/B -> PIN 19 */
+ { 3, 0, 15, 0, (18 << 2) | 2, 2, 16 }, /* 0/18/C -> PIN 16 */
+ { 3, 0, 15, 0, (18 << 2) | 3, 2, 17 }, /* 0/18/D -> PIN 17 */
+
+ /* PCI Slot 17 */
+ { 3, 0, 15, 0, (17 << 2) | 0, 2, 19 }, /* 0/17/A -> PIN 19 */
+ { 3, 0, 15, 0, (17 << 2) | 1, 2, 16 }, /* 0/17/B -> PIN 16 */
+ { 3, 0, 15, 0, (17 << 2) | 2, 2, 17 }, /* 0/17/C -> PIN 17 */
+ { 3, 0, 15, 0, (17 << 2) | 3, 2, 18 }, /* 0/17/D -> PIN 18 */
+
+ /* The USB controller shares its IRQ line with PCI Slot 17 */
+ { 3, 0, 15, 0, (7 << 2) | 3, 2, 19 }, /* 0/7/D -> PIN 19 */
+
+#if 0
+ /* If you have a PCI bridge in a slot (e.g. a multiport
+ ethernet adapter) you will have to hardcode what IRQ
+ assignments it will get.
+
+ It seems as if a DEC DC21052 PCI Bridge will map the
+ interrupt from the first subdevice to its IRQ A pin,
+ the interrupt from the second subdevice to its IRQ B
+ pin and so on. This might be useful information.
+
+ This is an example for ZNYX dual Ethernet adapter in
+ PCI Slot 19: the first subdevice is on bus 1, slot 4
+ with the interrupt routed to IRQ A on slot 19, the
+ second subdevice is on bus 1, slot 5 with IRQ B on
+ slot 19. */
+
+ { 3, 0, 15, 1, (4 << 2) | 0, 2, 17 }, /* 1/4/0 -> PIN 17 */
+ { 3, 0, 15, 1, (5 << 2) | 0, 2, 18 }, /* 1/5/0 -> PIN 18 */
+#endif
+ };
+ int i;
+
+ /* Re-map all ISA interrupts to the ISA bus */
+ for (i = 0; i < mp_irq_entries; i++) {
+ if (mp_irqs[i].mpc_dstirq >= 16) {
+ mp_irqs[i].mpc_irqflag = 0;
+ mp_irqs[i].mpc_dstirq = mp_irqs[i].mpc_srcbusirq;
+ }
+ }
+
+ /* Hardwire my own PCI interrupts */
+ for (i = 0;
+ i < sizeof(mp_hardwire)/sizeof(struct mpc_config_intsrc);
+ i++) {
+ mp_irqs [mp_irq_entries] = mp_hardwire[i];
+ if (++mp_irq_entries == MAX_IRQ_SOURCES) {
+ printk("Max irq sources exceeded!!\n");
+ printk("Skipping remaining sources.\n");
+ --mp_irq_entries;
+ }
+ }
+ }
+#endif

/*
* If there are no explicit MP IRQ entries, it's either one of the

-- 
If it's tourist season, why can't we shoot them?

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/