[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. */