[patch] GIO bus support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jun 26, 2002 at 03:07:13PM +0200, Maciej W. Rozycki wrote:
> On Wed, 26 Jun 2002, Ralf Baechle wrote:
> 
> > Certainly looks saner than what we're having right now.  Please apply.
> 
>  Done.

You rock Maciej (but Jun is right ;-)) So here it is. This patch introduces
basic support for GIO bus found SGI IP22 machines. I put it into
arch/mips/sgi-ip22/ directory rather than to drivers/gio/, because the
only machine with GIO bus supported by linux is Indy and Indigo2. GIO
devices are detected early - this allows to use gio_find_device() in
newport_con.c to make it more robust.

Here is proc listing (I have Newport XL in gfx slot):
ladis@indy:~$ cat /proc/gio
GIO devices found:
  Slot GFX, DeviceId 0x04
      BaseAddr 0x1f000000, MapSize 0x00400000

I'd like to hear optinion from someone more experienced to make it as
well parseable as possible - it will be used by XFree driver.

Please see ip22_baddr() function, i did my best, but it still looks
ungly :-(

	ladis

Following patch is generated against linux_2_4 brach a while ago

--- /dev/null	Mon Mar  4 10:32:31 2002
+++ linux/include/asm/sgi/sgigio.h	Wed Jun 26 02:12:23 2002
@@ -0,0 +1,69 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * sgigio.h: Definitions for GIO bus found on SGI IP22 (and others by linux
+ *           unsupported) machines.
+ *
+ * Copyright (C) 2002 Ladislav Michl
+ */
+#ifndef _ASM_SGI_SGIGIO_H
+#define _ASM_SGI_SGIGIO_H
+
+/*
+ * There is 10MB of GIO address space for GIO64 slot devices
+ * slot#   slot type address range            size
+ * -----   --------- ----------------------- -----
+ *   0     GFX       0x1f000000 - 0x1f3fffff   4MB
+ *   1     EXP0      0x1f400000 - 0x1f5fffff   2MB
+ *   2     EXP1      0x1f600000 - 0x1f9fffff   4MB
+ *
+ * There are un-slotted devices, HPC, I/O and misc devices, which are grouped 
+ * into the HPC address space.
+ *   -     MISC      0x1fb00000 - 0x1fbfffff   1MB
+ *      
+ * Following space is reserved and unused
+ *   -     RESERVED  0x18000000 - 0x1effffff 112MB
+ *
+ * The GIO specification tends to use slot numbers while the MC specification 
+ * tends to use slot types.
+ *
+ * slot0  - the "graphics" (GFX) slot but there is no requirement that 
+ *          a graphics dev may only use this slot
+ * slot1  - this is the "expansion"-slot 0 (EXP0), do not confuse with 
+ *          slot 0 (GFX).
+ * slot2  - this is the "expansion"-slot 1 (EXP1), do not confuse with 
+ *          slot 1 (EXP0).
+ */
+
+#define GIO_SLOT_GFX	0
+#define GIO_SLOT_GIO1	1
+#define GIO_SLOT_GIO2	2
+#define GIO_NUM_SLOTS	3
+
+#define GIO_ANY_ID	0xff
+
+#define GIO_VALID_ID_ONLY	0x01
+#define GIO_IFACE_64		0x02
+#define GIO_HAS_ROM		0x04
+
+struct gio_dev {
+	unsigned char	device;
+	unsigned char	revision;
+	unsigned short	vendor;
+	unsigned char	flags;
+
+	unsigned char	slot_number;
+	unsigned long	base_addr;
+	unsigned int	map_size;
+	
+	char		*name;
+	char		slot_name[5];
+};
+
+extern struct gio_dev* gio_find_device(unsigned char device, const struct gio_dev *from);
+
+extern void sgigio_init(void);
+
+#endif /* _ASM_SGI_SGIGIO_H */
--- /dev/null	Mon Mar  4 10:32:31 2002
+++ linux/arch/mips/sgi-ip22/ip22-gio.c	Wed Jun 26 02:11:01 2002
@@ -0,0 +1,152 @@
+/* 
+ * ip22-gio.c: Support for GIO64 bus (inspired by PCI code)
+ * 
+ * Copyright (C) 2002 Ladislav Michl
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/sgi/sgimc.h>
+#include <asm/sgi/sgigio.h>
+
+#define GIO_PIO_MAP_BASE	0x1f000000L
+#define GIO_PIO_MAP_SIZE	(16 * 1024*1024)
+
+#define GIO_ADDR_GFX		0x1f000000L
+#define GIO_ADDR_GIO1		0x1f400000L
+#define GIO_ADDR_GIO2		0x1f600000L
+
+#define GIO_GFX_MAP_SIZE	(4 * 1024*1024)
+#define GIO_GIO1_MAP_SIZE	(2 * 1024*1024)
+#define GIO_GIO2_MAP_SIZE	(4 * 1024*1024)
+
+#define GIO_NO_DEVICE		0x80
+
+static struct gio_dev gio_slot[GIO_NUM_SLOTS] = {
+	{
+		0,
+		0,
+		0,
+		GIO_NO_DEVICE,
+		GIO_SLOT_GFX,
+		GIO_ADDR_GFX,
+		GIO_GFX_MAP_SIZE,
+		NULL,
+		"GFX"
+	},
+	{
+		0,
+		0,
+		0,
+		GIO_NO_DEVICE,
+		GIO_SLOT_GIO1,
+		GIO_ADDR_GIO1,
+		GIO_GIO1_MAP_SIZE,
+		NULL,
+		"EXP0"
+	},
+	{
+		0,
+		0,
+		0,
+		GIO_NO_DEVICE,
+		GIO_SLOT_GIO2,
+		GIO_ADDR_GIO2,
+		GIO_GIO2_MAP_SIZE,
+		NULL,
+		"EXP1"
+	}
+};
+
+static int gio_read_proc(char *buf, char **start, off_t off,
+			 int count, int *eof, void *data)
+{
+	int i;
+	char *p = buf;
+	
+	p += sprintf(p, "GIO devices found:\n");
+	for (i = 0; i < GIO_NUM_SLOTS; i++) {
+		if (gio_slot[i].flags & GIO_NO_DEVICE)
+			continue;
+		p += sprintf(p, "  Slot %s, DeviceId 0x%02x\n",
+			     gio_slot[i].slot_name, gio_slot[i].device);
+		p += sprintf(p, "    BaseAddr 0x%08lx, MapSize 0x%08x\n",
+			     gio_slot[i].base_addr, gio_slot[i].map_size);
+	}
+	
+	return p - buf;
+}
+
+void create_gio_proc_entry(void)
+{
+	create_proc_read_entry("gio", 0, NULL, gio_read_proc, NULL);
+}
+
+/**
+ * gio_find_device - begin or continue searching for a GIO device by device id
+ * @device: GIO device id to match, or %GIO_ANY_ID to match all device ids
+ * @from: Previous GIO device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known GIO devices. If a GIO device is found
+ * with a matching @device, a pointer to its device structure is returned. 
+ * Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device.
+ */
+struct gio_dev *
+gio_find_device(unsigned char device, const struct gio_dev *from)
+{
+	int i;
+	
+	for (i = (from) ? from->slot_number : 0; i < GIO_NUM_SLOTS; i++)
+		if (!(gio_slot[i].flags & GIO_NO_DEVICE) && 
+		   (device == GIO_ANY_ID || device == gio_slot[i].device))
+			return &gio_slot[i];
+	
+	return NULL;
+}
+
+#define GIO_IDCODE(x)		(x & 0x7f)
+#define GIO_ALL_BITS_VALID	0x80
+#define GIO_REV(x)		((x >> 8) & 0xff)
+#define GIO_GIO_SIZE_64		0x10000
+#define GIO_ROM_PRESENT		0x20000
+#define GIO_VENDOR_CODE(x)	((x >> 18) & 0x3fff)
+
+extern int ip22_baddr(unsigned int *val, unsigned long addr);
+
+/** 
+ * sgigio_init - scan the GIO space and figure out what hardware is actually
+ * present.
+ */
+void __init sgigio_init(void)
+{
+	unsigned int i, id, found = 0;
+
+	printk("GIO: Scanning for GIO cards...\n");
+	for (i = 0; i < GIO_NUM_SLOTS; i++) {
+		if (ip22_baddr(&id, KSEG1ADDR(gio_slot[i].base_addr)))
+			continue;
+
+		found = 1;
+		gio_slot[i].device = GIO_IDCODE(id);
+		if (id & GIO_ALL_BITS_VALID) {
+			gio_slot[i].revision = GIO_REV(id);
+			gio_slot[i].vendor = GIO_VENDOR_CODE(id);
+			gio_slot[i].flags =
+				(id & GIO_GIO_SIZE_64) ? GIO_IFACE_64 : 0 |
+				(id & GIO_ROM_PRESENT) ? GIO_HAS_ROM : 0;
+		} else
+			gio_slot[i].flags = GIO_VALID_ID_ONLY;
+
+		printk("GIO: Card 0x%02x @ 0x%08lx\n", gio_slot[i].device,
+			gio_slot[i].base_addr);
+	}
+	
+	if (!found)
+		printk("GIO: No GIO cards present.\n");
+}
--- /dev/null	Mon Mar  4 10:32:31 2002
+++ linux/arch/mips/sgi-ip22/ip22-berr.c	Wed Jun 26 02:06:56 2002
@@ -0,0 +1,78 @@
+/*
+ * ip22-berr.c: Bus error handling.
+ *
+ * Copyright (C) 2002 Ladislav Michl
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/branch.h>
+#include <asm/sgi/sgimc.h>
+#include <asm/sgi/sgihpc.h>
+
+unsigned int cpu_err_stat;	/* Status reg for CPU */
+unsigned int gio_err_stat;	/* Status reg for GIO */
+unsigned int cpu_err_addr;	/* Error address reg for CPU */
+unsigned int gio_err_addr;	/* Error address reg for GIO */
+
+volatile int nofault;
+
+static void save_and_clear_buserr(void)
+{
+	/* save memory controler's error status registers */ 
+	cpu_err_addr = mcmisc_regs->cerr;
+	cpu_err_stat = mcmisc_regs->cstat;
+	gio_err_addr = mcmisc_regs->gerr;
+	gio_err_stat = mcmisc_regs->gstat;
+
+	mcmisc_regs->cstat = mcmisc_regs->gstat = 0;
+}
+
+/*
+ * MC sends an interrupt whenever bus or parity errors occur. In addition, 
+ * if the error happened during a CPU read, it also asserts the bus error 
+ * pin on the R4K. Code in bus error handler save the MC bus error registers
+ * and then clear the interrupt when this happens.
+ */
+
+void be_ip22_interrupt(int irq, struct pt_regs *regs)
+{
+	save_and_clear_buserr();
+	printk(KERN_ALERT "Bus error, epc == %08lx, ra == %08lx\n",
+	       regs->cp0_epc, regs->regs[31]);
+	die_if_kernel("Oops", regs);
+	force_sig(SIGBUS, current);
+}
+
+int be_ip22_handler(struct pt_regs *regs, int is_fixup)
+{
+	save_and_clear_buserr();
+	if (nofault) {
+		nofault = 0;
+		compute_return_epc(regs);
+		return MIPS_BE_DISCARD;
+	}
+	return MIPS_BE_FIXUP;
+}
+
+int ip22_baddr(unsigned int *val, unsigned long addr)
+{
+	nofault = 1;
+	*val = *(volatile unsigned int *) addr;
+	__asm__ __volatile__("nop;nop;nop;nop");
+	if (nofault) {
+		nofault = 0;
+		return 0;
+	}
+	return -EFAULT;
+}
+
+void __init bus_error_init(void)
+{
+	be_board_handler = be_ip22_handler;
+}
Index: linux/arch/mips/sgi-ip22/ip22-int.c
===================================================================
RCS file: /cvs/linux/arch/mips/sgi-ip22/ip22-int.c,v
retrieving revision 1.2.2.2
diff -u -r1.2.2.2 ip22-int.c
--- linux/arch/mips/sgi-ip22/ip22-int.c	2002/06/26 11:48:54	1.2.2.2
+++ linux/arch/mips/sgi-ip22/ip22-int.c	2002/06/26 20:41:03
@@ -16,8 +16,8 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
-#include <asm/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
 #include <asm/gdb-stub.h>
@@ -279,6 +279,8 @@
 	return;	
 }
 
+extern void be_ip22_interrupt(int irq, struct pt_regs *regs);
+
 void indy_buserror_irq(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
@@ -286,9 +288,7 @@
 
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
-	die("Got a bus error IRQ, shouldn't happen yet\n", regs);
-	printk("Spinning...\n");
-	while(1);
+	be_ip22_interrupt(irq, regs);
 	irq_exit(cpu, irq);
 }
 
@@ -305,9 +305,8 @@
 	{ no_action, SA_INTERRUPT, 0, "mappable1 cascade", NULL, NULL };
 #endif
 
-extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
-extern void mips_cpu_irq_init(u32 irq_base);
-	
+extern void mips_cpu_irq_init(unsigned int irq_base);
+
 void __init init_IRQ(void)
 {
 	int i;
Index: linux/arch/mips/sgi-ip22/ip22-mc.c
===================================================================
RCS file: /cvs/linux/arch/mips/sgi-ip22/ip22-mc.c,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 ip22-mc.c
--- linux/arch/mips/sgi-ip22/ip22-mc.c	2002/06/26 11:44:49	1.1.2.2
+++ linux/arch/mips/sgi-ip22/ip22-mc.c	2002/06/26 20:42:55
@@ -4,20 +4,21 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
  */
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 
 #include <asm/addrspace.h>
 #include <asm/ptrace.h>
+#include <asm/sgialib.h>
 #include <asm/sgi/sgimc.h>
 #include <asm/sgi/sgihpc.h>
-#include <asm/sgialib.h>
 
 /* #define DEBUG_SGIMC */
 
 struct sgimc_misc_ctrl *mcmisc_regs;
-u32 *rpsscounter;
 struct sgimc_dma_ctrl *dmactrlregs;
+u32 *rpsscounter;
 
 static inline char *mconfig_string(unsigned long val)
 {
@@ -42,7 +43,7 @@
 
 	default:
 		return "wheee, unknown";
-	};
+	}
 }
 
 void __init sgimc_init(void)
@@ -50,8 +51,8 @@
 	unsigned long tmpreg;
 
 	mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
-	rpsscounter = (unsigned int *) (KSEG1 + 0x1fa01004);
-	dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000);
+	rpsscounter = (unsigned int *)(KSEG1+0x1fa01004);
+	dmactrlregs = (struct sgimc_dma_ctrl *)(KSEG1+0x1fa02000);
 
 	printk(KERN_INFO "MC: SGI memory controller Revision %d\n",
 	       (int) mcmisc_regs->systemid & SGIMC_SYSID_MASKREV);
@@ -81,7 +82,7 @@
 	/* Place the MC into a known state.  This must be done before
 	 * interrupts are first enabled etc.
 	 */
-
+	
 	/* Step 0: Make sure we turn off the watchdog in case it's
 	 *         still running (which might be the case after a
 	 *         soft reboot).
@@ -137,7 +138,7 @@
 	 *       revision on this machine.  You have been warned.
 	 */
 
-	/* First the basic invariants across all gio64 implementations. */
+	/* First the basic invariants across all GIO64 implementations. */
 	tmpreg = SGIMC_GIOPARM_HPC64;    /* All 1st HPC's interface at 64bits. */
 	tmpreg |= SGIMC_GIOPARM_ONEBUS;  /* Only one physical GIO bus exists. */
 
Index: linux/arch/mips/sgi-ip22/ip22-time.c
===================================================================
RCS file: /cvs/linux/arch/mips/sgi-ip22/ip22-time.c,v
retrieving revision 1.1.2.6
diff -u -r1.1.2.6 ip22-time.c
--- linux/arch/mips/sgi-ip22/ip22-time.c	2002/06/26 11:44:49	1.1.2.6
+++ linux/arch/mips/sgi-ip22/ip22-time.c	2002/06/26 20:47:22
@@ -20,6 +20,7 @@
 #include <asm/ds1286.h>
 #include <asm/sgialib.h>
 #include <asm/sgi/sgint23.h>
+#include <asm/sgi/sgigio.h>
 #include <asm/time.h>
 
 /*
@@ -179,6 +180,14 @@
 		(int) (r4k_tick / 5000), (int) (r4k_tick % 5000) / 50);
 
 	mips_counter_frequency = r4k_tick * HZ;	
+	
+	/* HACK ALERT! This get's called after traps initialization
+	 * We piggyback the initialization of GIO bus here even though
+	 * it is technically not related with the timer in any way.
+	 * Doing it from ip22_setup wouldn't work since traps aren't 
+	 * initialized yet.
+	 */
+	sgigio_init();
 }
 
 /* Generic SGI handler for (spurious) 8254 interrupts */
Index: linux/arch/mips/sgi-ip22/ip22-setup.c
===================================================================
RCS file: /cvs/linux/arch/mips/sgi-ip22/ip22-setup.c,v
retrieving revision 1.1.2.9
diff -u -r1.1.2.9 ip22-setup.c
--- linux/arch/mips/sgi-ip22/ip22-setup.c	2002/06/26 12:22:42	1.1.2.9
+++ linux/arch/mips/sgi-ip22/ip22-setup.c	2002/06/26 20:49:01
@@ -46,6 +46,7 @@
 extern struct rtc_ops indy_rtc_ops;
 extern void indy_reboot_setup(void);
 extern void sgi_volume_set(unsigned char);
+extern void create_gio_proc_entry(void);
 
 #define sgi_kh ((struct hpc_keyb *) &(hpc3mregs->kbdmouse0))
 
@@ -61,12 +62,18 @@
 static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *))
 {
 	/* Dirty hack, this get's called as a callback from the keyboard
-	   driver.  We piggyback the initialization of the front panel
-	   button handling on it even though they're technically not
-	   related with the keyboard driver in any way.  Doing it from
-	   indy_setup wouldn't work since kmalloc isn't initialized yet.  */
+	 * driver.  We piggyback the initialization of the front panel
+	 * button handling on it even though they're technically not
+	 * related with the keyboard driver in any way.  Doing it from
+	 * ip22_setup wouldn't work since kmalloc isn't initialized yet.
+	 */
 	indy_reboot_setup();
 
+	/* Ehm, well... once David used hack above, let's add yet another.
+	 * Register GIO bus proc entry here.
+	 */
+	create_gio_proc_entry();
+
 	return request_irq(SGI_KEYBD_IRQ, handler, 0, "keyboard", NULL);
 }
 
@@ -123,10 +130,6 @@
 	sgi_write_command,
 	sgi_read_status
 };
-
-void __init bus_error_init(void)
-{
-}
 
 void __init ip22_setup(void)
 {

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux