summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips64/config.in8
-rw-r--r--arch/mips64/defconfig2
-rw-r--r--arch/mips64/defconfig-ip272
-rw-r--r--arch/mips64/kernel/traps.c42
-rw-r--r--arch/mips64/sgi-ip27/Makefile4
-rw-r--r--arch/mips64/sgi-ip27/ip27-berr.c101
-rw-r--r--arch/mips64/sgi-ip27/ip27-pci.c219
-rw-r--r--arch/mips64/sgi-ip27/ip27-setup.c18
-rw-r--r--include/asm-mips64/paccess.h92
9 files changed, 451 insertions, 37 deletions
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 85f28ad6e..ead24edff 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.5 1999/12/04 03:59:00 ralf Exp $
+# $Id: config.in,v 1.6 2000/01/17 23:32:46 ralf Exp $
#
# For a description of the syntax of this configuration file,
# see the Configure script.
@@ -20,6 +20,10 @@ if [ "$CONFIG_SGI_IP27" = "y" ]; then
fi
endmenu
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Symmetric Multi-Processing support' CONFIG_SMP
+fi
+
#
# Select some configuration options automatically based on user selections
#
@@ -30,6 +34,7 @@ unset CONFIG_ARC64
unset CONFIG_BOARD_SCACHE
unset CONFIG_COHERENT_IO
unset CONFIG_BINFMT_ELF32
+unset CONFIG_PCI
if [ "$CONFIG_SGI_IP22" = "y" ]; then
define_bool CONFIG_BOOT_ELF32 y
@@ -42,6 +47,7 @@ if [ "$CONFIG_SGI_IP27" = "y" ]; then
define_bool CONFIG_BOOT_ELF64 y
define_bool CONFIG_ARC64 y
define_bool CONFIG_COHERENT_IO y
+ define_bool CONFIG_PCI y
fi
mainmenu_option next_comment
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index e96745afc..0261dd61c 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -16,6 +16,7 @@ CONFIG_SGI_IP27=y
CONFIG_BOOT_ELF64=y
CONFIG_ARC64=y
CONFIG_COHERENT_IO=y
+CONFIG_PCI=y
#
# CPU selection
@@ -55,6 +56,7 @@ CONFIG_BINFMT_ELF=y
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_CPQ_DA is not set
#
# Additional Block Devices
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index e96745afc..0261dd61c 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -16,6 +16,7 @@ CONFIG_SGI_IP27=y
CONFIG_BOOT_ELF64=y
CONFIG_ARC64=y
CONFIG_COHERENT_IO=y
+CONFIG_PCI=y
#
# CPU selection
@@ -55,6 +56,7 @@ CONFIG_BINFMT_ELF=y
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_CPQ_DA is not set
#
# Additional Block Devices
diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c
index edb24201b..825562342 100644
--- a/arch/mips64/kernel/traps.c
+++ b/arch/mips64/kernel/traps.c
@@ -64,9 +64,6 @@ char dedicated_iv_available = 0;
char vce_available = 0;
char mips4_available = 0;
-void (*ibe_board_handler)(struct pt_regs *regs);
-void (*dbe_board_handler)(struct pt_regs *regs);
-
int kstack_depth_to_print = 24;
/*
@@ -198,26 +195,6 @@ void die_if_kernel(const char * str, struct pt_regs * regs, unsigned long err)
die(str, regs, err);
}
-static void default_be_board_handler(struct pt_regs *regs)
-{
- /*
- * Assume it would be too dangerous to continue ...
- */
- force_sig(SIGBUS, current);
-}
-
-void do_ibe(struct pt_regs *regs)
-{
-show_regs(regs); while(1);
- ibe_board_handler(regs);
-}
-
-void do_dbe(struct pt_regs *regs)
-{
-show_regs(regs); while(1);
- dbe_board_handler(regs);
-}
-
void do_ov(struct pt_regs *regs)
{
if (compute_return_epc(regs))
@@ -396,11 +373,12 @@ void do_watch(struct pt_regs *regs)
void do_reserved(struct pt_regs *regs)
{
/*
- * Game over - no way to handle this if it ever occurs.
- * Most probably caused by a new unknown cpu type or
- * after another deadly hard/software error.
+ * Game over - no way to handle this if it ever occurs. Most probably
+ * caused by a new unknown cpu type or after another deadly
+ * hard/software error.
*/
- panic("Caught reserved exception - should not happen.");
+ panic("Caught reserved exception %d - should not happen.",
+ (regs->cp0_cause & 0x1f) >> 2);
}
static inline void watch_init(unsigned long cputype)
@@ -485,6 +463,7 @@ void __init trap_init(void)
extern char __xtlb_refill_debug_tramp;
extern char except_vec2_generic;
extern char except_vec3_generic, except_vec3_r4000;
+ extern void bus_error_init(void);
unsigned long i;
/* Some firmware leaves the BEV flag set, clear it. */
@@ -557,13 +536,8 @@ r4k:
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
- /*
- * The following two are signaled by onboard hardware and
- * should get board specific handlers to get maximum
- * available information.
- */
- set_except_vector(6, handle_ibe);
- set_except_vector(7, handle_dbe);
+ /* DBE / IBE exception handler are system specific. */
+ bus_error_init();
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
diff --git a/arch/mips64/sgi-ip27/Makefile b/arch/mips64/sgi-ip27/Makefile
index 46fbe0b5c..37d2c0700 100644
--- a/arch/mips64/sgi-ip27/Makefile
+++ b/arch/mips64/sgi-ip27/Makefile
@@ -9,7 +9,7 @@
$(CC) $(CFLAGS) -c $< -o $*.o
L_TARGET = ip27.a
-L_OBJS = ip27-irq.o ip27-irq-glue.o ip27-klconfig.o ip27-memory.o \
- ip27-reset.o ip27-setup.o ip27-timer.o
+L_OBJS = ip27-berr.o ip27-irq.o ip27-irq-glue.o ip27-klconfig.o \
+ ip27-memory.o ip27-pci.o ip27-reset.o ip27-setup.o ip27-timer.o
include $(TOPDIR)/Rules.make
diff --git a/arch/mips64/sgi-ip27/ip27-berr.c b/arch/mips64/sgi-ip27/ip27-berr.c
new file mode 100644
index 000000000..b4b594baa
--- /dev/null
+++ b/arch/mips64/sgi-ip27/ip27-berr.c
@@ -0,0 +1,101 @@
+/* $Id: ip27-berr.c,v 1.1 2000/01/20 22:50:29 ralf Exp $
+ *
+ * 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.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/sn0/hub.h>
+#include <asm/uaccess.h>
+
+extern asmlinkage void handle_ibe(void);
+extern asmlinkage void handle_dbe(void);
+
+extern const struct exception_table_entry __start___dbe_table[];
+extern const struct exception_table_entry __stop___dbe_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->nextinsn;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+ return 0;
+}
+
+static inline unsigned long
+search_dbe_table(unsigned long addr)
+{
+ unsigned long ret;
+
+ /* There is only the kernel to search. */
+ ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr);
+ if (ret) return ret;
+
+ return 0;
+}
+
+void do_ibe(struct pt_regs *regs)
+{
+ printk("Got ibe at 0x%lx\n", regs->cp0_epc);
+ show_regs(regs);
+ dump_tlb_addr(regs->cp0_epc);
+ force_sig(SIGBUS, current);
+ while(1);
+}
+
+void do_dbe(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ fixup = search_dbe_table(regs->cp0_epc);
+ if (fixup) {
+ long new_epc;
+
+ new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
+ regs->cp0_epc = new_epc;
+ return;
+ }
+
+ printk("Got dbe at 0x%lx\n", regs->cp0_epc);
+ show_regs(regs);
+ dump_tlb_all();
+ while(1);
+ force_sig(SIGBUS, current);
+}
+
+void __init
+bus_error_init(void)
+{
+ /* XXX Initialize all the Hub & Bridge error handling here. */
+ int cpu = LOCAL_HUB_L(PI_CPU_NUM);
+ int cpuoff = cpu << 8;
+
+ set_except_vector(6, handle_ibe);
+ set_except_vector(7, handle_dbe);
+
+ LOCAL_HUB_S(PI_ERR_INT_PEND,
+ cpu ? PI_ERR_CLEAR_ALL_A : PI_ERR_CLEAR_ALL_B);
+ LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0);
+ LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0);
+ LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); /* Disable error stack */
+ LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
+}
diff --git a/arch/mips64/sgi-ip27/ip27-pci.c b/arch/mips64/sgi-ip27/ip27-pci.c
new file mode 100644
index 000000000..13c2630c9
--- /dev/null
+++ b/arch/mips64/sgi-ip27/ip27-pci.c
@@ -0,0 +1,219 @@
+/* $Id: ip27-pci.c,v 1.1 2000/01/20 22:50:29 ralf Exp $
+ *
+ * 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.
+ *
+ * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/sn/arch.h>
+#include <asm/pci/bridge.h>
+#include <asm/paccess.h>
+
+/*
+ * The Bridge ASIC supports both type 0 and type 1 access. Type 1 is
+ * not really documented, so right now I can't write code which uses it.
+ * Therefore we use type 0 accesses for now even though they won't work
+ * correcly for PCI-to-PCI bridges.
+ */
+#define CF0_READ_PCI_CFG(dev,where,value,bm,mask) \
+do { \
+ bridge_t *bridge = (bridge_t *) 0x9200000008000000; \
+ int slot = PCI_SLOT(dev->devfn); \
+ int fn = PCI_FUNC(dev->devfn); \
+ volatile u32 *addr; \
+ u32 cf, __bit; \
+ \
+ if (dev->bus->number) \
+ return PCIBIOS_DEVICE_NOT_FOUND; \
+ \
+ __bit = (((where) & (bm)) << 3); \
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \
+ if (get_dbe(cf, addr)) \
+ return PCIBIOS_DEVICE_NOT_FOUND; \
+ *value = (cf >> __bit) & (mask); \
+ return PCIBIOS_SUCCESSFUL; \
+} while (0)
+
+static int
+pci_conf0_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ CF0_READ_PCI_CFG(dev,where,value,3,0xff);
+}
+
+static int
+pci_conf0_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+ CF0_READ_PCI_CFG(dev,where,value,2,0xffff);
+}
+
+static int
+pci_conf0_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ CF0_READ_PCI_CFG(dev,where,value,0,0xffffffff);
+}
+
+#define CF0_WRITE_PCI_CFG(dev,where,value,bm,mask) \
+do { \
+ bridge_t *bridge = (bridge_t *) 0x9200000008000000; \
+ int slot = PCI_SLOT(dev->devfn); \
+ int fn = PCI_FUNC(dev->devfn); \
+ volatile u32 *addr; \
+ u32 cf, __bit; \
+ \
+ if (dev->bus->number) \
+ return PCIBIOS_DEVICE_NOT_FOUND; \
+ \
+ __bit = (((where) & (bm)) << 3); \
+ addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \
+ if (get_dbe(cf, addr)) \
+ return PCIBIOS_DEVICE_NOT_FOUND; \
+ cf &= (mask << __bit); \
+ cf |= ((value) << __bit); \
+ return PCIBIOS_SUCCESSFUL; \
+} while (0)
+
+static int
+pci_conf0_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+ CF0_WRITE_PCI_CFG(dev,where,value,3,0xff);
+}
+
+static int
+pci_conf0_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+ CF0_WRITE_PCI_CFG(dev,where,value,2,0xffff);
+}
+
+static int
+pci_conf0_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+ CF0_WRITE_PCI_CFG(dev,where,value,0,0xffffffff);
+}
+
+
+static struct pci_ops bridge_pci_ops = {
+ pci_conf0_read_config_byte,
+ pci_conf0_read_config_word,
+ pci_conf0_read_config_dword,
+ pci_conf0_write_config_byte,
+ pci_conf0_write_config_word,
+ pci_conf0_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+ struct pci_ops *ops = &bridge_pci_ops;
+ nasid_t nid = get_nasid();
+
+ /* Nothing to do for now. */
+ printk("%s called.\n", __FUNCTION__);
+
+ printk("PCI: Probing PCI hardware on host bus 0, node %d.\n", nid);
+ pci_scan_bus(0, ops, NULL);
+}
+
+static inline u8
+bridge_swizzle(u8 pin, u8 slot)
+{
+ return (((pin-1) + slot) % 4) + 1;
+}
+
+static u8 __init
+pci_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ u8 pin = *pinp;
+
+ while (dev->bus->self) { /* Move up the chain of bridges. */
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+ dev = dev->bus->self;
+ }
+ *pinp = pin;
+
+ return PCI_SLOT(dev->devfn);
+}
+
+/* XXX This should include the node ID into the final interrupt number. */
+static int __init
+pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return (slot + (((pin-1) & 1) << 2)) & 7;
+}
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ /* IOC3 is fucked ... */
+ if (dev->vendor == PCI_VENDOR_ID_SGI
+ && dev->device == PCI_DEVICE_ID_SGI_IOC3)
+ return;
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ unsigned long where, size;
+ u32 reg;
+
+ /* IOC3 is fucked ... */
+ if (dev->vendor == PCI_VENDOR_ID_SGI
+ && dev->device == PCI_DEVICE_ID_SGI_IOC3
+ && resource > 0)
+ return;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, &reg);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
+
+void __init
+pcibios_fixup_bus(struct pci_bus *b)
+{
+ /* Nothing to do for now. */
+ printk("%s called.\n", __FUNCTION__);
+ pci_fixup_irqs(pci_swizzle, pci_map_irq);
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+ /* Nothing to do for now. */
+
+ return str;
+}
+
+static void __init
+pci_fixup_ioc3(struct pci_dev *d)
+{
+ int i;
+
+ /* IOC3 only decodes 0x20 bytes of the config space, so we end up
+ with tons of bogus information in the pci_dev. On Origins the
+ INTA, INTB and INTC pins are all wired together as if it'd only
+ use INTA. */
+ printk("PCI: Fixing base addresses for device %s\n", d->slot_name);
+
+ for (i = 1; i <= PCI_ROM_RESOURCE; i++) {
+ d->resource[i].start = 0UL;
+ d->resource[i].end = 0UL;
+ d->resource[i].flags = 0UL;
+ }
+ d->subsystem_vendor = 0;
+ d->subsystem_device = 0;
+ d->irq = 1;
+}
+
+struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ pci_fixup_ioc3 },
+ { 0 }
+};
diff --git a/arch/mips64/sgi-ip27/ip27-setup.c b/arch/mips64/sgi-ip27/ip27-setup.c
index 52e3782dd..39858a23f 100644
--- a/arch/mips64/sgi-ip27/ip27-setup.c
+++ b/arch/mips64/sgi-ip27/ip27-setup.c
@@ -62,6 +62,23 @@ static inline void ioc3_eth_init(void)
ioc3->eier = 0;
}
+/* Try to catch kernel missconfigurations and give user an indication what
+ option to select. */
+static void __init verify_mode(void)
+{
+ int n_mode;
+
+ n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
+ printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
+#ifdef CONFIG_SGI_SN0_N_MODE
+ if (!n_mode)
+ panic("Kernel compiled for M mode.");
+#else
+ if (n_mode)
+ panic("Kernel compiled for N mode.");
+#endif
+}
+
void __init ip27_setup(void)
{
nasid_t nid;
@@ -83,6 +100,7 @@ void __init ip27_setup(void)
p ? "a" : "no",
e ? ", CPU is running" : "");
+ verify_mode();
ioc3_sio_init();
ioc3_eth_init();
}
diff --git a/include/asm-mips64/paccess.h b/include/asm-mips64/paccess.h
new file mode 100644
index 000000000..0b97674cf
--- /dev/null
+++ b/include/asm-mips64/paccess.h
@@ -0,0 +1,92 @@
+/* $Id: paccess.h,v 1.1 2000/01/20 22:50:32 ralf Exp $
+ *
+ * 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.
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ *
+ * Protected memory access. Used for everything that might take revenge
+ * by sending a DBE error like accessing possibly non-existant memory or
+ * devices.
+ */
+#ifndef _ASM_PACCESS_H
+#define _ASM_PACCESS_H
+
+#include <linux/errno.h>
+
+#define put_dbe(x,ptr) __put_dbe((x),(ptr),sizeof(*(ptr)))
+#define get_dbe(x,ptr) __get_dbe((x),(ptr),sizeof(*(ptr)))
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+#define __get_dbe(x,ptr,size) ({ \
+long __gu_err; \
+__typeof(*(ptr)) __gu_val; \
+long __gu_addr; \
+__asm__("":"=r" (__gu_val)); \
+__gu_addr = (long) (ptr); \
+__asm__("":"=r" (__gu_err)); \
+switch (size) { \
+case 1: __get_dbe_asm("lb"); break; \
+case 2: __get_dbe_asm("lh"); break; \
+case 4: __get_dbe_asm("lw"); break; \
+case 8: __get_dbe_asm("ld"); break; \
+default: __get_dbe_unknown(); break; \
+} x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
+
+#define __get_dbe_asm(insn) \
+({ \
+__asm__ __volatile__( \
+ "1:\t" insn "\t%1,%2\n\t" \
+ "move\t%0,$0\n" \
+ "2:\n\t" \
+ ".section\t.fixup,\"ax\"\n" \
+ "3:\tli\t%0,%3\n\t" \
+ "move\t%1,$0\n\t" \
+ "j\t2b\n\t" \
+ ".previous\n\t" \
+ ".section\t__dbe_table,\"a\"\n\t" \
+ ".dword\t1b,3b\n\t" \
+ ".previous" \
+ :"=r" (__gu_err), "=r" (__gu_val) \
+ :"o" (__m(__gu_addr)), "i" (-EFAULT)); })
+
+extern void __get_dbe_unknown(void);
+
+#define __put_dbe(x,ptr,size) ({ \
+long __pu_err; \
+__typeof__(*(ptr)) __pu_val; \
+long __pu_addr; \
+__pu_val = (x); \
+__pu_addr = (long) (ptr); \
+__asm__("":"=r" (__pu_err)); \
+switch (size) { \
+case 1: __put_dbe_asm("sb"); break; \
+case 2: __put_dbe_asm("sh"); break; \
+case 4: __put_dbe_asm("sw"); break; \
+case 8: __put_dbe_asm("sd"); break; \
+default: __put_dbe_unknown(); break; \
+} __pu_err; })
+
+#define __put_dbe_asm(insn) \
+({ \
+__asm__ __volatile__( \
+ "1:\t" insn "\t%1,%2\n\t" \
+ "move\t%0,$0\n" \
+ "2:\n\t" \
+ ".section\t.fixup,\"ax\"\n" \
+ "3:\tli\t%0,%3\n\t" \
+ "j\t2b\n\t" \
+ ".previous\n\t" \
+ ".section\t__dbe_table,\"a\"\n\t" \
+ ".dword\t1b,3b\n\t" \
+ ".previous" \
+ :"=r" (__pu_err) \
+ :"r" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
+
+extern void __put_dbe_unknown(void);
+
+#endif /* _ASM_PACCESS_H */