linux-mips
[Top] [All Lists]

patch to support the EISA bus on the Indigo2

To: Linux SGI <linux@cthulhu.engr.sgi.com>
Subject: patch to support the EISA bus on the Indigo2
From: "Andrew R. Baker" <andrewb@uab.edu>
Date: Thu, 26 Aug 1999 16:17:46 -0500 (CDT)
Sender: owner-linux@cthulhu.engr.sgi.com
Here is my initial patch for adding EISA support on the Indigo2.  It has
allowed me to get an ISA Etherlink III running in my Indigo2 with a couple
of changes to the driver.  Several things have yet to be done:  I have not
looked into DMA support;  Interrupts on the EISA bus are not reported via
/proc;  "make config" won't allow you to select any (E)ISA bus network
drivers;  I have not looked at irq probing either.  Also, remember that
many drivers will not work on the Indigo2 because they were written with
only little endian architectures in mind.

Things I want some input on:

1)  Should the #ifdefs for making the support optional be put somewhere
      else, it looks clunky in "indy_int.c".  I thought about putting it
      in i8259.h by creating stubs if support is not supposed to compiled
      in.

2)  Where in the /proc/interrupts output should the (E)ISA interrupts go?
      They have a range from 0-15.  They could be interleaved with the
      current set with an [EISA] tag.  Any opinions?


-Andrew

P.S.  This goes against the 2.2 branch of the CVS tree.
--- linux/include/asm-mips/i8259.h.orig Thu Aug 26 15:29:50 1999
+++ linux/include/asm-mips/i8259.h      Wed Aug 25 17:34:46 1999
@@ -0,0 +1,26 @@
+/* 
+ * sgieisa.h: Defines for the (E)ISA bus on the SGI Indigo2
+ *
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
+ *
+ */
+#ifndef _MIPS_SGIEISA_H
+#define _MIPS_SGIEISA_H
+
+#ifdef CONFIG_SGI_EISA
+extern void i8259_disable_irq(unsigned int);
+extern void i8259_enable_irq(unsigned int);
+extern int i8259_request_irq(unsigned int irq,
+                            void (*handler)(int, void *, struct pt_regs *),
+                            unsigned long flags,
+                            const char *device,
+                            void *dev_id);
+
+extern void i8259_free_irq(unsigned int irq, void *dev_id);
+
+extern void i8259_do_irq(int, struct pt_regs *);
+
+extern void i8259_init(void);
+#endif /* CONFIG_SGI_EISA */
+
+#endif /* !(_MIPS_SGIEISA_H) */
--- linux/include/asm-mips/sgieisa.h.orig       Thu Aug 26 15:25:15 1999
+++ linux/include/asm-mips/sgieisa.h    Thu Aug 26 16:07:36 1999
@@ -0,0 +1,32 @@
+/* 
+ * sgieisa.h: Defines for the (E)ISA bus on the SGI Indigo2
+ *
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
+ *
+ */
+#ifndef _MIPS_SGIEISA_H
+#define _MIPS_SGIEISA_H
+
+#define SGI_EISA_BASE 0x00080000
+
+/* EIU registers */
+#define SGI_EIU_BASE 0x0009ffc0
+
+struct sgi_eiu_regs {
+       volatile unsigned long mode;
+       volatile unsigned long status;
+       volatile unsigned long prempt;
+       volatile unsigned long quiet;
+};
+
+
+#define SGI_EISA_NMI_BASE 0x00080461
+
+struct sgi_eisa_nmi_regs { 
+       volatile unsigned char reset;
+       volatile unsigned char port;
+};
+
+extern void sgi_eisa_init(void);
+
+#endif /* !(_MIPS_SGIEISA_H) */
--- linux/include/asm-mips/sgint23.h.orig       Thu Aug 26 15:29:12 1999
+++ linux/include/asm-mips/sgint23.h    Thu Aug 26 15:28:54 1999
@@ -2,7 +2,9 @@
  * sgint23.h: Defines for the SGI INT2 and INT3 chipsets.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - INT2 corrections
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
+ *             - INT2 corrections
+ *             - EISA additions
  */
 #ifndef _MIPS_SGINT23_H
 #define _MIPS_SGINT23_H
@@ -12,13 +14,14 @@
  * that particular IRQ on an SGI machine.  Add new 'spaces' as new
  * IRQ hardware is supported.
  */
-#define SGINT_LOCAL0   0   /* INDY has 8 local0 irq levels */
-#define SGINT_LOCAL1   8   /* INDY has 8 local1 irq levels */
-#define SGINT_LOCAL2   16  /* INDY has 8 local2 vectored irq levels */
-#define SGINT_LOCAL3   24  /* INDY has 8 local3 vectored irq levels */
-#define SGINT_GIO      32  /* INDY has 9 GIO irq levels */
-#define SGINT_HPCDMA   41  /* INDY has 11 HPCDMA irq _sources_ */
-#define SGINT_END      52  /* End of 'spaces' */
+#define SGINT_EISA     0   /* Indigo2 has EISA interrupts 0-15 */  
+#define SGINT_LOCAL0   16  /* INDY has 8 local0 irq levels */
+#define SGINT_LOCAL1   24  /* INDY has 8 local1 irq levels */
+#define SGINT_LOCAL2   32  /* INDY has 8 local2 vectored irq levels */
+#define SGINT_LOCAL3   40  /* INDY has 8 local3 vectored irq levels */
+#define SGINT_GIO      48  /* INDY has 9 GIO irq levels */
+#define SGINT_HPCDMA   57  /* INDY has 11 HPCDMA irq _sources_ */
+#define SGINT_END      68  /* End of 'spaces' */
 
 /* Individual interrupt definitions for the INDY and Indigo2
  */
--- linux/init/main.c.orig      Thu Aug 26 15:44:48 1999
+++ linux/init/main.c   Tue Aug 24 12:25:46 1999
@@ -97,6 +97,10 @@
 extern void ecard_init(void);
 #endif
 
+#ifdef CONFIG_SGI_EISA
+extern void sgi_eisa_init(void);
+#endif
+
 extern void smp_setup(char *str, int *ints);
 #ifdef __i386__
 extern void ioapic_pirq_setup(char *str, int *ints);
@@ -878,6 +882,7 @@
 };
 
 static struct kernel_param raw_params[] __initdata = {
+       { "OSLoadOptions=", root_dev_setup },
        { "root=", root_dev_setup },
 #ifdef CONFIG_ROOT_NFS
        { "nfsroot=", nfs_root_setup },
@@ -1303,6 +1308,10 @@
 #endif
 #ifdef CONFIG_TC
        tc_init();
+#endif
+       
+#if defined(CONFIG_SGI_EISA)
+       sgi_eisa_init();
 #endif
 
        /* Networking initialization needs a process context */ 
--- linux/arch/mips/config.in.orig      Thu Aug 26 15:43:07 1999
+++ linux/arch/mips/config.in   Thu Aug 26 15:43:17 1999
@@ -70,6 +70,9 @@
   fi
   bool '   Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
 fi
+if [ "$CONFIG_SGI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       bool 'SGI (E)ISA support (experimental)' CONFIG_SGI_EISA
+fi
 
 if [ "$CONFIG_DECSTATION" = "y" ]; then
   define_bool CONFIG_CPU_LITTLE_ENDIAN y
--- linux/arch/mips/sgi/kernel/Makefile.orig    Thu Aug 26 15:40:58 1999
+++ linux/arch/mips/sgi/kernel/Makefile Thu Aug 26 15:40:40 1999
@@ -15,8 +15,13 @@
 
 OBJS  = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \
         system.o indy_timer.o indyIRQ.o reset.o setup.o time.o
+
 ifdef CONFIG_SGI_PROM_CONSOLE
 OBJS += promcon.o
+endif
+
+ifdef CONFIG_SGI_EISA
+OBJS +=        eisa.o i8259.o
 endif
 
 all: sgikern.a
--- linux/arch/mips/sgi/kernel/indy_mc.c.orig   Thu Aug 26 15:37:05 1999
+++ linux/arch/mips/sgi/kernel/indy_mc.c        Thu Aug 26 16:09:08 1999
@@ -17,6 +17,8 @@
 
 /* #define DEBUG_SGIMC */
 
+extern int sgi_eisa_bus;
+
 struct sgimc_misc_ctrl *mcmisc_regs;
 unsigned long *rpsscounter;
 struct sgimc_dma_ctrl *dmactrlregs;
@@ -58,16 +60,16 @@
        printk("MC: SGI memory controller Revision %d\n",
               (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV);
 
-#if 0 /* XXX Until I figure out what this bit really indicates XXX */
+       /* XXX Until I figure out what this bit really indicates XXX */
+       /* it should indicate whether we have an (E)ISA bus or not -Andrew */
        /* XXX Is this systemid bit reliable? */
        if(mcmisc_regs->systemid & SGIMC_SYSID_EPRESENT) {
-               EISA_bus = 1;
+               sgi_eisa_bus = 1;
                printk("with EISA\n");
        } else {
-               EISA_bus = 0;
+               sgi_eisa_bus = 0;
                printk("no EISA\n");
        }
-#endif
 
 #ifdef DEBUG_SGIMC
        prom_printf("sgimc_init: memconfig0<%s> mconfig1<%s>\n",
--- linux/arch/mips/sgi/kernel/indy_int.c.orig  Thu Aug 26 15:38:41 1999
+++ linux/arch/mips/sgi/kernel/indy_int.c       Wed Aug 25 17:23:27 1999
@@ -8,6 +8,7 @@
  * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
  *                    - Indigo2 changes
  *                    - Interrupt handling fixes
+ *                    - EISA support
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -40,6 +41,10 @@
 #include <asm/sgialib.h>
 #include <asm/gdb-stub.h>
 
+#ifdef CONFIG_SGI_EISA
+  #include <asm/sgieisa.h>
+#endif
+
 /* #define DEBUG_SGINT */
 
 struct sgi_int2_regs *sgi_i2regs;
@@ -146,14 +151,20 @@
                printk("whee, invalid irq_nr %d\n", irq_nr);
                panic("IRQ, you lose...");
        }
-       if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
+       if(n >= SGINT_EISA && n < SGINT_LOCAL0) {
+#ifdef CONFIG_SGI_EISA
+               i8259_disable_irq(n - SGINT_EISA);
+#else
+               printk("No (E)ISA support.");
+#endif
+       } else if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
                disable_local_irq(n - SGINT_LOCAL0);
        } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) {
                disable_gio_irq(n - SGINT_GIO);
        } else if(n >= SGINT_HPCDMA && n < SGINT_END) {
                disable_hpcdma_irq(n - SGINT_HPCDMA);
        } else {
-               panic("how did I get here?");
+               panic("how did I get here? (%i)", irq_nr);
        }
 }
 
@@ -164,14 +175,20 @@
                printk("whee, invalid irq_nr %d\n", irq_nr);
                panic("IRQ, you lose...");
        }
-       if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
+       if(n >= SGINT_EISA && n < SGINT_LOCAL0) {
+#ifdef CONFIG_SGI_EISA
+               i8259_enable_irq(n - SGINT_EISA);
+#else
+               printk("No (E)ISA support.\n");
+#endif
+       } if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
                enable_local_irq(n - SGINT_LOCAL0);
        } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) {
                enable_gio_irq(n - SGINT_GIO);
        } else if(n >= SGINT_HPCDMA && n < SGINT_END) {
                enable_hpcdma_irq(n - SGINT_HPCDMA);
        } else {
-               panic("how did I get here?");
+               panic("how did I get here? (%i)", irq_nr);
        }
 }
 
@@ -355,6 +372,7 @@
        kfree(action);
 }
 
+
 int request_irq(unsigned int irq, 
                void (*handler)(int, void *, struct pt_regs *),
                unsigned long irqflags, 
@@ -368,7 +386,16 @@
                return -EINVAL;
        if (!handler)
                return -EINVAL;
-
+       
+       if((irq >= SGINT_EISA) && (irq < SGINT_LOCAL0))
+#ifdef CONFIG_SGI_EISA
+               return i8259_request_irq(irq, handler, irqflags, devname, 
dev_id);
+#else
+       {
+               printk("No (E)ISA support.");
+               return -EINVAL;
+       }
+#endif
        if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO))
                return request_local_irq(irq, handler, irqflags, devname, 
dev_id);
 
@@ -397,6 +424,14 @@
 
        if (irq >= SGINT_END) {
                printk("Trying to free IRQ%d\n",irq);
+               return;
+       }
+       if((irq >= SGINT_EISA) && (irq <SGINT_LOCAL0)) {
+#ifdef CONFIG_SGI_EISA
+               i8259_free_irq(irq, dev_id);
+#else
+               printk("No (E)ISA support.\n");
+#endif
                return;
        }
        if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO)) {
--- linux/arch/mips/sgi/kernel/i8259.c.orig     Thu Aug 26 15:36:30 1999
+++ linux/arch/mips/sgi/kernel/i8259.c  Thu Aug 26 15:48:33 1999
@@ -0,0 +1,253 @@
+/*
+ *
+ * i8259.c:  Generic support for the i8259 PIC
+ *
+ * Code copied from arch/mips/kernel/irq.c with minor changes.
+ *
+ *  This should really go into some architecture independent place
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/sgint23.h>
+#include <asm/i8259.h>
+
+/*
+ * This contains the irq mask for both 8259A irq controllers, it's an
+ * int so we can deal with the third PIC in some systems like the RM300.
+ */
+
+static unsigned int cached_irq_mask = 0xfffb;
+
+#define __byte(x,y) (((unsigned char *)&(y))[x])
+//#define __word(x,y) (((unsigned short *)&(y))[x])
+//#define __long(x,y) (((unsigned int *)&(y))[x])
+
+/* These are for big endian machines */
+#define cached_21       (__byte(3,cached_irq_mask))
+#define cached_A1       (__byte(2,cached_irq_mask))
+
+static struct irqaction *i8259_irq_action[16] = {
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static inline void i8259_mask_irq(unsigned int irq)
+{
+       cached_irq_mask |= 1 << irq;
+       if (irq & 8) {
+               outb(cached_A1, 0xa1);
+       } else {
+               outb(cached_21, 0x21);
+       }
+}
+
+static inline void i8259_unmask_irq(unsigned int irq)
+{
+        cached_irq_mask &= ~(1 << irq);
+        if (irq & 8) {
+               outb(cached_A1, 0xa1);
+        } else {
+               outb(cached_21, 0x21);
+       }
+}
+
+
+int i8259_setup_irq(int irq, struct irqaction * new)
+{
+       int shared = 0;
+       struct irqaction *old, **p;
+       unsigned long flags;
+
+       p = i8259_irq_action + irq;
+       if ((old = *p) != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & new->flags & SA_SHIRQ))
+                       return -EBUSY;
+
+               /* Can't share interrupts unless both are the same type */
+               if ((old->flags ^ new->flags) & SA_INTERRUPT)
+                       return -EBUSY;
+       
+               /* add new interrupt at end of irq queue */
+               do {
+                       p = & old->next;
+                       old = *p;
+               } while (old);
+               shared = 1;
+       }
+
+       if (new->flags & SA_SAMPLE_RANDOM)
+               rand_initialize_irq(irq);
+
+       save_and_cli(flags);
+       *p = new;
+
+       if (!shared) {
+               i8259_unmask_irq(irq);
+       }
+       restore_flags(flags);
+       return 0;
+}
+
+
+/* enable and disable for EISA irqs */
+
+void i8259_disable_irq(unsigned int irq_nr)
+{
+       unsigned long flags;
+
+       save_and_cli(flags);
+       i8259_mask_irq(irq_nr);
+       restore_flags(flags);
+}
+
+void i8259_enable_irq(unsigned int irq_nr)
+{
+       unsigned long flags;
+
+       save_and_cli(flags);
+       i8259_unmask_irq(irq_nr);
+       restore_flags(flags);
+}
+
+
+int i8259_request_irq(unsigned int irq, 
+                     void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, 
+                     const char *device, 
+                     void *dev_id)
+{
+       int retval;
+       struct irqaction *action;
+       
+       /* We only have 0-15 for (E)ISA irqs */
+       if (irq >= 16)
+               return -EINVAL;
+       if (!handler)
+               return -EINVAL;
+
+       action = (struct irqaction *)kmalloc(sizeof(struct irqaction), 
GFP_KERNEL);
+       if (!action)
+               return -ENOMEM;
+
+       action->handler = handler;
+       action->flags = flags;
+       action->mask = 0;
+       action->name = device;
+       action->next = NULL;
+       action->dev_id = dev_id;
+
+       retval = i8259_setup_irq(irq, action);
+
+       if (retval)
+               kfree(action);
+       return retval;
+}
+
+void i8259_free_irq(unsigned int irq, void *dev_id)
+{
+       struct irqaction *action, **p;
+       unsigned long flags;
+
+       if ( irq > 15) { 
+               printk("Trying to free (E)ISA IRQ%d\n", irq);
+               return;
+       }
+       for (p = irq + i8259_irq_action; (action = *p) != NULL; p = 
&action->next) {
+               if (action->dev_id != dev_id)
+                       continue;
+
+               /* Found it - now free it */
+               save_and_cli(flags);
+               *p = action->next;
+               if (!irq[i8259_irq_action])
+                       i8259_mask_irq(irq);
+               restore_flags(flags);
+               kfree(action);
+               return;
+       }
+       printk("Trying to free free (E)ISA IRQ%d\n", irq);
+}
+
+static inline void i8259_mask_and_ack_irq(int irq)
+{
+       cached_irq_mask |= 1 << irq;
+       if (irq & 8) {
+               inb(0xa1);
+               outb(cached_A1, 0xa1);
+               outb(0x62, 0x20);               /* Specific EOI to cascade */
+               outb(0x20, 0xa0);
+       } else {
+               inb(0x21);
+               outb(cached_21, 0x21);
+               outb(0x20, 0x20);
+       }
+}
+
+
+asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs)
+{
+       struct irqaction *action;
+       int do_random, cpu;
+
+       cpu = smp_processor_id();
+       hardirq_enter(cpu);
+
+       if (irq >= 16)
+               goto out;
+
+       i8259_mask_and_ack_irq(irq);
+
+       kstat.irqs[cpu][irq]++;
+
+       action = *(irq + i8259_irq_action);
+       if (!action)
+               goto out;
+
+       if (!(action->flags & SA_INTERRUPT))
+               __sti();
+       action = *(irq + i8259_irq_action);
+       do_random = 0;
+       do {
+               do_random |= action->flags;
+               action->handler(irq, action->dev_id, regs);
+               action = action->next;
+       } while (action);
+       if (do_random & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
+       __cli();
+       i8259_unmask_irq (irq);
+
+out:
+       hardirq_exit(cpu);
+}      
+
+__initfunc(void i8259_init(void))
+{
+       /* Init master interrupt controller */
+       outb(0x11, (0x20)); /* Start init sequence */
+       outb(0x00, (0x21)); /* Vector base */
+       outb(0x04, (0x21)); /* edge tiggered, Cascade (slave) on IRQ2 */
+       outb(0x01, (0x21)); /* Select 8086 mode */
+       outb(0xff, (0x21)); /* Mask all */
+
+       /* Init slave interrupt controller */
+       outb(0x11, (0xa0)); /* Start init sequence */
+       outb(0x08, (0xa1)); /* Vector base */
+       outb(0x02, (0xa1)); /* edge triggered, Cascade (slave) on IRQ2 */
+       outb(0x01, (0xa1)); /* Select 8086 mode */
+       outb(0xff, (0xa1)); /* Mask all */
+
+       outb(cached_A1, (0xa1));
+       outb(cached_21, (0x21));
+}
--- linux/arch/mips/sgi/kernel/eisa.c.orig      Thu Aug 26 15:36:24 1999
+++ linux/arch/mips/sgi/kernel/eisa.c   Thu Aug 26 16:12:04 1999
@@ -0,0 +1,70 @@
+/*
+ *
+ * eisa.c:  Support for the (E)ISA bus found on the Indigo2
+ *
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/sgint23.h>
+#include <asm/sgieisa.h>
+#include <asm/i8259.h>
+
+struct sgi_eiu_regs *sgi_eiu;
+int sgi_eisa_bus = 0;
+
+static void eisa_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+       /* which (E)ISA interrupt did we get? */
+       int eisa_irq = inb(0x10004);
+       /* find out which EISA irq we got and call i8259_do_irq */
+       i8259_do_irq(eisa_irq, regs);
+}
+
+void eisa_reset(void)
+{
+       int i;
+       outb(0x1, 0x461);
+       /* wait */
+       for (i = 0 ; i < 1000 ; i++)
+               ;
+       outb(0x0, 0x461);
+}
+
+
+__initfunc(void sgi_eisa_init(void))
+{
+       if(sgi_eisa_bus) 
+       {
+               printk("Initializing the (E)ISA subsystem.\n");
+
+               /* setup the EIU */
+               sgi_eiu = (struct sgi_eiu_regs *) (KSEG1 + SGI_EIU_BASE);
+               sgi_eiu->prempt = 0xffff;
+               sgi_eiu->quiet = 0x1;
+               sgi_eiu->mode = 0x40f3c07f;
+
+               /* set the I/O base */
+               mips_io_port_base = KSEG1 | SGI_EISA_BASE;
+
+               /* reset the bus */
+               eisa_reset();
+       
+               /* setup the i8259 interrupt controllers */
+               i8259_init();
+               
+               /* register the EISA bus interrupt handler */
+               request_irq(SGI_EISA_IRQ, eisa_int, 0, "EISA Bus", NULL);
+       }
+}
<Prev in Thread] Current Thread [Next in Thread>
  • patch to support the EISA bus on the Indigo2, Andrew R. Baker <=