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)
{
|