diff options
-rw-r--r-- | arch/mips64/config.in | 8 | ||||
-rw-r--r-- | arch/mips64/defconfig | 2 | ||||
-rw-r--r-- | arch/mips64/defconfig-ip27 | 2 | ||||
-rw-r--r-- | arch/mips64/kernel/traps.c | 42 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/Makefile | 4 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-berr.c | 101 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-pci.c | 219 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-setup.c | 18 | ||||
-rw-r--r-- | include/asm-mips64/paccess.h | 92 |
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 & 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 */ |