[parisc-linux-cvs] Second tranche of EISA changes

Matthew Wilcox willy@ldl.fc.hp.com
Thu, 11 Oct 2001 18:09:50 -0600


 * -pa48
 * Stop reserving bus 0 for EISA in order to solve SuckyIO problems
 * Register drivers in the right order to make the Asp/Wax IRQ region
   available to the EISA driver; and make sure EISA claims its PCI
   bus before Dino does.
 * Fill in ->sibling links for Snake firmware machines.
 * Choose Asp subdevice IRQs by sversion rather than address (except for
   the serial ports... oh well :-)
 * Add an `irq' field to the parisc_device, and fill it in for Asp's
   children _and siblings_ because Mongoose is a sibling of Asp.
 * Short-circuit busdevice_alloc_irq if the irq field has been filled in.
 * The beginnings of irq support in eisa.c itself.  Note that this is
   far from complete and doesn't incorporate all the suggestions from
   Richard yet.

Index: arch/parisc/kernel/inventory.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/inventory.c,v
retrieving revision 1.40
diff -u -p -r1.40 inventory.c
--- arch/parisc/kernel/inventory.c	2001/10/06 19:17:02	1.40
+++ arch/parisc/kernel/inventory.c	2001/10/11 23:18:42
@@ -446,6 +446,7 @@ legacy_create_device(struct pdc_memory_m
 static int __init snake_inventory(void)
 {
 	int mod, num = 0;
+	struct parisc_device *prev = NULL;
 	for (mod = 0; mod < 16; mod++) {
 		struct parisc_device *dev;
 		struct pdc_module_path module_path;
@@ -457,10 +458,16 @@ static int __init snake_inventory(void)
 		dev = legacy_create_device(&r_addr, &module_path);
 		if (!dev)
 			continue;
+
 		num++;
+		if (prev) {
+			prev->sibling = dev;
+		}
 
-		if (dev->id.hw_type != HPHW_BA)
+		if (dev->id.hw_type != HPHW_BA) {
+			prev = dev;
 			continue;
+		}
 
 		memset(module_path.bc, 0xff, 4);
 		module_path.bc[4] = mod;
@@ -474,7 +481,14 @@ static int __init snake_inventory(void)
 				continue;
 			num++;
 			child->parent = dev;
+			if (!dev->child) {
+				dev->child = child;
+			} else {
+				prev->sibling = child;
+			}
+			prev = child;
 		}
+		prev = dev;
 	}
 
 	return num;
Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.38
diff -u -p -r1.38 lba_pci.c
--- arch/parisc/kernel/lba_pci.c	2001/10/10 20:10:10	1.38
+++ arch/parisc/kernel/lba_pci.c	2001/10/11 23:18:42
@@ -1487,7 +1487,7 @@ lba_init_iregs(void *sba_hpa, u32 ibase,
 	*/
 	DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask);
 
-	for (i = 1; i < pci_hba_count; i++) {
+	for (i = 0; i < pci_hba_count; i++) {
 		struct pci_hba_data *lba = &parisc_pci_hba[i];
 		DBG("%s() base_addr %p\n", __FUNCTION__, lba->base_addr);
 		WRITE_REG32( imask, lba->base_addr + LBA_IMASK);
Index: arch/parisc/kernel/pci.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/pci.c,v
retrieving revision 1.28
diff -u -p -r1.28 pci.c
--- arch/parisc/kernel/pci.c	2001/10/10 20:10:10	1.28
+++ arch/parisc/kernel/pci.c	2001/10/11 23:18:42
@@ -51,8 +51,7 @@ int pci_post_reset_delay = 50;
 struct pci_port_ops *pci_port;
 struct pci_bios_ops *pci_bios;
 
-/* NB: hba 0 is reserved for EISA */
-int pci_hba_count = 1;
+int pci_hba_count = 0;
 
 /*
 ** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.
@@ -75,8 +74,8 @@ struct pci_hba_data *parisc_pci_hba[PCI_
  */
 
 #ifdef CONFIG_EISA
-#define EISA_IN(size) if (b == 0) return eisa_in##size(addr)
-#define EISA_OUT(size) if (b == 0) return eisa_out##size(d, addr)
+#define EISA_IN(size) if (EISA_bus && (b == 0)) return eisa_in##size(addr)
+#define EISA_OUT(size) if (EISA_bus && (b == 0)) return eisa_out##size(d, addr)
 #else
 #define EISA_IN(size)
 #define EISA_OUT(size)
Index: arch/parisc/kernel/setup.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/setup.c,v
retrieving revision 1.92
diff -u -p -r1.92 setup.c
--- arch/parisc/kernel/setup.c	2001/10/10 20:10:10	1.92
+++ arch/parisc/kernel/setup.c	2001/10/11 23:18:42
@@ -208,16 +208,21 @@ void __init parisc_init(void)
 #if defined(CONFIG_IOMMU_CCIO)
 	ccio_init();
 #endif
-#if defined(CONFIG_GSC_DINO)
-	dino_init();
-#endif
-#ifdef CONFIG_EISA
-	eisa_init();
-#endif
 
+	/*
+	 * Need to register Asp & Wax before the EISA adapters for the IRQ
+	 * regions.  EISA must come before PCI to be sure it gets IRQ region
+	 * 0.
+	 */
 #if defined(CONFIG_GSC_LASI) || defined(CONFIG_GSC_DINO) \
 		|| defined(CONFIG_GSC_WAX)
 	busdevices_init();
+#endif
+#ifdef CONFIG_EISA
+	eisa_init();
+#endif
+#if defined(CONFIG_GSC_DINO)
+	dino_init();
 #endif
 
 #ifdef CONFIG_CHASSIS_LCD_LED
Index: drivers/gsc/asp.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/gsc/asp.c,v
retrieving revision 1.11
diff -u -p -r1.11 asp.c
--- drivers/gsc/asp.c	2001/10/03 08:06:40	1.11
+++ drivers/gsc/asp.c	2001/10/11 23:18:42
@@ -13,6 +13,7 @@
 
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -33,30 +34,40 @@
 static int
 asp_find_irq(struct busdevice *busdev_dev, struct parisc_device *dev)
 {
-	int irq;
-	int off = dev->hpa & 0xffff;
+	int irq = 0;
 
-	/*
-	** "irq" bits below are numbered relative to most significant bit.
-	*/
-	switch (off) {
-	case 0x1000:	irq = 30; break; /* FIXME? (29,30 or 2 !)*/ /* HIL */
-	case 0x2000:	irq = 25; break; /* RS232 B */	
-	case 0x3000:	irq = 26; break; /* RS232 A */
-	case 0x4000:	irq = 24; break; /* Centronics/Parallel Port */
-	case 0x5000:	irq = 22; break; /* SCSI */
-	case 0x6000:	irq = 23; break; /* LAN */
-
-	case 0x0000:	irq = 18; break; /* Audio ??? */
-	case 0x9000:	irq = 18; break; /* Audio ??? */
-
-	case 0xF000:	irq = 17; break; /* ASP itself */
-	default: 	irq = -1; break; /* unknown */
+	switch (dev->id.sversion) {
+		case 0x71:	irq = 22; break; /* SCSI */
+		case 0x72:	irq = 23; break; /* LAN */
+		case 0x73:	irq = 30; break; /* HIL */
+		case 0x74:	irq = 24; break; /* Centronics */
+		case 0x75:	if ((dev->hpa & 0xffff) == 0x3000)
+					irq = 26; /* RS232 A */
+				else
+					irq = 25; /* RS232 B */
+				break;
+		case 0x76:	irq = 21; break; /* EISA BA */
+		case 0x77:	irq = 20; break; /* Graphics1 */
+		case 0x7a:	irq = 18; break; /* Audio (Bushmaster) */
+		case 0x7b:	irq = 18; break; /* Audio (Scorpio) */
+		case 0x7c:	irq = 28; break; /* FW SCSI */
+		case 0x7d:	irq = 27; break; /* FDDI */
+		case 0x7f:	irq = 18; break; /* Audio (Outfield) */
 	}
-
 	return irq;
 }
 
+static void fixup_bus(struct parisc_device *dev, int base)
+{
+	while (dev) {
+		int irq = asp_find_irq(NULL, dev);
+		if (irq) {
+			dev->irq = base + irq;
+		}
+		dev = dev->sibling;
+	}
+}
+
 int __init
 asp_init_chip(struct parisc_device *dev)
 {
@@ -101,7 +112,10 @@ asp_init_chip(struct parisc_device *dev)
 	ret = register_busdevice(dev, asp);
 	if (ret)
 		goto out;
-	
+
+	fixup_bus(dev->child, asp->busdev_region->data.irqbase);
+	fixup_bus(dev, asp->busdev_region->data.irqbase);
+
 	/* initialize the chassis LEDs */ 
 #ifdef CONFIG_CHASSIS_LCD_LED	
 	register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, 
Index: drivers/gsc/busdevice.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/gsc/busdevice.c,v
retrieving revision 1.26
diff -u -p -r1.26 busdevice.c
--- drivers/gsc/busdevice.c	2001/10/10 20:10:12	1.26
+++ drivers/gsc/busdevice.c	2001/10/11 23:18:42
@@ -53,6 +53,9 @@ int busdevice_alloc_irq(struct parisc_de
 	int	irq;
 	int hpa = dev->hpa;
 
+	if (dev->irq)
+		return dev->irq;
+
 	if (dev->parent) {
 		hpa = dev->parent->hpa;
 	}
Index: drivers/gsc/eisa.c
===================================================================
RCS file: /home/cvs/parisc/linux/drivers/gsc/eisa.c,v
retrieving revision 1.1
diff -u -p -r1.1 eisa.c
--- drivers/gsc/eisa.c	2001/10/10 20:10:12	1.1
+++ drivers/gsc/eisa.c	2001/10/11 23:18:42
@@ -9,7 +9,7 @@
  * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
  *
  * There are two distinct EISA adapters.  Mongoose is found in machines
- * up to the 712; then the Wax ASIC is used.  To complicate matters, the
+ * before the 712; then the Wax ASIC is used.  To complicate matters, the
  * Wax ASIC also includes a PS/2 and RS-232 controller, but those are
  * dealt with elsewhere; this file is concerned only with the EISA portions
  * of Wax.
@@ -17,9 +17,11 @@
 
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/sched.h>
 
 #include <asm/byteorder.h>
 #include <asm/gsc.h>
@@ -30,7 +32,8 @@
  * implementation can be flexed.
  */
 struct eisa_ba {
-	struct resource mem;
+	struct pci_hba_data	hba;
+	struct irq_region *region;
 } eisa_dev;
 
 /* Port ops */
@@ -84,21 +87,92 @@ void eisa_out32(u32 data, u16 port)
 		gsc_writel(cpu_to_le32(data), eisa_permute(port));
 }
 
+/* Interrupt handling */
+
+static void eisa_irq(int _, void *intr_dev, struct pt_regs *regs)
+{
+	extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
+	int irq = gsc_readb(0xfc01f000);
+
+	printk(KERN_DEBUG "EISA irq %d\n", irq);
+
+	do_irq(&eisa_dev.region->action[irq],
+			eisa_dev.region->data.irqbase + irq, regs);
+}
+
+static void eisa_disable_irq(void *irq_dev, int irq)
+{
+	return;
+}
+
+static void eisa_enable_irq(void *irq_dev, int irq)
+{
+	return;
+}
+
+static void eisa_mask_irq(void *irq_dev, int irq)
+{
+	return;
+}
+
+static void eisa_unmask_irq(void *irq_dev, int irq)
+{
+	return;
+}
+
+static struct irq_region_ops eisa_irq_ops = {
+	disable_irq:	eisa_disable_irq,
+	enable_irq:	eisa_enable_irq,
+	mask_irq:	eisa_mask_irq,
+	unmask_irq:	eisa_unmask_irq,
+};
+
+/* Device initialisation */
+
+#define is_mongoose(dev) (dev->id.sversion == 0x00076)
+
 static int __devinit eisa_probe(struct parisc_device *dev)
 {
-	int result;
-	char *name = (dev->id.sversion == 0x00076) ? "Mongoose" : "Wax";
+	int result, irq;
+	char *name = is_mongoose(dev) ? "Mongoose" : "Wax";
 
 	printk("%s EISA Adapter found at 0x%08lx\n", name, dev->hpa);
 
-	eisa_dev.mem.name = "EISA Bus";
-	eisa_dev.mem.start = 0xfc000000;
-	eisa_dev.mem.end = 0xffbfffff;
-	eisa_dev.mem.flags = IORESOURCE_MEM;
-	result = request_resource(&iomem_resource, &eisa_dev.mem);
+	eisa_dev.hba.lmmio_space.name = "EISA";
+	eisa_dev.hba.lmmio_space.start = 0xfc000000;
+	eisa_dev.hba.lmmio_space.end = 0xffbfffff;
+	eisa_dev.hba.lmmio_space.flags = IORESOURCE_MEM;
+	result = request_resource(&iomem_resource, &eisa_dev.hba.lmmio_space);
 	if (result < 0) {
 		printk(KERN_ERR "EISA: failed to claim EISA Bus address space!\n");
 		return result;
+	}
+	eisa_dev.hba.io_space.name = "EISA";
+	eisa_dev.hba.io_space.start = 0;
+	eisa_dev.hba.io_space.end = 0xffff;
+	eisa_dev.hba.lmmio_space.flags = IORESOURCE_IO;
+	result = request_resource(&ioport_resource, &eisa_dev.hba.io_space);
+	if (result < 0) {
+		printk(KERN_ERR "EISA: failed to claim EISA Bus port space!\n");
+		return result;
+	}
+	pcibios_register_hba(&eisa_dev.hba);
+
+	irq = busdevice_alloc_irq(dev);
+	if (!irq) {
+		printk(KERN_ERR "EISA: failed to claim IRQ\n");
+		return -ENODEV;
+	}
+	result = request_irq(irq, eisa_irq, 0, name, NULL);
+	if (result) {
+		printk(KERN_ERR "EISA: request_irq failed!\n");
+		return result;
+	}
+	eisa_dev.region = alloc_irq_region(8, &eisa_irq_ops,
+			IRQ_REG_MASK|IRQ_REG_DIS, name, NULL);
+	if (eisa_dev.region == NULL) {
+		printk(KERN_ERR "EISA: Couldn't allocate IRQ region\n");
+		return -ENODEV;
 	}
 
 	EISA_bus = 1;
Index: include/asm-parisc/hardware.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/hardware.h,v
retrieving revision 1.23
diff -u -p -r1.23 hardware.h
--- include/asm-parisc/hardware.h	2001/10/05 02:43:50	1.23
+++ include/asm-parisc/hardware.h	2001/10/11 23:18:43
@@ -29,6 +29,7 @@ struct parisc_device {
 	struct parisc_device *child;
 	struct parisc_driver *driver;	/* Driver for this device */
 	char name[80];			/* The hardware description */
+	int		irq;
 
 	unsigned int    hw_path;        /* The hardware path on the current bus */
 	unsigned int	num_addrs;	/* some devices have additional address ranges. */