patch-2.2.14 linux/arch/ppc/kernel/pmac_pic.c

Next file: linux/arch/ppc/kernel/pmac_setup.c
Previous file: linux/arch/ppc/kernel/openpic.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
@@ -3,12 +3,14 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/prom.h>
 #include "pmac_pic.h"
 
-/* pmac */struct pmac_irq_hw {
+struct pmac_irq_hw {
         unsigned int    flag;
         unsigned int    enable;
         unsigned int    ack;
@@ -31,6 +33,12 @@
 #define GATWICK_IRQ_POOL_SIZE        10
 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+                                      unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+                                      unsigned char offset, unsigned short val);
+
+
 static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
 {
         unsigned long bit = 1UL << (irq_nr & 0x1f);
@@ -108,7 +116,7 @@
 };
 
 struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
+        " PMAC-PI2 ",
 	NULL,
 	NULL,
 	NULL,
@@ -160,7 +168,7 @@
                         if (xmon_2nd)
                                 xmon(regs);
 #endif
-                        smp_message_recv();
+                        pmac_smp_message_recv();
                         goto out;
                 }
                 /* could be here due to a do_fake_interrupt call but we don't
@@ -290,17 +298,67 @@
 	}
 }
 
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller.  If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static void __init enable_second_ohare(void)
+{
+	unsigned char bus, devfn;
+	unsigned short cmd;
+        unsigned long addr;
+	int second_irq;
+	struct device_node *irqctrler = find_devices("pci106b,7");
+	struct device_node *ether;
+
+	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+		return;
+	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+	max_irqs = 64;
+	if (pci_device_loc(irqctrler, &bus, &devfn) == 0) {
+		pmac_pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+		cmd &= ~PCI_COMMAND_IO;
+		pmac_pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	}
+
+	second_irq = irqctrler->intrs[0].line;
+	printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq);
+	request_irq(second_irq, gatwick_action, SA_INTERRUPT,
+		    "interrupt cascade", 0 );
+
+	/* Fix interrupt for the modem/ethernet combo controller. The number
+	   in the device tree (27) is bogus (correct for the ethernet-only
+	   board but not the combo ethernet/modem board).
+	   The real interrupt is 28 on the second controller -> 28+32 = 60.
+	*/
+	ether = find_devices("pci1011,14");
+	if (ether && ether->n_intrs > 0) {
+		ether->intrs[0].line = 60;
+		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+		       ether->intrs[0].line);
+	}
+}
+
 __initfunc(void
 pmac_pic_init(void))
 {
         int i;
         struct device_node *irqctrler;
-        unsigned long addr;
-	int second_irq = -999;
+        volatile struct pmac_irq_hw *addr;
+	int second_irq;
 
-
-	/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
-	   others have 32 */
+	/*
+	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+	 * 1998 G3 Series PowerBooks have 128, 
+	 * other powermacs have 32.
+	 * The combo ethernet/modem card for the Powerstar powerbooks
+	 * (2400/3400/3500, ohare based) has a second ohare chip
+	 * effectively making a total of 64.
+	 */
 	max_irqs = max_real_irqs = 32;
 	irqctrler = find_devices("mac-io");
 	if (irqctrler)
@@ -317,24 +375,28 @@
 	/* get addresses of first controller */
 	if (irqctrler) {
 		if  (irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 0; i < 2; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (2 - i) * 0x10);
+			addr = ioremap(irqctrler->addrs[0].address, 0x40);
+			addr += 2;
+			for (i = 0; i < 2; ++i, --addr)
+				pmac_irq_hw[i] = addr;
 		}
 		
 		/* get addresses of second controller */
-		irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+		irqctrler = irqctrler->next;
 		if (irqctrler && irqctrler->n_addrs > 0) {
-			addr = (unsigned long) 
-				ioremap(irqctrler->addrs[0].address, 0x40);
-			for (i = 2; i < 4; ++i)
-				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-					(addr + (4 - i) * 0x10);
+			addr = ioremap(irqctrler->addrs[0].address, 0x40);
+			addr += 2;
+			for (i = 2; i < 4; ++i, --addr)
+				pmac_irq_hw[i] = addr;
 		}
 	}
 
+	/* PowerBooks 3400 and 3500 can have a second controller in a second
+	   ohare chip, on the combo ethernet/modem card */
+	if (machine_is_compatible("AAPL,3400/2400")
+	     || machine_is_compatible("AAPL,3500"))
+		enable_second_ohare();
+
 	/* disable all interrupts in all controllers */
 	for (i = 0; i * 32 < max_irqs; ++i)
 		out_le32(&pmac_irq_hw[i]->enable, 0);
@@ -346,11 +408,11 @@
 			(int)second_irq);
 		if (device_is_compatible(irqctrler, "gatwick"))
 			pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-		for ( i = max_real_irqs ; i < max_irqs ; i++ )
-			irq_desc[i].ctl = &gatwick_pic;
 		request_irq( second_irq, gatwick_action, SA_INTERRUPT,
-			     "gatwick cascade", 0 );
+			     "interrupt cascade", 0 );
 	}
+	for (i = max_real_irqs; i < max_irqs; i++)
+		irq_desc[i].ctl = &gatwick_pic;
 	printk("System has %d possible interrupts\n", max_irqs);
 	if (max_irqs != max_real_irqs)
 		printk(KERN_DEBUG "%d interrupts on main controller\n",
@@ -381,6 +443,7 @@
 	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+	(void)in_le32(&pmac_irq_hw[0]->flag);
 	mb();
 }
 
@@ -392,6 +455,7 @@
 	out_le32(&pmac_irq_hw[0]->enable, 0);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, 0);
+	(void)in_le32(&pmac_irq_hw[0]->flag);
 	mb();
 	for (i = 0; i < max_real_irqs; ++i)
 		if (test_bit(i, sleep_save_mask))

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)