diff options
Diffstat (limited to 'arch/alpha')
56 files changed, 9550 insertions, 7091 deletions
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index ff6e422df..d497ec3c8 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -10,36 +10,41 @@ NM := nm -B -#LINKFLAGS = -static -T arch/alpha/vmlinux.lds -#CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8 +LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N +CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8 -ifdef CONFIG_CROSSCOMPILE -# enable this for linking under OSF/1: -LINKFLAGS = -non_shared -T 0xfffffc0000310000 -N -else - elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi) - ifeq ($(elf),yes) -# LINKFLAGS = -static -Ttext 0xfffffc0000310000 -N -LINKFLAGS = -static -T arch/alpha/vmlinux.lds - else - LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N - endif -# GNU gcc/cc1/as can use pipes instead of temporary files -CFLAGS := $(CFLAGS) -pipe -endif +# Determine if we can use the BWX instructions with GAS. +old_gas := $(shell if $(AS) --version 2>&1 | grep 'version 2.7' > /dev/null; then echo y; else echo n; fi) -CFLAGS := $(CFLAGS) -mno-fp-regs -ffixed-8 -Wno-uninitialized +# Determine if GCC understands the -mcpu= option. +have_mcpu := $(shell if $(CC) -mcpu=ev5 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) + +# If GENERIC, make sure to turn off any instruction set extensions that +# the host compiler might have on by default. Given that EV4 and EV5 +# have the same instruction set, prefer EV5 because an EV5 schedule is +# more likely to keep an EV4 processor busy than vice-versa. +ifeq ($(CONFIG_ALPHA_GENERIC)$(have_mcpu),yy) + CFLAGS := $(CFLAGS) -mcpu=ev5 +endif -# determine if we can use the BWX instructions with GAS -$(shell rm -f ./GAS_VER) -$(shell $(AS) --version >& ./GAS_VER) -OLD_GAS := $(shell if cat ./GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi) -$(shell rm -f ./GAS_VER) +# If EV6, turn on the proper optimizations. +ifeq ($(CONFIG_ALPHA_EV6)$(have_mcpu),yy) + CFLAGS := $(CFLAGS) -mcpu=ev6 +endif -ifneq ($(OLD_GAS),yes) -# if PYXIS, then enable use of BWIO space +# For TSUNAMI, we must have the assembler not emulate our instructions. +# BWX is most important, but we don't really want any emulation ever. +ifeq ($(old_gas),y) + ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI),) + # How do we do #error in make? + CFLAGS := --error-please-upgrade-your-assembler + endif +else + ifeq ($(CONFIG_ALPHA_GENERIC),y) + CFLAGS := $(CFLAGS) -Wa,-mev6 + endif ifeq ($(CONFIG_ALPHA_PYXIS),y) - CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED + CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWIO_ENABLED endif endif @@ -61,7 +66,7 @@ rawboot: @$(MAKEBOOT) rawboot # -# my boot writes directly to a specific disk partition, I doubt most +# My boot writes directly to a specific disk partition, I doubt most # people will want to do that without changes.. # msb my-special-boot: @@ -76,6 +81,8 @@ srmboot: archclean: @$(MAKEBOOT) clean +archmrproper: + archdep: @$(MAKEBOOT) dep diff --git a/arch/alpha/config.in b/arch/alpha/config.in index fc2546218..9d0f5769e 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -4,15 +4,6 @@ # mainmenu_name "Kernel configuration of Linux for Alpha machines" -# clear all implied options (don't want default values for those): -unset CONFIG_CROSSCOMPILE CONFIG_NATIVE -unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 -unset CONFIG_PCI CONFIG_ALPHA_EISA -unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA -unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS -unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA -unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION - mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -31,6 +22,8 @@ endmenu mainmenu_option next_comment comment 'General setup' +unset CONFIG_CROSSCOMPILE CONFIG_NATIVE + if [ "`uname`" != "Linux" ]; then define_bool CONFIG_CROSSCOMPILE y else @@ -38,31 +31,44 @@ else fi choice 'Alpha system type' \ - "Avanti CONFIG_ALPHA_AVANTI \ - Alpha-XL CONFIG_ALPHA_XL \ - Alpha-XLT CONFIG_ALPHA_XLT \ - Cabriolet CONFIG_ALPHA_CABRIOLET \ - EB66 CONFIG_ALPHA_EB66 \ - EB66+ CONFIG_ALPHA_EB66P \ - EB64+ CONFIG_ALPHA_EB64P \ - EB164 CONFIG_ALPHA_EB164 \ - PC164 CONFIG_ALPHA_PC164 \ - LX164 CONFIG_ALPHA_LX164 \ - SX164 CONFIG_ALPHA_SX164 \ - DP264 CONFIG_ALPHA_DP264 \ - Jensen CONFIG_ALPHA_JENSEN \ - Noname CONFIG_ALPHA_NONAME \ - Takara CONFIG_ALPHA_TAKARA \ - Mikasa CONFIG_ALPHA_MIKASA \ - Noritake CONFIG_ALPHA_NORITAKE \ - Alcor CONFIG_ALPHA_ALCOR \ - Miata CONFIG_ALPHA_MIATA \ - Sable CONFIG_ALPHA_SABLE \ - Rawhide CONFIG_ALPHA_RAWHIDE \ - AlphaBook1 CONFIG_ALPHA_BOOK1 \ - Ruffian CONFIG_ALPHA_RUFFIAN \ - Platform2000 CONFIG_ALPHA_P2K" Cabriolet + "Generic CONFIG_ALPHA_GENERIC \ + Alcor/Alpha-XLT CONFIG_ALPHA_ALCOR \ + Alpha-XL CONFIG_ALPHA_XL \ + AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Avanti CONFIG_ALPHA_AVANTI \ + Cabriolet CONFIG_ALPHA_CABRIOLET \ + DP264 CONFIG_ALPHA_DP264 \ + EB164 CONFIG_ALPHA_EB164 \ + EB64+ CONFIG_ALPHA_EB64P \ + EB66 CONFIG_ALPHA_EB66 \ + EB66+ CONFIG_ALPHA_EB66P \ + Jensen CONFIG_ALPHA_JENSEN \ + LX164 CONFIG_ALPHA_LX164 \ + Miata CONFIG_ALPHA_MIATA \ + Mikasa CONFIG_ALPHA_MIKASA \ + Noname CONFIG_ALPHA_NONAME \ + Noritake CONFIG_ALPHA_NORITAKE \ + PC164 CONFIG_ALPHA_PC164 \ + Platform2000 CONFIG_ALPHA_P2K \ + Rawhide CONFIG_ALPHA_RAWHIDE \ + Ruffian CONFIG_ALPHA_RUFFIAN \ + SX164 CONFIG_ALPHA_SX164 \ + Sable CONFIG_ALPHA_SABLE \ + Takara CONFIG_ALPHA_TAKARA" Generic +# clear all implied options (don't want default values for those): +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 +unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA +unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS +unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA +unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION + +if [ "$CONFIG_ALPHA_GENERIC" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y +fi if [ "$CONFIG_ALPHA_BOOK1" = "y" ] then define_bool CONFIG_ALPHA_NONAME y @@ -172,10 +178,6 @@ fi #bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO if [ "$CONFIG_PCI" = "y" ]; then - bool 'TGA Console Support' CONFIG_TGA_CONSOLE -# if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then -# bool 'VGA Console Support' CONFIG_VGA_CONSOLE -# fi bool 'PCI quirks' CONFIG_PCI_QUIRKS if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE @@ -184,6 +186,7 @@ if [ "$CONFIG_PCI" = "y" ]; then fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF @@ -250,11 +253,23 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then fi endmenu +source drivers/char/Config.in + source fs/Config.in source fs/nls/Config.in -source drivers/char/Config.in +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE + bool 'Support for frame buffer devices' CONFIG_FB + if [ "$CONFIG_FB" = "y" ]; then + define_bool CONFIG_PCI_CONSOLE y + fi + source drivers/video/Config.in + endmenu +fi mainmenu_option next_comment comment 'Sound' @@ -269,10 +284,6 @@ mainmenu_option next_comment comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -bool 'Kernel profiling support' CONFIG_PROFILE -if [ "$CONFIG_PROFILE" = "y" ]; then - int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 -fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel FP software completion' CONFIG_MATHEMU else @@ -281,7 +292,3 @@ fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu - -if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then - define_bool CONFIG_VGA_CONSOLE y -fi diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 7d78e4b97..64a051c16 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -18,39 +18,37 @@ CONFIG_MODULES=y # General setup # CONFIG_NATIVE=y -# CONFIG_ALPHA_AVANTI is not set +CONFIG_ALPHA_GENERIC=y +# CONFIG_ALPHA_ALCOR is not set # CONFIG_ALPHA_XL is not set -# CONFIG_ALPHA_XLT is not set +# CONFIG_ALPHA_BOOK1 is not set +# CONFIG_ALPHA_AVANTI is not set # CONFIG_ALPHA_CABRIOLET is not set +# CONFIG_ALPHA_DP264 is not set +# CONFIG_ALPHA_EB164 is not set +# CONFIG_ALPHA_EB64P is not set # CONFIG_ALPHA_EB66 is not set # CONFIG_ALPHA_EB66P is not set -# CONFIG_ALPHA_EB64P is not set -# CONFIG_ALPHA_EB164 is not set -# CONFIG_ALPHA_PC164 is not set -# CONFIG_ALPHA_LX164 is not set -# CONFIG_ALPHA_SX164 is not set -# CONFIG_ALPHA_DP264 is not set # CONFIG_ALPHA_JENSEN is not set -# CONFIG_ALPHA_NONAME is not set -# CONFIG_ALPHA_TAKARA is not set +# CONFIG_ALPHA_LX164 is not set +# CONFIG_ALPHA_MIATA is not set # CONFIG_ALPHA_MIKASA is not set +# CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_NORITAKE is not set -CONFIG_ALPHA_ALCOR=y -# CONFIG_ALPHA_MIATA is not set -# CONFIG_ALPHA_SABLE is not set +# CONFIG_ALPHA_PC164 is not set +# CONFIG_ALPHA_P2K is not set # CONFIG_ALPHA_RAWHIDE is not set -# CONFIG_ALPHA_BOOK1 is not set # CONFIG_ALPHA_RUFFIAN is not set -# CONFIG_ALPHA_P2K is not set +# CONFIG_ALPHA_SX164 is not set +# CONFIG_ALPHA_SABLE is not set +# CONFIG_ALPHA_TAKARA is not set CONFIG_PCI=y -CONFIG_ALPHA_EV5=y -CONFIG_ALPHA_CIA=y -CONFIG_ALPHA_SRM=y -CONFIG_ALPHA_EISA=y -CONFIG_TGA_CONSOLE=y +CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y +# CONFIG_PCI_QUIRKS is not set CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y @@ -64,7 +62,7 @@ CONFIG_BINFMT_EM86=y # CONFIG_PNP is not set # -# Floppy, IDE, and other block devices +# Block devices # CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_IDE is not set @@ -78,6 +76,7 @@ CONFIG_BLK_DEV_FD=y # Additional Block Devices # # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set @@ -98,8 +97,6 @@ CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ACCT is not set -# CONFIG_IP_MASQUERADE is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set @@ -195,6 +192,8 @@ CONFIG_DE4X5=y # CONFIG_DEC_ELCP is not set # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set @@ -222,6 +221,38 @@ CONFIG_DE4X5=y # CONFIG_CD_NO_IDESCSI is not set # +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_MOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_UMISC is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_APM is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_NVRAM is not set +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -248,39 +279,15 @@ CONFIG_LOCKD=y # CONFIG_ROMFS_FS is not set # CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_MAC_PARTITION is not set # CONFIG_NLS is not set # -# Character devices +# Console drivers # -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_MOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set -# CONFIG_UMISC is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set -# CONFIG_JOYSTICK is not set -# CONFIG_MISC_RADIO is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set +CONFIG_VGA_CONSOLE=y +# CONFIG_FB is not set # # Sound @@ -290,6 +297,5 @@ CONFIG_PSMOUSE=y # # Kernel hacking # -# CONFIG_PROFILE is not set CONFIG_MATHEMU=y # CONFIG_MAGIC_SYSRQ is not set diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 8d09ea8c4..fcbb37615 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -20,34 +20,96 @@ O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ OX_OBJS := alpha_ksyms.o +ifdef CONFIG_ALPHA_GENERIC + +O_OBJS += core_apecs.o core_cia.o core_lca.o core_mcpcia.o core_pyxis.o \ + core_t2.o core_tsunami.o \ + sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o \ + sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \ + sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \ + sys_sx164.o sys_takara.o \ + es1888.o smc37c669.o smc37c93x.o +else + +# Core logic support ifdef CONFIG_ALPHA_APECS -O_OBJS += apecs.o +O_OBJS += core_apecs.o endif ifdef CONFIG_ALPHA_CIA -O_OBJS += cia.o +O_OBJS += core_cia.o endif ifdef CONFIG_ALPHA_LCA -O_OBJS += lca.o +O_OBJS += core_lca.o +endif +ifdef CONFIG_ALPHA_MCPCIA +O_OBJS += core_mcpcia.o endif ifdef CONFIG_ALPHA_PYXIS -O_OBJS += pyxis.o +O_OBJS += core_pyxis.o endif ifdef CONFIG_ALPHA_T2 -O_OBJS += t2.o +O_OBJS += core_t2.o endif ifdef CONFIG_ALPHA_TSUNAMI -O_OBJS += tsunami.o +O_OBJS += core_tsunami.o endif -ifdef CONFIG_ALPHA_MCPCIA -O_OBJS += mcpcia.o + +# Board support +ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) +O_OBJS += sys_alcor.o +endif +ifneq ($(CONFIG_ALPHA_CABRIOLET)$(CONFIG_ALPHA_EB164)$(CONFIG_ALPHA_EB66P)$(CONFIG_ALPHA_LX164)$(CONFIG_ALPHA_PC164),) +O_OBJS += sys_cabriolet.o +endif +ifdef CONFIG_ALPHA_DP264 +O_OBJS += sys_dp264.o +endif +ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),) +O_OBJS += sys_eb64p.o +endif +ifdef CONFIG_ALPHA_JENSEN +O_OBJS += sys_jensen.o +endif +ifdef CONFIG_ALPHA_MIATA +O_OBJS += sys_miata.o +endif +ifdef CONFIG_ALPHA_MIKASA +O_OBJS += sys_mikasa.o +endif +ifdef CONFIG_ALPHA_NORITAKE +O_OBJS += sys_noritake.o +endif +ifdef CONFIG_ALPHA_RAWHIDE +O_OBJS += sys_rawhide.o +endif +ifdef CONFIG_ALPHA_RUFFIAN +O_OBJS += sys_ruffian.o +endif +ifdef CONFIG_ALPHA_SABLE +O_OBJS += sys_sable.o +endif +ifneq ($(CONFIG_ALPHA_BOOK1)$(CONFIG_ALPHA_AVANTI)$(CONFIG_ALPHA_NONAME)$(CONFIG_ALPHA_P2K)$(CONFIG_ALPHA_XL),) +O_OBJS += sys_sio.o +endif +ifdef CONFIG_ALPHA_SX164 +O_OBJS += sys_sx164.o +endif +ifdef CONFIG_ALPHA_TAKARA +O_OBJS += sys_takara.o endif -ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn) -O_OBJS += smc37c93x.o +# Device support +ifdef CONFIG_ALPHA_MIATA +O_OBJS += es1888.o endif -ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),nnn) +ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),) O_OBJS += smc37c669.o endif +ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),) +O_OBJS += smc37c93x.o +endif + +endif # GENERIC ifdef SMP O_OBJS += smp.o @@ -55,9 +117,4 @@ endif all: kernel.o head.o -head.o: head.s - -head.s: head.S $(TOPDIR)/include/asm-alpha/system.h - $(CPP) -traditional $(AFLAGS) -o $*.s $< - include $(TOPDIR)/Rules.make diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index c220ccdc6..a7047dd1f 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -14,6 +14,7 @@ #include <linux/in.h> #include <linux/in6.h> #include <linux/pci.h> +#include <linux/tty.h> #include <asm/io.h> #include <asm/hwrpb.h> @@ -23,6 +24,8 @@ #include <linux/interrupt.h> #include <asm/softirq.h> #include <asm/fpu.h> +#include <asm/irq.h> +#include <asm/machvec.h> #define __KERNEL_SYSCALLS__ #include <asm/unistd.h> @@ -41,8 +44,12 @@ extern void __remlu (void); extern void __divqu (void); extern void __remqu (void); +EXPORT_SYMBOL(alpha_mv); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(screen_info); /* platform dependent support */ EXPORT_SYMBOL(_inb); @@ -59,7 +66,7 @@ EXPORT_SYMBOL(_writew); EXPORT_SYMBOL(_writel); EXPORT_SYMBOL(_memcpy_fromio); EXPORT_SYMBOL(_memcpy_toio); -EXPORT_SYMBOL(_memset_io); +EXPORT_SYMBOL(_memset_c_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); @@ -82,6 +89,7 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); +EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); EXPORT_SYMBOL(dump_thread); @@ -115,7 +123,9 @@ EXPORT_SYMBOL(csum_ipv6_magic); #ifdef CONFIG_MATHEMU_MODULE extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +extern long (*alpha_fp_emul) (unsigned long pc); EXPORT_SYMBOL(alpha_fp_emul_imprecise); +EXPORT_SYMBOL(alpha_fp_emul); #endif /* diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 64c7442b6..633273954 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -29,9 +29,17 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <asm/pci.h> #include <asm/dma.h> -#if 0 +#include "proto.h" +#include "bios32.h" + +#define DEBUG_DEVS 0 + +#if DEBUG_DEVS # define DBG_DEVS(args) printk args #else # define DBG_DEVS(args) @@ -39,174 +47,290 @@ #ifndef CONFIG_PCI -int pcibios_present(void) +asmlinkage int sys_pciconfig_read() { return -ENOSYS; } +asmlinkage int sys_pciconfig_write() { return -ENOSYS; } +void reset_for_srm(void) { } + +#else /* CONFIG_PCI */ + +#include <linux/malloc.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/segment.h> +#include <asm/system.h> + +/* + * PCI public interfaces. + */ + +#define MAJOR_REV 0 +#define MINOR_REV 4 /* minor revision 4, add multi-PCI handling */ + + +int +pcibios_present(void) { - return 0; + return alpha_mv.pci_read_config_byte != NULL; } -asmlinkage int sys_pciconfig_read() +void __init +pcibios_init(void) { - return -ENOSYS; + printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + if (alpha_use_srm_setup) + printk(" NOT modifying existing (SRM) PCI configuration\n"); + + /* FIXME: Scan for multiple PCI busses here. */ } -asmlinkage int sys_pciconfig_write() +char * __init +pcibios_setup(char *str) { - return -ENOSYS; + return str; } -#else /* CONFIG_PCI */ +void __init +pcibios_fixup(void) +{ + alpha_mv.pci_fixup(); +} -#include <linux/pci.h> -#include <linux/malloc.h> -#include <linux/mm.h> +void __init +pcibios_fixup_bus(struct pci_bus *bus) +{ +} -#include <asm/hwrpb.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/segment.h> -#include <asm/system.h> +int +pcibios_read_config_byte (u8 bus, u8 dev, u8 where, u8 *value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_read_config_byte) + r = alpha_mv.pci_read_config_byte(bus, dev, where, value); + return r; +} +int +pcibios_read_config_word (u8 bus, u8 dev, u8 where, u16 *value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_read_config_word) + r = alpha_mv.pci_read_config_word(bus, dev, where, value); + return r; +} -#define KB 1024 -#define MB (1024*KB) -#define GB (1024*MB) +int +pcibios_read_config_dword (u8 bus, u8 dev, u8 where, u32 *value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_read_config_dword) + r = alpha_mv.pci_read_config_dword(bus, dev, where, value); + return r; +} -#define MAJOR_REV 0 +int +pcibios_write_config_byte (u8 bus, u8 dev, u8 where, u8 value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_write_config_byte) + r = alpha_mv.pci_write_config_byte(bus, dev, where, value); + return r; +} -/* minor revision 4, add multi-PCI handling */ -#define MINOR_REV 4 +int +pcibios_write_config_word (u8 bus, u8 dev, u8 where, u16 value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_write_config_word) + r = alpha_mv.pci_write_config_word(bus, dev, where, value); + return r; +} -/* - * Align VAL to ALIGN, which must be a power of two. - */ -#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) +int +pcibios_write_config_dword (u8 bus, u8 dev, u8 where, u32 value) +{ + int r = PCIBIOS_FUNC_NOT_SUPPORTED; + if (alpha_mv.pci_write_config_dword) + r = alpha_mv.pci_write_config_dword(bus, dev, where, value); + return r; +} +asmlinkage int +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; -#if defined(CONFIG_ALPHA_MCPCIA) || defined(CONFIG_ALPHA_TSUNAMI) -/* multiple PCI bus machines */ -/* make handle from bus number */ -extern struct linux_hose_info *bus2hose[256]; -#define HANDLE(b) (((unsigned long)(bus2hose[(b)]->pci_hose_index)&3)<<32) -#define DEV_IS_ON_PRIMARY(dev) \ - (bus2hose[(dev)->bus->number]->pci_first_busno == (dev)->bus->number) -#else /* MCPCIA || TSUNAMI */ -#define HANDLE(b) (0) -#define DEV_IS_ON_PRIMARY(dev) ((dev)->bus->number == 0) -#endif /* MCPCIA || TSUNAMI */ -/* - * PCI_MODIFY - * - * Temporary internal macro. If this 0, then do not write to any of - * the PCI registers, merely read them (i.e., use configuration as - * determined by SRM). The SRM seem do be doing a less than perfect - * job in configuring PCI devices, so for now we do it ourselves. - * Reconfiguring PCI devices breaks console (RPB) callbacks, but - * those don't work properly with 64 bit addresses anyways. - * - * The accepted convention seems to be that the console (POST - * software) should fully configure boot devices and configure the - * interrupt routing of *all* devices. In particular, the base - * addresses of non-boot devices need not be initialized. For - * example, on the AXPpci33 board, the base address a #9 GXE PCI - * graphics card reads as zero (this may, however, be due to a bug in - * the graphics card---there have been some rumor that the #9 BIOS - * incorrectly resets that address to 0...). - */ -#ifdef CONFIG_ALPHA_SRM_SETUP -#define PCI_MODIFY 0 -static struct pci_dev *irq_dev_to_reset[16]; -static unsigned char irq_to_reset[16]; -static int irq_reset_count = 0; -static struct pci_dev *io_dev_to_reset[16]; -static unsigned char io_reg_to_reset[16]; -static unsigned int io_to_reset[16]; -static int io_reset_count = 0; -#else /* SRM_SETUP */ -#define PCI_MODIFY 1 -#endif /* SRM_SETUP */ - -extern struct hwrpb_struct *hwrpb; - -/* Forward declarations for some extra fixup routines for specific hardware. */ -#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) -extern int SMC93x_Init(void); -#endif -extern int SMC669_Init(void); -#ifdef CONFIG_ALPHA_MIATA -static int es1888_init(void); -#endif + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + lock_kernel(); + switch (len) { + case 1: + err = pcibios_read_config_byte(bus, dfn, off, &ubyte); + if (err != PCIBIOS_SUCCESSFUL) + ubyte = 0xff; + put_user(ubyte, buf); + break; + case 2: + err = pcibios_read_config_word(bus, dfn, off, &ushort); + if (err != PCIBIOS_SUCCESSFUL) + ushort = 0xffff; + put_user(ushort, (unsigned short *)buf); + break; + case 4: + err = pcibios_read_config_dword(bus, dfn, off, &uint); + if (err != PCIBIOS_SUCCESSFUL) + uint = 0xffffffff; + put_user(uint, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + } + unlock_kernel(); + return err; +} -#if PCI_MODIFY +asmlinkage int +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + lock_kernel(); + switch (len) { + case 1: + err = get_user(ubyte, buf); + if (err) + break; + err = pcibios_write_config_byte(bus, dfn, off, ubyte); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 2: + err = get_user(ushort, (unsigned short *)buf); + if (err) + break; + err = pcibios_write_config_word(bus, dfn, off, ushort); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 4: + err = get_user(uint, (unsigned int *)buf); + if (err) + break; + err = pcibios_write_config_dword(bus, dfn, off, uint); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + default: + err = -EINVAL; + break; + } + unlock_kernel(); + return err; +} -/* - * NOTE: we can't just blindly use 64K for machines with EISA busses; they - * may also have PCI-PCI bridges present, and then we'd configure the bridge - * incorrectly. - * - * Also, we start at 0x8000 or 0x9000, in hopes to get all devices' - * IO space areas allocated *before* 0xC000; this is because certain - * BIOSes (Millennium for one) use PCI Config space "mechanism #2" - * accesses to probe the bus. If a device's registers appear at 0xC000, - * it may see an INx/OUTx at that address during BIOS emulation of the - * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense. - * - * Note that we may need this stuff for SRM_SETUP also, since certain - * SRM consoles screw up and allocate I/O space addresses > 64K behind - * PCI-to_PCI bridges, which can't pass I/O addresses larger than 64K, AFAIK. - */ -#if defined(CONFIG_ALPHA_EISA) -#define DEFAULT_IO_BASE 0x9000 /* start above 8th slot */ -#else -#define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */ -#endif -static unsigned int io_base; -#if defined(CONFIG_ALPHA_XL) /* - * An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address - * that get passed through the PCI<->ISA bridge chip. Although this causes - * us to set the PCI->Mem window bases lower than normal, we still allocate - * PCI bus devices' memory addresses *below* the low DMA mapping window, - * and hope they fit below 64Mb (to avoid conflicts), and so that they can - * be accessed via SPARSE space. - * - * We accept the risk that a broken Myrinet card will be put into a true XL - * and thus can more easily run into the problem described below. + * Gory details start here... */ -#define DEFAULT_MEM_BASE (16*MB + 2*MB) /* 16M to 64M-1 is avail */ -#elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS) +struct linux_hose_info *bus2hose[256]; + /* - * We try to make this address *always* have more than 1 bit set. - * this is so that devices like the broken Myrinet card will always have - * a PCI memory address that will never match a IDSEL address in - * PCI Config space, which can cause problems with early rev cards. - * - * However, APECS and LCA have only 34 bits for physical addresses, thus - * limiting PCI bus memory addresses for SPARSE access to be less than 128Mb. + * Align VAL to ALIGN, which must be a power of two. */ -#define DEFAULT_MEM_BASE (64*MB + 2*MB) +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) -#else -/* - * We try to make this address *always* have more than 1 bit set. - * this is so that devices like the broken Myrinet card will always have - * a PCI memory address that will never match a IDSEL address in - * PCI Config space, which can cause problems with early rev cards. - * - * Because CIA and PYXIS and T2 have more bits for physical addresses, - * they support an expanded range of SPARSE memory addresses. + +/* + * The following structure records initial configuration of devices + * so that we can reset them on shutdown and so enable clean reboots + * on SRM. It is more trouble than it iw worth to conditionalize this. */ -#define DEFAULT_MEM_BASE (128*MB + 16*MB) +static struct { + struct reset_irq { + struct pci_dev *dev; + u8 irq; + } irq[16]; + int irq_count; + + struct reset_io { + struct pci_dev *dev; + u8 reg; + u32 io; + } io[16]; + int io_count; +} srm_resets; + +/* Apply the collected reset modifications. */ + +void +reset_for_srm(void) +{ + struct pci_dev *dev; + int i; + + /* Reset any IRQs that we changed. */ + for (i = 0; i < srm_resets.irq_count; i++) { + dev = srm_resets.irq[i].dev; + + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, + srm_resets.irq[i].irq); +#if 1 + printk("reset_for_srm: bus %d slot 0x%x " + "SRM IRQ 0x%x changed back from 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + srm_resets.irq[i].irq, dev->irq); #endif -static unsigned int mem_base; + } + + /* Reset any IO addresses that we changed. */ + for (i = 0; i < srm_resets.io_count; i++) { + dev = srm_resets.io[i].dev; + + pcibios_write_config_byte(dev->bus->number, dev->devfn, + srm_resets.io[i].reg, + srm_resets.io[i].io); +#if 1 + printk("reset_for_srm: bus %d slot 0x%x " + "SRM IO restored to 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + srm_resets.io[i].io); +#endif + } +} + /* * Disable PCI device DEV so that it does not respond to I/O or memory * accesses. */ -static void disable_dev(struct pci_dev *dev) +static void __init +disable_dev(struct pci_dev *dev) { struct pci_bus *bus; unsigned short cmd; @@ -217,12 +341,20 @@ static void disable_dev(struct pci_dev *dev) */ if (dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_82375) { + dev->class = PCI_CLASS_BRIDGE_EISA; DBG_DEVS(("disable_dev: ignoring PCEB...\n")); return; } + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82378) { + dev->class = PCI_CLASS_BRIDGE_ISA; + DBG_DEVS(("disable_dev: ignoring SIO...\n")); + return; + } + /* - * we don't have code that will init the CYPRESS bridge correctly + * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous * console code to do the right thing, and ignore it here... :-\ */ @@ -232,6 +364,19 @@ static void disable_dev(struct pci_dev *dev) return; } +#if DEBUG_DEVS && 0 + /* Worse HACK: Don't disable the video card, so I can see where + it is *really* falling over. */ + if (dev->class >> 16 == PCI_BASE_CLASS_DISPLAY) { + DBG_DEVS(("disable_dev: ignoring video card %04x:%04x\n", + dev->vendor, dev->device)); + return; + } +#endif + + DBG_DEVS(("disable_dev: disabling %04x:%04x\n", + dev->vendor, dev->device)); + bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -246,7 +391,11 @@ static void disable_dev(struct pci_dev *dev) */ #define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) -static void layout_dev(struct pci_dev *dev) +static unsigned int io_base; +static unsigned int mem_base; + +static void __init +layout_dev(struct pci_dev *dev) { struct pci_bus *bus; unsigned short cmd; @@ -260,12 +409,20 @@ static void layout_dev(struct pci_dev *dev) */ if (dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_82375) { + dev->class = PCI_CLASS_BRIDGE_EISA; DBG_DEVS(("layout_dev: ignoring PCEB...\n")); return; } + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82378) { + dev->class = PCI_CLASS_BRIDGE_ISA; + DBG_DEVS(("layout_dev: ignoring SIO...\n")); + return; + } + /* - * we don't have code that will init the CYPRESS bridge correctly + * We don't have code that will init the CYPRESS bridge correctly * so we do the next best thing, and depend on the previous * console code to do the right thing, and ignore it here... :-\ */ @@ -324,7 +481,7 @@ static void layout_dev(struct pci_dev *dev) pcibios_write_config_dword(bus->number, dev->devfn, off, base | 0x1); - handle = HANDLE(bus->number) | base | 1; + handle = PCI_HANDLE(bus->number) | base | 1; dev->base_address[idx] = handle; DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%lx (0x%x)\n", @@ -375,7 +532,7 @@ static void layout_dev(struct pci_dev *dev) * * In sparse memory address space, the first * octant (16MB) of every 128MB segment is - * aliased to the the very first 16MB of the + * aliased to the very first 16 MB of the * address space (i.e., it aliases the ISA * memory address space). Thus, we try to * avoid allocating PCI devices in that range. @@ -409,7 +566,7 @@ static void layout_dev(struct pci_dev *dev) mem_base = base + size; pcibios_write_config_dword(bus->number, dev->devfn, off, base); - handle = HANDLE(bus->number) | base; + handle = PCI_HANDLE(bus->number) | base; dev->base_address[idx] = handle; DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n", dev->device, handle, size)); @@ -440,8 +597,8 @@ static void layout_dev(struct pci_dev *dev) dev->device, dev->class, cmd|PCI_COMMAND_MASTER)); } - -static int layout_bus(struct pci_bus *bus) +static int __init +layout_bus(struct pci_bus *bus) { unsigned int l, tio, bio, tmem, bmem; struct pci_bus *child; @@ -552,24 +709,44 @@ static int layout_bus(struct pci_bus *bus) return found_vga; } -#endif /* !PCI_MODIFY */ - - -int pcibios_present(void) +void __init +layout_all_busses(unsigned long default_io_base, + unsigned long default_mem_base) { - return 1; -} + struct pci_bus *cur; +#if defined(CONFIG_ALPHA_GENERIC) + static struct linux_hose_info dummy_hose; + int i; -void __init -pcibios_init(void) -{ - printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); -#if !PCI_MODIFY - printk("...NOT modifying existing (SRM) PCI configuration\n"); + /* + * HACK: Emulate a multi-bus machine to a limited extent + * by initializing bus2hose to point to something that + * has pci_hose_index & pci_first_busno zero. + */ + for (i = 0; i <= 0xff; i++) + bus2hose[i] = &dummy_hose; #endif + + /* + * Scan the tree, allocating PCI memory and I/O space. + */ + /* + * Sigh; check_region() will need changing to accept a PCI_HANDLE, + * if we allocate I/O space addresses on a per-bus basis. + * For now, make the I/O bases unique across all busses, so + * that check_region() will not get confused... ;-} + */ + io_base = default_io_base; + for (cur = &pci_root; cur; cur = cur->next) { + mem_base = default_mem_base; + DBG_DEVS(("layout_all_busses: calling layout_bus()\n")); + layout_bus(cur); + } + DBG_DEVS(("layout_all_busses: done.\n")); } + /* * The SRM console *disables* the IDE interface, this code ensures it's * enabled. @@ -584,7 +761,9 @@ pcibios_init(void) * written twice (I believe this is a safety feature to prevent * accidental modification---fun, isn't it?). */ -static inline void enable_ide(long ide_base) + +void __init +enable_ide(long ide_base) { int data; @@ -595,68 +774,29 @@ static inline void enable_ide(long ide_base) outb(data | 0x40, ide_base+1); /* turn on IDE, really! */ } -/* - * A small note about bridges and interrupts. The DECchip 21050 (and later) - * adheres to the PCI-PCI bridge specification. This says that the - * interrupts on the other side of a bridge are swizzled in the following - * manner: - * - * Dev Interrupt Interrupt - * Pin on Pin on - * Device Connector - * - * 4 A A - * B B - * C C - * D D - * - * 5 A B - * B C - * C D - * D A - * - * 6 A C - * B D - * C A - * D B - * - * 7 A D - * B A - * C B - * D C - * - * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. - * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 - * - * The following code is somewhat simplistic as it assumes only one bridge. - * I will fix it later (david.rusling@reo.mts.dec.com). - */ -static inline unsigned char -bridge_swizzle(unsigned char pin, unsigned int slot) -{ - /* swizzle */ - return (((pin-1) + slot) % 4) + 1; -} - -#ifdef CONFIG_ALPHA_SRM_SETUP -/* look for mis-configured devices' I/O space addresses behind bridges */ -static void check_behind_io(struct pci_dev *dev) +/* Look for mis-configured devices' I/O space addresses behind bridges. */ +static void +check_behind_io(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; unsigned int reg, orig_base, new_base, found_one = 0; + struct reset_io *ior; for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { - /* read the current setting, check for I/O space and >= 64K */ - pcibios_read_config_dword(bus->number, dev->devfn, reg, &orig_base); + /* Read the current setting, check for I/O space and >= 64K */ + pcibios_read_config_dword(bus->number, dev->devfn, + reg, &orig_base); + if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO)) continue; /* unused or non-IO */ + if (orig_base < 64*1024) { #if 1 printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n", bus->number, PCI_SLOT(dev->devfn), orig_base); #endif if (orig_base & ~1) - continue; /* OK! */ + continue; /* OK! */ orig_base = 0x12001; /* HACK! FIXME!! */ } @@ -671,1160 +811,148 @@ printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n", pcibios_write_config_dword(bus->number, dev->devfn, reg, new_base); - io_dev_to_reset[io_reset_count] = dev; - io_reg_to_reset[io_reset_count] = reg; - io_to_reset[io_reset_count] = orig_base; - io_reset_count++; + ior = &srm_resets.io[srm_resets.io_count++]; + ior->dev = dev; + ior->reg = reg; + ior->io = orig_base; found_one++; - } /* end for-loop */ + } - /* if any were modified, gotta hack the bridge IO limits too... */ + /* If any were modified, gotta hack the bridge IO limits too. */ if (found_one) { - if (bus->self) { - struct pci_dev *bridge = bus->self; - unsigned int l; - /* - * Set up the top and bottom of the PCI I/O segment - * for this bus. - */ - pcibios_read_config_dword(bridge->bus->number, - bridge->devfn, 0x1c, &l); + if (bus->self) { + struct pci_dev *bridge = bus->self; + unsigned int l; + /* + * Set up the top and bottom of the PCI I/O segment + * for this bus. + */ + pcibios_read_config_dword(bridge->bus->number, + bridge->devfn, 0x1c, &l); #if 1 printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n", bus->number, PCI_SLOT(bridge->devfn), l); #endif - l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */ - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, 0x1c, l); - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, - 0x3c, 0x00040000); - pcibios_write_config_dword(bridge->bus->number, - bridge->devfn, - 0x4, 0xffff0007); - } else - printk("check_behind_io: WARNING! bus->self NULL\n"); + l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */ + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, 0x1c, l); + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, + 0x3c, 0x00040000); + pcibios_write_config_dword(bridge->bus->number, + bridge->devfn, + 0x4, 0xffff0007); + } else + printk("check_behind_io: WARNING! bus->self NULL\n"); } } -#endif /* CONFIG_ALPHA_SRM_SETUP */ + /* - * Most evaluation boards share most of the fixup code, which is isolated - * here. This function is declared "inline" as only one platform will ever - * be selected in any given kernel. If that platform doesn't need this code, - * we don't want it around as dead code. + * Most boards share most of the fixup code, which is isolated here. */ -static inline void -common_fixup(long min_idsel, long max_idsel, long irqs_per_slot, - char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot], - long ide_base) + +void __init +common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), + int (*swizzle)(struct pci_dev *dev, int *pin)) { - struct pci_dev *dev, *curr; - unsigned char pin; - unsigned char slot; + struct pci_dev *dev; + u8 pin, slot, irq_orig; + int irq; /* - * Go through all devices, fixing up irqs as we see fit: + * Go through all devices, fixing up irqs as we see fit. */ for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE || - dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) { - /* - * HACK: the PCI-to-EISA bridge appears not to identify - * itself as a bridge... :-( - */ - if (dev->vendor == PCI_VENDOR_ID_INTEL && - dev->device == PCI_DEVICE_ID_INTEL_82375) { - DBG_DEVS(("common_fixup: ignoring PCEB...\n")); - continue; - } - - /* - * This device is not on the primary bus, we need - * to figure out which interrupt pin it will come - * in on. We know which slot it will come in on - * 'cos that slot is where the bridge is. Each - * time the interrupt line passes through a PCI-PCI - * bridge we must apply the swizzle function (see - * the inline static routine above). - */ - dev->irq = 0; - if (!DEV_IS_ON_PRIMARY(dev)) { - /* read the pin and do the PCI-PCI bridge - interrupt pin swizzle */ - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_PIN, - &pin); - /* cope with 0 and illegal */ - if (pin == 0 || pin > 4) - pin = 1; - /* follow the chain of bridges, swizzling - as we go */ - curr = dev; -#if defined(CONFIG_ALPHA_MIATA) - /* check first for the built-in bridge */ - if ((PCI_SLOT(dev->bus->self->devfn) == 8) || - (PCI_SLOT(dev->bus->self->devfn) == 20)) { - slot = PCI_SLOT(dev->devfn) + 5; - DBG_DEVS(("MIATA: bus 1 slot %d pin %d" - " irq %d min_idsel %d\n", - PCI_SLOT(dev->devfn), pin, - irq_tab[slot - min_idsel][pin], - min_idsel)); - } - else /* must be a card-based bridge */ - { - do { - if ((PCI_SLOT(curr->bus->self->devfn) == 8) || - (PCI_SLOT(curr->bus->self->devfn) == 20)) - { - slot = PCI_SLOT(curr->devfn) + 5; - break; - } - /* swizzle */ - pin = bridge_swizzle( - pin, PCI_SLOT(curr->devfn)) ; - /* move up the chain of bridges */ - curr = curr->bus->self ; - /* slot of the next bridge. */ - slot = PCI_SLOT(curr->devfn); - } while (curr->bus->self) ; - } -#elif defined(CONFIG_ALPHA_NORITAKE) - /* check first for the built-in bridge */ - if (PCI_SLOT(dev->bus->self->devfn) == 8) { - slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */ - DBG_DEVS(("NORITAKE: bus 1 slot %d pin %d" - "irq %d min_idsel %ld\n", - PCI_SLOT(dev->devfn), pin, - irq_tab[slot - min_idsel][pin], - min_idsel)); - } - else /* must be a card-based bridge */ - { - do { - if (PCI_SLOT(curr->bus->self->devfn) == 8) { - slot = PCI_SLOT(curr->devfn) + 15; - break; - } - /* swizzle */ - pin = bridge_swizzle( - pin, PCI_SLOT(curr->devfn)) ; - /* move up the chain of bridges */ - curr = curr->bus->self ; - /* slot of the next bridge. */ - slot = PCI_SLOT(curr->devfn); - } while (curr->bus->self) ; - } -#else /* everyone but MIATA and NORITAKE */ - DBG_DEVS(("common_fixup: bus %d slot %d pin %d " - "irq %d min_idsel %ld\n", - curr->bus->number, - PCI_SLOT(dev->devfn), pin, - irq_tab[slot - min_idsel][pin], - min_idsel)); - do { - /* swizzle */ - pin = - bridge_swizzle(pin, PCI_SLOT(curr->devfn)); - /* move up the chain of bridges */ - curr = curr->bus->self; - } while (curr->bus->self); - /* The slot is the slot of the last bridge. */ - slot = PCI_SLOT(curr->devfn); -#endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* - * must make sure that SRM didn't screw up - * and allocate an address > 64K for I/O - * space behind a PCI-PCI bridge - */ - check_behind_io(dev); -#endif /* CONFIG_ALPHA_SRM_SETUP */ - } else { /* just a device on a primary bus */ - /* work out the slot */ - slot = PCI_SLOT(dev->devfn); - /* read the pin */ - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_PIN, - &pin); - DBG_DEVS(("common_fixup: bus %d slot %d" - " pin %d irq %d min_idsel %ld\n", - dev->bus->number, slot, pin, - irq_tab[slot - min_idsel][pin], - min_idsel)); - /* cope with 0 and illegal */ - if (pin == 0 || pin > 4) - pin = 1; - } - if (irq_tab[slot - min_idsel][pin] != -1) - dev->irq = irq_tab[slot - min_idsel][pin]; -#ifdef CONFIG_ALPHA_RAWHIDE - dev->irq += - 24 * bus2hose[dev->bus->number]->pci_hose_index; -#endif /* RAWHIDE */ -#ifdef CONFIG_ALPHA_SRM - { - unsigned char irq_orig; - /* read the original SRM-set IRQ and tell */ - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_LINE, - &irq_orig); - if (irq_orig != dev->irq) { - DBG_DEVS(("common_fixup: bus %d slot 0x%x " - "SRM IRQ 0x%x changed to 0x%x\n", - dev->bus->number,PCI_SLOT(dev->devfn), - irq_orig, dev->irq)); -#ifdef CONFIG_ALPHA_SRM_SETUP - irq_dev_to_reset[irq_reset_count] = dev; - irq_to_reset[irq_reset_count] = irq_orig; - irq_reset_count++; -#endif /* CONFIG_ALPHA_SRM_SETUP */ - } - } -#endif /* SRM */ - - /* always tell the device, so the driver knows what is - * the real IRQ to use; the device does not use it. - */ - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); - - DBG_DEVS(("common_fixup: bus %d slot 0x%x" - " VID 0x%x DID 0x%x\n" - " int_slot 0x%x pin 0x%x" - " pirq 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - dev->vendor, dev->device, - slot, pin, dev->irq)); - - /* - * if it's a VGA, enable its BIOS ROM at C0000 - */ - if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - /* but if its a Cirrus 543x/544x DISABLE it, */ - /* since enabling ROM disables the memory... */ - if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) && - (dev->device >= 0x00a0) && - (dev->device <= 0x00ac)) { - pcibios_write_config_dword( - dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x00000000); - } else { - pcibios_write_config_dword( - dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); - } - } - /* - * if it's a SCSI, disable its BIOS ROM - */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) { - pcibios_write_config_dword(dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x0000000); - } - } - } - if (ide_base) { - enable_ide(ide_base); - } -} - -/* - * The EB66+ is very similar to the EB66 except that it does not have - * the on-board NCR and Tulip chips. In the code below, I have used - * slot number to refer to the id select line and *not* the slot - * number used in the EB66+ documentation. However, in the table, - * I've given the slot number, the id select line and the Jxx number - * that's printed on the board. The interrupt pins from the PCI slots - * are wired into 3 interrupt summary registers at 0x804, 0x805 and - * 0x806 ISA. - * - * In the table, -1 means don't assign an IRQ number. This is usually - * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. - */ -static inline void eb66p_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ - {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */ - {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */ - }; - common_fixup(6, 10, 5, irq_tab, 0x398); -} - - -/* - * The PC164 and LX164 have 19 PCI interrupts, four from each of the four - * PCI slots, the SIO, PCI/IDE, and USB. - * - * Each of the interrupts can be individually masked. This is - * accomplished by setting the appropriate bit in the mask register. - * A bit is set by writing a "1" to the desired position in the mask - * register and cleared by writing a "0". There are 3 mask registers - * located at ISA address 804h, 805h and 806h. - * - * An I/O read at ISA address 804h, 805h, 806h will return the - * state of the 11 PCI interrupts and not the state of the MASKED - * interrupts. - * - * Note: A write to I/O 804h, 805h, and 806h the mask register will be - * updated. - * - * - * ISA DATA<7:0> - * ISA +--------------------------------------------------------------+ - * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * +==============================================================+ - * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 | - * +--------------------------------------------------------------+ - * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 | - * +--------------------------------------------------------------+ - * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 | - * +--------------------------------------------------------------+ - * * Rsrv = reserved bits - * Note: The mask register is write-only. - * - * IdSel - * 5 32 bit PCI option slot 2 - * 6 64 bit PCI option slot 0 - * 7 64 bit PCI option slot 1 - * 8 Saturn I/O - * 9 32 bit PCI option slot 3 - * 10 USB - * 11 IDE - * - */ - -#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) -static inline void alphapc164_fixup(void) -{ - static char irq_tab[7][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ - { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ - { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */ - { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */ - { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */ - }; - - common_fixup(5, 11, 5, irq_tab, 0); - SMC93x_Init(); -} -#endif - -/* - * The AlphaPC64 is very similar to the EB66+ except that its slots - * are numbered differently. In the code below, I have used slot - * number to refer to the id select line and *not* the slot number - * used in the AlphaPC64 documentation. However, in the table, I've - * given the slot number, the id select line and the Jxx number that's - * printed on the board. The interrupt pins from the PCI slots are - * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806 - * ISA. - * - * In the table, -1 means don't assign an IRQ number. This is usually - * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. - */ -static inline void cabriolet_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ - { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ - { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */ - }; - - common_fixup(5, 9, 5, irq_tab, 0x398); -} - - -/* - * Fixup configuration for EB66/EB64+ boards. - * - * Both these boards use the same interrupt summary scheme. There are - * two 8 bit external summary registers as follows: - * - * Summary @ 0x26: - * Bit Meaning - * 0 Interrupt Line A from slot 0 - * 1 Interrupt Line A from slot 1 - * 2 Interrupt Line B from slot 0 - * 3 Interrupt Line B from slot 1 - * 4 Interrupt Line C from slot 0 - * 5 Interrupt line from the two ISA PICs - * 6 Tulip (slot - * 7 NCR SCSI - * - * Summary @ 0x27 - * Bit Meaning - * 0 Interrupt Line C from slot 1 - * 1 Interrupt Line D from slot 0 - * 2 Interrupt Line D from slot 1 - * 3 RAZ - * 4 RAZ - * 5 RAZ - * 6 RAZ - * 7 RAZ - * - * The device to slot mapping looks like: - * - * Slot Device - * 5 NCR SCSI controller - * 6 PCI on board slot 0 - * 7 PCI on board slot 1 - * 8 Intel SIO PCI-ISA bridge chip - * 9 Tulip - DECchip 21040 ethernet controller - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ -static inline void eb66_and_eb64p_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ - {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ - {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ - { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ - {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */ - }; - common_fixup(5, 9, 5, irq_tab, 0); -} - - -/* - * Fixup configuration for MIKASA (AlphaServer 1000) - * - * Summary @ 0x536: - * Bit Meaning - * 0 Interrupt Line A from slot 0 - * 1 Interrupt Line B from slot 0 - * 2 Interrupt Line C from slot 0 - * 3 Interrupt Line D from slot 0 - * 4 Interrupt Line A from slot 1 - * 5 Interrupt line B from slot 1 - * 6 Interrupt Line C from slot 1 - * 7 Interrupt Line D from slot 1 - * 8 Interrupt Line A from slot 2 - * 9 Interrupt Line B from slot 2 - *10 Interrupt Line C from slot 2 - *11 Interrupt Line D from slot 2 - *12 NCR 810 SCSI - *13 Power Supply Fail - *14 Temperature Warn - *15 Reserved - * - * The device to slot mapping looks like: - * - * Slot Device - * 6 NCR SCSI controller - * 7 Intel PCI-EISA bridge chip - * 11 PCI on board slot 0 - * 12 PCI on board slot 1 - * 13 PCI on board slot 2 - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ -static inline void mikasa_fixup(void) -{ - static char irq_tab[8][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ - { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ - { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */ - { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ - { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ - { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */ - { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ - { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */ - }; - common_fixup(6, 13, 5, irq_tab, 0); -} - -/* - * Fixup configuration for NORITAKE (AlphaServer 1000A) - * - * This is also used for CORELLE (AlphaServer 800) - * and ALCOR Primo (AlphaStation 600A). - * - * Summary @ 0x542, summary register #1: - * Bit Meaning - * 0 All valid ints from summary regs 2 & 3 - * 1 QLOGIC ISP1020A SCSI - * 2 Interrupt Line A from slot 0 - * 3 Interrupt Line B from slot 0 - * 4 Interrupt Line A from slot 1 - * 5 Interrupt line B from slot 1 - * 6 Interrupt Line A from slot 2 - * 7 Interrupt Line B from slot 2 - * 8 Interrupt Line A from slot 3 - * 9 Interrupt Line B from slot 3 - *10 Interrupt Line A from slot 4 - *11 Interrupt Line B from slot 4 - *12 Interrupt Line A from slot 5 - *13 Interrupt Line B from slot 5 - *14 Interrupt Line A from slot 6 - *15 Interrupt Line B from slot 6 - * - * Summary @ 0x544, summary register #2: - * Bit Meaning - * 0 OR of all unmasked ints in SR #2 - * 1 OR of secondary bus ints - * 2 Interrupt Line C from slot 0 - * 3 Interrupt Line D from slot 0 - * 4 Interrupt Line C from slot 1 - * 5 Interrupt line D from slot 1 - * 6 Interrupt Line C from slot 2 - * 7 Interrupt Line D from slot 2 - * 8 Interrupt Line C from slot 3 - * 9 Interrupt Line D from slot 3 - *10 Interrupt Line C from slot 4 - *11 Interrupt Line D from slot 4 - *12 Interrupt Line C from slot 5 - *13 Interrupt Line D from slot 5 - *14 Interrupt Line C from slot 6 - *15 Interrupt Line D from slot 6 - * - * The device to slot mapping looks like: - * - * Slot Device - * 7 Intel PCI-EISA bridge chip - * 8 DEC PCI-PCI bridge chip - * 11 PCI on board slot 0 - * 12 PCI on board slot 1 - * 13 PCI on board slot 2 - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ -static inline void noritake_fixup(void) -{ - static char irq_tab[15][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - /* note: IDSELs 16, 17, and 25 are CORELLE only */ - { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ - { -1, -1, -1, -1, -1}, /* IdSel 17, S3 Trio64 */ - { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ - { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ - { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ - { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ - { 16+2, 16+2, 16+3, 32+2, 32+3}, /* IdSel 22, slot 0 */ - { 16+4, 16+4, 16+5, 32+4, 32+5}, /* IdSel 23, slot 1 */ - { 16+6, 16+6, 16+7, 32+6, 32+7}, /* IdSel 24, slot 2 */ - { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 25, slot 3 */ - /* the following 5 are actually on PCI bus 1, which is */ - /* across the built-in bridge of the NORITAKE only */ - { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ - { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 17, slot 3 */ - {16+10, 16+10, 16+11, 32+10, 32+11}, /* IdSel 18, slot 4 */ - {16+12, 16+12, 16+13, 32+12, 32+13}, /* IdSel 19, slot 5 */ - {16+14, 16+14, 16+15, 32+14, 32+15}, /* IdSel 20, slot 6 */ - }; - common_fixup(5, 19, 5, irq_tab, 0); -} - -/* - * Fixup configuration for ALCOR and XLT (XL-300/366/433) - * - * Summary @ GRU_INT_REQ: - * Bit Meaning - * 0 Interrupt Line A from slot 2 - * 1 Interrupt Line B from slot 2 - * 2 Interrupt Line C from slot 2 - * 3 Interrupt Line D from slot 2 - * 4 Interrupt Line A from slot 1 - * 5 Interrupt line B from slot 1 - * 6 Interrupt Line C from slot 1 - * 7 Interrupt Line D from slot 1 - * 8 Interrupt Line A from slot 0 - * 9 Interrupt Line B from slot 0 - *10 Interrupt Line C from slot 0 - *11 Interrupt Line D from slot 0 - *12 Interrupt Line A from slot 4 - *13 Interrupt Line B from slot 4 - *14 Interrupt Line C from slot 4 - *15 Interrupt Line D from slot 4 - *16 Interrupt Line D from slot 3 - *17 Interrupt Line D from slot 3 - *18 Interrupt Line D from slot 3 - *19 Interrupt Line D from slot 3 - *20-30 Reserved - *31 EISA interrupt - * - * The device to slot mapping looks like: - * - * Slot Device - * 6 built-in TULIP (XLT only) - * 7 PCI on board slot 0 - * 8 PCI on board slot 3 - * 9 PCI on board slot 4 - * 10 PCEB (PCI-EISA bridge) - * 11 PCI on board slot 2 - * 12 PCI on board slot 1 - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ -static inline void alcor_fixup(void) -{ - static char irq_tab[7][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - /* note: IDSEL 17 is XLT only */ - {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ - { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ - {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ - {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */ - { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */ - { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ - { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ - }; - common_fixup(6, 12, 5, irq_tab, 0); -} - -/* - * Fixup configuration for ALPHA SABLE (2100) - 2100A is different ?? - * - * Summary Registers (536/53a/53c): - * Bit Meaning - *----------------- - * 0 PCI slot 0 - * 1 NCR810 (builtin) - * 2 TULIP (builtin) - * 3 mouse - * 4 PCI slot 1 - * 5 PCI slot 2 - * 6 keyboard - * 7 floppy - * 8 COM2 - * 9 parallel port - *10 EISA irq 3 - *11 EISA irq 4 - *12 EISA irq 5 - *13 EISA irq 6 - *14 EISA irq 7 - *15 COM1 - *16 EISA irq 9 - *17 EISA irq 10 - *18 EISA irq 11 - *19 EISA irq 12 - *20 EISA irq 13 - *21 EISA irq 14 - *22 NC - *23 IIC - * - * The device to slot mapping looks like: - * - * Slot Device - * 0 TULIP - * 1 SCSI - * 2 PCI-EISA bridge - * 3 none - * 4 none - * 5 none - * 6 PCI on board slot 0 - * 7 PCI on board slot 1 - * 8 PCI on board slot 2 - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ -/* - * NOTE: the IRQ assignments below are arbitrary, but need to be consistent - * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables - * in irq.c - */ -static inline void sable_fixup(void) -{ - static char irq_tab[9][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ - { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ - { -1, -1, -1, -1, -1}, /* IdSel 2, SIO */ - { -1, -1, -1, -1, -1}, /* IdSel 3, none */ - { -1, -1, -1, -1, -1}, /* IdSel 4, none */ - { -1, -1, -1, -1, -1}, /* IdSel 5, none */ - { 32+2, 32+2, 32+2, 32+2, 32+2}, /* IdSel 6, slot 0 */ - { 32+3, 32+3, 32+3, 32+3, 32+3}, /* IdSel 7, slot 1 */ - { 32+4, 32+4, 32+4, 32+4, 32+4}, /* IdSel 8, slot 2 */ - }; - common_fixup(0, 8, 5, irq_tab, 0); -} - -/* - * Fixup configuration for MIATA (EV56+PYXIS) - * - * Summary @ PYXIS_INT_REQ: - * Bit Meaning - * 0 Fan Fault - * 1 NMI - * 2 Halt/Reset switch - * 3 none - * 4 CID0 (Riser ID) - * 5 CID1 (Riser ID) - * 6 Interval timer - * 7 PCI-ISA Bridge - * 8 Ethernet - * 9 EIDE (deprecated, ISA 14/15 used) - *10 none - *11 USB - *12 Interrupt Line A from slot 4 - *13 Interrupt Line B from slot 4 - *14 Interrupt Line C from slot 4 - *15 Interrupt Line D from slot 4 - *16 Interrupt Line A from slot 5 - *17 Interrupt line B from slot 5 - *18 Interrupt Line C from slot 5 - *19 Interrupt Line D from slot 5 - *20 Interrupt Line A from slot 1 - *21 Interrupt Line B from slot 1 - *22 Interrupt Line C from slot 1 - *23 Interrupt Line D from slot 1 - *24 Interrupt Line A from slot 2 - *25 Interrupt Line B from slot 2 - *26 Interrupt Line C from slot 2 - *27 Interrupt Line D from slot 2 - *27 Interrupt Line A from slot 3 - *29 Interrupt Line B from slot 3 - *30 Interrupt Line C from slot 3 - *31 Interrupt Line D from slot 3 - * - * The device to slot mapping looks like: - * - * Slot Device - * 3 DC21142 Ethernet - * 4 EIDE CMD646 - * 5 none - * 6 USB - * 7 PCI-ISA bridge - * 8 PCI-PCI Bridge (SBU Riser) - * 9 none - * 10 none - * 11 PCI on board slot 4 (SBU Riser) - * 12 PCI on board slot 5 (SBU Riser) - * - * These are behind the bridge, so I'm not sure what to do... - * - * 13 PCI on board slot 1 (SBU Riser) - * 14 PCI on board slot 2 (SBU Riser) - * 15 PCI on board slot 3 (SBU Riser) - * - * - * This two layered interrupt approach means that we allocate IRQ 16 and - * above for PCI interrupts. The IRQ relates to which bit the interrupt - * comes in on. This makes interrupt processing much easier. - */ - -#ifdef CONFIG_ALPHA_MIATA -static inline void miata_fixup(void) -{ - static char irq_tab[18][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ - { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ - { -1, -1, -1, -1, -1}, /* IdSel 16, none */ - { -1, -1, -1, -1, -1}, /* IdSel 17, none */ -/* {16+11, 16+11, 16+11, 16+11, 16+11},*//* IdSel 17, USB ?? */ - { -1, -1, -1, -1, -1}, /* IdSel 18, PCI-ISA */ - { -1, -1, -1, -1, -1}, /* IdSel 19, PCI-PCI */ - { -1, -1, -1, -1, -1}, /* IdSel 20, none */ - { -1, -1, -1, -1, -1}, /* IdSel 21, none */ - {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 22, slot 4 */ - {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 23, slot 5 */ - /* The following are actually on bus 1, which is */ - /* across the builtin PCI-PCI bridge */ - {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 24, slot 1 */ - {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 25, slot 2 */ - {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 26, slot 3 */ - { -1, -1, -1, -1, -1}, /* IdSel 27, none */ - { -1, -1, -1, -1, -1}, /* IdSel 28, none */ - { -1, -1, -1, -1, -1}, /* IdSel 29, none */ - { -1, -1, -1, -1, -1}, /* IdSel 30, none */ - { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ - }; - common_fixup(3, 20, 5, irq_tab, 0); - SMC669_Init(); /* it might be a GL (fails harmlessly if not) */ - es1888_init(); -} -#endif - -/* - * Fixup configuration for SX164 (PCA56+PYXIS) - * - * Summary @ PYXIS_INT_REQ: - * Bit Meaning - * 0 RSVD - * 1 NMI - * 2 Halt/Reset switch - * 3 MBZ - * 4 RAZ - * 5 RAZ - * 6 Interval timer (RTC) - * 7 PCI-ISA Bridge - * 8 Interrupt Line A from slot 3 - * 9 Interrupt Line A from slot 2 - *10 Interrupt Line A from slot 1 - *11 Interrupt Line A from slot 0 - *12 Interrupt Line B from slot 3 - *13 Interrupt Line B from slot 2 - *14 Interrupt Line B from slot 1 - *15 Interrupt line B from slot 0 - *16 Interrupt Line C from slot 3 - *17 Interrupt Line C from slot 2 - *18 Interrupt Line C from slot 1 - *19 Interrupt Line C from slot 0 - *20 Interrupt Line D from slot 3 - *21 Interrupt Line D from slot 2 - *22 Interrupt Line D from slot 1 - *23 Interrupt Line D from slot 0 - * - * IdSel - * 5 32 bit PCI option slot 2 - * 6 64 bit PCI option slot 0 - * 7 64 bit PCI option slot 1 - * 8 Cypress I/O - * 9 32 bit PCI option slot 3 - * - */ + if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + continue; -static inline void sx164_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */ - { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */ - { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */ - { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */ - { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */ - }; - common_fixup(5, 9, 5, irq_tab, 0); - SMC669_Init(); -} + /* + * This device is not on the primary bus, we need + * to figure out which interrupt pin it will come + * in on. We know which slot it will come in on + * 'cos that slot is where the bridge is. Each + * time the interrupt line passes through a PCI-PCI + * bridge we must apply the swizzle function (see + * the inline static routine above). + */ + dev->irq = 0; -/* - * Fixup configuration for DP264 (EV6+TSUNAMI) - * - * Summary @ TSUNAMI_CSR_DIM0: - * Bit Meaning - * 0-17 Unused - *18 Interrupt SCSI B (Adaptec 7895 builtin) - *19 Interrupt SCSI A (Adaptec 7895 builtin) - *20 Interrupt Line D from slot 2 PCI0 - *21 Interrupt Line C from slot 2 PCI0 - *22 Interrupt Line B from slot 2 PCI0 - *23 Interrupt Line A from slot 2 PCI0 - *24 Interrupt Line D from slot 1 PCI0 - *25 Interrupt Line C from slot 1 PCI0 - *26 Interrupt Line B from slot 1 PCI0 - *27 Interrupt Line A from slot 1 PCI0 - *28 Interrupt Line D from slot 0 PCI0 - *29 Interrupt Line C from slot 0 PCI0 - *30 Interrupt Line B from slot 0 PCI0 - *31 Interrupt Line A from slot 0 PCI0 - * - *32 Interrupt Line D from slot 3 PCI1 - *33 Interrupt Line C from slot 3 PCI1 - *34 Interrupt Line B from slot 3 PCI1 - *35 Interrupt Line A from slot 3 PCI1 - *36 Interrupt Line D from slot 2 PCI1 - *37 Interrupt Line C from slot 2 PCI1 - *38 Interrupt Line B from slot 2 PCI1 - *39 Interrupt Line A from slot 2 PCI1 - *40 Interrupt Line D from slot 1 PCI1 - *41 Interrupt Line C from slot 1 PCI1 - *42 Interrupt Line B from slot 1 PCI1 - *43 Interrupt Line A from slot 1 PCI1 - *44 Interrupt Line D from slot 0 PCI1 - *45 Interrupt Line C from slot 0 PCI1 - *46 Interrupt Line B from slot 0 PCI1 - *47 Interrupt Line A from slot 0 PCI1 - *48-52 Unused - *53 PCI0 NMI (from Cypress) - *54 PCI0 SMI INT (from Cypress) - *55 PCI0 ISA Interrupt (from Cypress) - *56-60 Unused - *61 PCI1 Bus Error - *62 PCI0 Bus Error - *63 Reserved - * - * IdSel - * 5 Cypress Bridge I/O - * 6 SCSI Adaptec builtin - * 7 64 bit PCI option slot 0 - * 8 64 bit PCI option slot 1 - * 9 64 bit PCI option slot 2 - * - */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &pin); + /* Cope with 0 and illegal. */ + if (pin == 0 || pin > 4) + pin = 1; -static inline void dp264_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { -1, -1, -1, -1, -1}, /* IdSel 5 ISA Bridge */ - { 16+ 2, 16+ 2, 16+ 2, 16+ 2, 16+ 2}, /* IdSel 6 SCSI builtin */ - { 16+15, 16+15, 16+14, 16+13, 16+12}, /* IdSel 7 slot 0 */ - { 16+11, 16+11, 16+10, 16+ 9, 16+ 8}, /* IdSel 8 slot 1 */ - { 16+ 7, 16+ 7, 16+ 6, 16+ 5, 16+ 4} /* IdSel 9 slot 2 */ - }; - common_fixup(5, 9, 5, irq_tab, 0); - SMC669_Init(); -} + if (!DEV_IS_ON_PRIMARY(dev)) { + /* Follow the chain of bridges, swizzling as we go. */ -/* - * Fixup configuration for RAWHIDE - * - * Summary @ MCPCIA_PCI0_INT_REQ: - * Bit Meaning - *0 Interrupt Line A from slot 2 PCI0 - *1 Interrupt Line B from slot 2 PCI0 - *2 Interrupt Line C from slot 2 PCI0 - *3 Interrupt Line D from slot 2 PCI0 - *4 Interrupt Line A from slot 3 PCI0 - *5 Interrupt Line B from slot 3 PCI0 - *6 Interrupt Line C from slot 3 PCI0 - *7 Interrupt Line D from slot 3 PCI0 - *8 Interrupt Line A from slot 4 PCI0 - *9 Interrupt Line B from slot 4 PCI0 - *10 Interrupt Line C from slot 4 PCI0 - *11 Interrupt Line D from slot 4 PCI0 - *12 Interrupt Line A from slot 5 PCI0 - *13 Interrupt Line B from slot 5 PCI0 - *14 Interrupt Line C from slot 5 PCI0 - *15 Interrupt Line D from slot 5 PCI0 - *16 EISA interrupt (PCI 0) or SCSI interrupt (PCI 1) - *17-23 NA - * - * IdSel - * 1 EISA bridge (PCI bus 0 only) - * 2 PCI option slot 2 - * 3 PCI option slot 3 - * 4 PCI option slot 4 - * 5 PCI option slot 5 - * - */ + int spill = pin; + slot = (*swizzle)(dev, &spill); + pin = spill; -static inline void rawhide_fixup(void) -{ - static char irq_tab[5][5] __initlocaldata = { - /*INT INTA INTB INTC INTD */ - { 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 only */ - { 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */ - { 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */ - { 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */ - { 16+12, 16+12, 16+13, 16+14, 16+15} /* IdSel 5 slot 5 */ - }; - common_fixup(1, 5, 5, irq_tab, 0); -} + /* Must make sure that SRM didn't screw up + and allocate an address > 64K for I/O + space behind a PCI-PCI bridge. */ + if (alpha_use_srm_setup) + check_behind_io(dev); + } else { + /* Just a device on a primary bus. */ + slot = PCI_SLOT(dev->devfn); + } -/* - * The Takara has PCI devices 1, 2, and 3 configured to slots 20, - * 19, and 18 respectively, in the default configuration. They can - * also be jumpered to slots 8, 7, and 6 respectively, which is fun - * because the SIO ISA bridge can also be slot 7. However, the SIO - * doesn't explicitly generate PCI-type interrupts, so we can - * assign it whatever the hell IRQ we like and it doesn't matter. - */ -static inline void takara_fixup(void) -{ - static char irq_tab[15][5] __initlocaldata = { - { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 6 == device 3 */ - { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 7 == device 2 */ - { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 8 == device 1 */ - { -1, -1, -1, -1, -1}, /* slot 9 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 10 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 11 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 12 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 13 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 14 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 15 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 16 == nothing */ - { -1, -1, -1, -1, -1}, /* slot 17 == nothing */ - { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 18 == device 3 */ - { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 19 == device 2 */ - { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 20 == device 1 */ - }; - common_fixup(6, 20, 5, irq_tab, 0x26e); -} + irq = (*map_irq)(dev, slot, pin); -/* - * Fixup configuration for all boards that route the PCI interrupts - * through the SIO PCI/ISA bridge. This includes Noname (AXPpci33), - * Avanti (AlphaStation) and Kenetics's Platform 2000. - */ -static inline void sio_fixup(void) -{ - struct pci_dev *dev; - /* - * The Noname board has 5 PCI slots with each of the 4 - * interrupt pins routed to different pins on the PCI/ISA - * bridge (PIRQ0-PIRQ3). The table below is based on - * information available at: - * - * http://ftp.digital.com/pub/DEC/axppci/ref_interrupts.txt - * - * I have no information on the Avanti interrupt routing, but - * the routing seems to be identical to the Noname except - * that the Avanti has an additional slot whose routing I'm - * unsure of. - * - * pirq_tab[0] is a fake entry to deal with old PCI boards - * that have the interrupt pin number hardwired to 0 (meaning - * that they use the default INTA line, if they are interrupt - * driven at all). - */ - static const char pirq_tab[][5] __initlocaldata = { - /*INT A B C D */ -#ifdef CONFIG_ALPHA_P2K - { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ - {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ - { 1, 1, 2, 3, 0}, /* idsel 8 (slot A) */ - { 2, 2, 3, 0, 1}, /* idsel 9 (slot B) */ - {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ - {-1, -1, -1, -1, -1}, /* idsel 11 (unused) */ - { 3, 3, -1, -1, -1}, /* idsel 12 (CMD0646) */ -#else - { 3, 3, 3, 3, 3}, /* idsel 6 (53c810) */ - {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ - { 2, 2, -1, -1, -1}, /* idsel 8 (Noname hack: slot closest to ISA) */ - {-1, -1, -1, -1, -1}, /* idsel 9 (unused) */ - {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ - { 0, 0, 2, 1, 0}, /* idsel 11 KN25_PCI_SLOT0 */ - { 1, 1, 0, 2, 1}, /* idsel 12 KN25_PCI_SLOT1 */ - { 2, 2, 1, 0, 2}, /* idsel 13 KN25_PCI_SLOT2 */ - { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */ -#endif - }; - const size_t pirq_tab_len = sizeof(pirq_tab)/sizeof(pirq_tab[0]); + DBG_DEVS(("common_pci_fixup: bus %d slot %d " + "pin %d irq %d\n", + dev->bus->number, slot, pin, irq)); - /* - * route_tab selects irq routing in PCI/ISA bridge so that: - * PIRQ0 -> irq 15 - * PIRQ1 -> irq 9 - * PIRQ2 -> irq 10 - * PIRQ3 -> irq 11 - * - * This probably ought to be configurable via MILO. For - * example, sound boards seem to like using IRQ 9. - */ + if (irq != -1) + dev->irq = irq; -#if defined(CONFIG_ALPHA_BOOK1) - /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */ - const unsigned int new_route_tab = 0x0e0f0a0a; + if (alpha_using_srm) { + /* Read the original SRM-set IRQ and tell. */ + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + &irq_orig); -#elif defined(CONFIG_ALPHA_NONAME) - /* - * For UDB, the only available PCI slot must not map to IRQ 9, - * since that's the builtin MSS sound chip. That PCI slot - * will map to PIRQ1 (for INTA at least), so we give it IRQ 15 - * instead. - * - * Unfortunately we have to do this for NONAME as well, since - * they are co-indicated when the platform type "Noname" is - * selected... :-( - */ - const unsigned int new_route_tab = 0x0b0a0f09; -#else - const unsigned int new_route_tab = 0x0b0a090f; -#endif - unsigned int route_tab, old_route_tab; - unsigned int level_bits, old_level_bits; - unsigned char pin, slot; - int pirq; - - pcibios_read_config_dword(0, PCI_DEVFN(7, 0), 0x60, &old_route_tab); - DBG_DEVS(("sio_fixup: old pirq route table: 0x%08x\n", - old_route_tab)); -#if PCI_MODIFY - route_tab = new_route_tab; - pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, route_tab); -#else - route_tab = old_route_tab; -#endif + if (irq_orig != dev->irq) { + struct reset_irq *r; - /* - * Go through all devices, fixing up irqs as we see fit: - */ - level_bits = 0; - for (dev = pci_devices; dev; dev = dev->next) { - if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && - (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) - continue; + DBG_DEVS(("common_pci_fixup: bus %d " + "slot 0x%x SRM IRQ 0x%x " + "changed to 0x%x\n", + dev->bus->number, + PCI_SLOT(dev->devfn), + irq_orig, dev->irq)); - dev->irq = 0; - if (dev->bus->number != 0) { - struct pci_dev *curr = dev; - /* - * read the pin and do the PCI-PCI bridge - * interrupt pin swizzle - */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &pin); - /* cope with 0 */ - if (pin == 0) - pin = 1; - /* follow the chain of bridges, swizzling as we go */ - do { - /* swizzle */ - pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)); - /* move up the chain of bridges */ - curr = curr->bus->self; - } while (curr->bus->self); - /* The slot is the slot of the last bridge. */ - slot = PCI_SLOT(curr->devfn); - } else { - /* work out the slot */ - slot = PCI_SLOT(dev->devfn); - /* read the pin */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &pin); + r = &srm_resets.irq[srm_resets.irq_count++]; + r->dev = dev; + r->irq = irq_orig; + } } - if (slot < 6 || slot >= 6 + pirq_tab_len) { - printk("bios32.sio_fixup: " - "weird, found device %04x:%04x in" - " non-existent slot %d!!\n", - dev->vendor, dev->device, slot); - continue; - } - pirq = pirq_tab[slot - 6][pin]; + /* Always tell the device, so the driver knows what is + the real IRQ to use; the device does not use it. */ + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); + + DBG_DEVS(("common_pci_fixup: bus %d slot 0x%x" + " VID 0x%x DID 0x%x\n" + " int_slot 0x%x pin 0x%x" + " pirq 0x%x\n", + dev->bus->number, PCI_SLOT(dev->devfn), + dev->vendor, dev->device, + slot, pin, dev->irq)); - DBG_DEVS(("sio_fixup: bus %d slot 0x%x VID 0x%x DID 0x%x\n" - " int_slot 0x%x pin 0x%x pirq 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, - dev->device, slot, pin, pirq)); /* - * if it's a VGA, enable its BIOS ROM at C0000 + * If it's a VGA, enable its BIOS ROM at C0000. */ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - /* but if its a Cirrus 543x/544x DISABLE it, */ - /* since enabling ROM disables the memory... */ + /* But if its a Cirrus 543x/544x DISABLE it, + since enabling ROM disables the memory... */ if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) && (dev->device >= 0x00a0) && (dev->device <= 0x00ac)) { @@ -1836,408 +964,37 @@ static inline void sio_fixup(void) } else { pcibios_write_config_dword( dev->bus->number, - dev->devfn, - PCI_ROM_ADDRESS, - 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); - } - } - if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - continue; /* for now, displays get no IRQ */ - } - - if (pirq < 0) { - DBG_DEVS(("bios32.sio_fixup: " - "weird, device %04x:%04x coming in on" - " slot %d has no irq line!!\n", - dev->vendor, dev->device, slot)); - continue; - } - - dev->irq = (route_tab >> (8 * pirq)) & 0xff; - -#ifndef CONFIG_ALPHA_BOOK1 - /* do not set *ANY* level triggers for AlphaBook1 */ - /* must set the PCI IRQs to level triggered */ - level_bits |= (1 << dev->irq); -#endif /* !CONFIG_ALPHA_BOOK1 */ - -#if PCI_MODIFY - /* tell the device: */ - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); -#endif - -#ifdef CONFIG_ALPHA_BOOK1 - /* - * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) - * is sensitive to PCI bus bursts, so we must DISABLE - * burst mode for the NCR 8xx SCSI... :-( - * - * Note that the NCR810 SCSI driver must preserve the - * setting of the bit in order for this to work. At the - * moment (2.0.29), ncr53c8xx.c does NOT do this, but - * 53c7,8xx.c DOES. - */ - if (dev->vendor == PCI_VENDOR_ID_NCR && - (dev->device == PCI_DEVICE_ID_NCR_53C810 || - dev->device == PCI_DEVICE_ID_NCR_53C815 || - dev->device == PCI_DEVICE_ID_NCR_53C820 || - dev->device == PCI_DEVICE_ID_NCR_53C825)) { - unsigned int io_port; - unsigned char ctest4; - - pcibios_read_config_dword(dev->bus->number, - dev->devfn, - PCI_BASE_ADDRESS_0, - &io_port); - io_port &= PCI_BASE_ADDRESS_IO_MASK; - ctest4 = inb(io_port+0x21); - if (!(ctest4 & 0x80)) { - printk("AlphaBook1 NCR init: setting" - " burst disable\n"); - outb(ctest4 | 0x80, io_port+0x21); + dev->devfn, + PCI_ROM_ADDRESS, + 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); } - } -#endif /* CONFIG_ALPHA_BOOK1 */ - } /* end for-devs */ - - /* - * Now, make all PCI interrupts level sensitive. Notice: - * these registers must be accessed byte-wise. inw()/outw() - * don't work. - * - * Make sure to turn off any level bits set for IRQs 9,10,11,15, - * so that the only bits getting set are for devices actually found. - * Note that we do preserve the remainder of the bits, which we hope - * will be set correctly by ARC/SRM. - * - * Note: we at least preserve any level-set bits on AlphaBook1 - */ - old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8); - DBG_DEVS(("sio_fixup: old irq level bits: 0x%04x\n", - old_level_bits)); - level_bits |= (old_level_bits & 0x71ff); - DBG_DEVS(("sio_fixup: new irq level bits: 0x%04x\n", - level_bits)); - outb((level_bits >> 0) & 0xff, 0x4d0); - outb((level_bits >> 8) & 0xff, 0x4d1); - -#ifdef CONFIG_ALPHA_BOOK1 - { - unsigned char orig, config; - /* On the AlphaBook1, make sure that register PR1 - indicates 1Mb mem */ - outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */ - outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */ - outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */ - if ((config & 0xc0) != 0xc0) { - printk("AlphaBook1 VGA init: setting 1Mb memory\n"); - config |= 0xc0; - outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */ } - outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */ - } -#endif /* CONFIG_ALPHA_BOOK1 */ - -#ifndef CONFIG_ALPHA_BOOK1 - /* Do not do IDE init for AlphaBook1 */ - enable_ide(0x26e); -#endif -} - - -#ifdef CONFIG_TGA_CONSOLE -extern void tga_console_init(void); -#endif /* CONFIG_TGA_CONSOLE */ - -void __init -pcibios_fixup(void) -{ - struct pci_bus *cur; - -#ifdef CONFIG_ALPHA_MCPCIA - /* must do massive setup for multiple PCI busses here... */ - DBG_DEVS(("pcibios_fixup: calling mcpcia_fixup()...\n")); - mcpcia_fixup(); -#endif /* MCPCIA */ - -#ifdef CONFIG_ALPHA_TSUNAMI - /* must do massive setup for multiple PCI busses here... */ - /* tsunami_fixup(); */ -#endif /* TSUNAMI */ - -#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN) - /* - * Scan the tree, allocating PCI memory and I/O space. - */ - /* - * Sigh; check_region() will need changing to accept a HANDLE, - * if we allocate I/O space addresses on a per-bus basis. - * For now, make the I/O bases unique across all busses, so - * that check_region() will not get confused... ;-} - */ - io_base = DEFAULT_IO_BASE; - for (cur = &pci_root; cur; cur = cur->next) { - mem_base = DEFAULT_MEM_BASE; - DBG_DEVS(("pcibios_fixup: calling layout_bus()\n")); - layout_bus(cur); - } -#endif - - /* - * Now is the time to do all those dirty little deeds... - */ -#if defined(CONFIG_ALPHA_NONAME) || defined(CONFIG_ALPHA_AVANTI) || \ - defined(CONFIG_ALPHA_P2K) - sio_fixup(); -#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164) - cabriolet_fixup(); -#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) - alphapc164_fixup(); -#elif defined(CONFIG_ALPHA_EB66P) - eb66p_fixup(); -#elif defined(CONFIG_ALPHA_EB66) - eb66_and_eb64p_fixup(); -#elif defined(CONFIG_ALPHA_EB64P) - eb66_and_eb64p_fixup(); -#elif defined(CONFIG_ALPHA_MIKASA) - mikasa_fixup(); -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) - alcor_fixup(); -#elif defined(CONFIG_ALPHA_SABLE) - sable_fixup(); -#elif defined(CONFIG_ALPHA_MIATA) - miata_fixup(); -#elif defined(CONFIG_ALPHA_NORITAKE) - noritake_fixup(); -#elif defined(CONFIG_ALPHA_SX164) - sx164_fixup(); -#elif defined(CONFIG_ALPHA_DP264) - dp264_fixup(); -#elif defined(CONFIG_ALPHA_RAWHIDE) - rawhide_fixup(); -#elif defined(CONFIG_ALPHA_TAKARA) - takara_fixup(); -#elif defined(CONFIG_ALPHA_RUFFIAN) - /* no fixup needed */ -#else -# error "You must tell me what kind of platform you want." -#endif - -#ifndef CONFIG_ABSTRACT_CONSOLE -#ifdef CONFIG_TGA_CONSOLE - tga_console_init(); -#endif -#endif -} - - -asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - lock_kernel(); - switch (len) { - case 1: - err = pcibios_read_config_byte(bus, dfn, off, &ubyte); - if (err != PCIBIOS_SUCCESSFUL) - ubyte = 0xff; - put_user(ubyte, buf); - break; - case 2: - err = pcibios_read_config_word(bus, dfn, off, &ushort); - if (err != PCIBIOS_SUCCESSFUL) - ushort = 0xffff; - put_user(ushort, (unsigned short *)buf); - break; - case 4: - err = pcibios_read_config_dword(bus, dfn, off, &uint); - if (err != PCIBIOS_SUCCESSFUL) - uint = 0xffffffff; - put_user(uint, (unsigned int *)buf); - break; - default: - err = -EINVAL; - break; - } - unlock_kernel(); - return err; -} - - -asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - lock_kernel(); - switch (len) { - case 1: - err = get_user(ubyte, buf); - if (err) - break; - err = pcibios_write_config_byte(bus, dfn, off, ubyte); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 2: - err = get_user(ushort, (unsigned short *)buf); - if (err) - break; - err = pcibios_write_config_word(bus, dfn, off, ushort); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 4: - err = get_user(uint, (unsigned int *)buf); - if (err) - break; - err = pcibios_write_config_dword(bus, dfn, off, uint); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; + /* + * If it's a SCSI, disable its BIOS ROM. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) { + pcibios_write_config_dword(dev->bus->number, + dev->devfn, + PCI_ROM_ADDRESS, + 0x0000000); } - break; - default: - err = -EINVAL; - break; } - unlock_kernel(); - return err; } -#if (defined(CONFIG_ALPHA_PC164) || \ - defined(CONFIG_ALPHA_LX164) || \ - defined(CONFIG_ALPHA_SX164) || \ - defined(CONFIG_ALPHA_EB164) || \ - defined(CONFIG_ALPHA_EB66P) || \ - defined(CONFIG_ALPHA_CABRIOLET)) && defined(CONFIG_ALPHA_SRM) +/* Most Alphas have straight-forward swizzling needs. */ -/* - on the above machines, under SRM console, we must use the CSERVE PALcode - routine to manage the interrupt mask for us, otherwise, the kernel/HW get - out of sync with what the PALcode thinks it needs to deliver/ignore - */ -void -cserve_update_hw(unsigned long irq, unsigned long mask) +int __init +common_swizzle(struct pci_dev *dev, int *pinp) { - extern void cserve_ena(unsigned long); - extern void cserve_dis(unsigned long); - - if (mask & (1UL << irq)) - /* disable */ - cserve_dis(irq - 16); - else - /* enable */ - cserve_ena(irq - 16); - return; -} -#endif /* (PC164 || LX164 || SX164 || EB164 || CABRIO) && SRM */ + int pin = *pinp; + do { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* Move up the chain of bridges. */ + dev = dev->bus->self; + } while (dev->bus->self); + *pinp = pin; -#ifdef CONFIG_ALPHA_MIATA -/* - * Init the built-in ES1888 sound chip (SB16 compatible) - */ -static int __init -es1888_init(void) -{ - /* Sequence of IO reads to init the audio controller */ - inb(0x0229); - inb(0x0229); - inb(0x0229); - inb(0x022b); - inb(0x0229); - inb(0x022b); - inb(0x0229); - inb(0x0229); - inb(0x022b); - inb(0x0229); - inb(0x0220); /* This sets the base address to 0x220 */ - - /* Sequence to set DMA channels */ - outb(0x01, 0x0226); /* reset */ - inb(0x0226); /* pause */ - outb(0x00, 0x0226); /* release reset */ - while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/ - continue; - inb(0x022a); /* pause */ - outb(0xc6, 0x022c); /* enable extended mode */ - while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ - continue; - outb(0xb1, 0x022c); /* setup for write to Interrupt CR */ - while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ - continue; - outb(0x14, 0x022c); /* set IRQ 5 */ - while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ - continue; - outb(0xb2, 0x022c); /* setup for write to DMA CR */ - while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ - continue; - outb(0x18, 0x022c); /* set DMA channel 1 */ - - return 0; + /* The slot is the slot of the last bridge. */ + return PCI_SLOT(dev->devfn); } -#endif /* CONFIG_ALPHA_MIATA */ - -__initfunc(char *pcibios_setup(char *str)) -{ - return str; -} - -#ifdef CONFIG_ALPHA_SRM_SETUP -void reset_for_srm(void) -{ - extern void scrreset(void); - struct pci_dev *dev; - int i; - - /* reset any IRQs that we changed */ - for (i = 0; i < irq_reset_count; i++) { - dev = irq_dev_to_reset[i]; - - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, irq_to_reset[i]); -#if 1 - printk("reset_for_srm: bus %d slot 0x%x " - "SRM IRQ 0x%x changed back from 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - irq_to_reset[i], dev->irq); -#endif - } - - /* reset any IO addresses that we changed */ - for (i = 0; i < io_reset_count; i++) { - dev = io_dev_to_reset[i]; - - pcibios_write_config_byte(dev->bus->number, dev->devfn, - io_reg_to_reset[i], io_to_reset[i]); -#if 1 - printk("reset_for_srm: bus %d slot 0x%x " - "SRM IO restored to 0x%x\n", - dev->bus->number, PCI_SLOT(dev->devfn), - io_to_reset[i]); -#endif -} - - /* reset the visible screen to the top of display memory */ - scrreset(); -} -#endif /* CONFIG_ALPHA_SRM_SETUP */ - #endif /* CONFIG_PCI */ diff --git a/arch/alpha/kernel/bios32.h b/arch/alpha/kernel/bios32.h new file mode 100644 index 000000000..9a3184fe5 --- /dev/null +++ b/arch/alpha/kernel/bios32.h @@ -0,0 +1,155 @@ +/* + * linux/arch/alpha/kernel/bios32.h + * + * This file contains declarations and inline functions for interfacing + * with the PCI initialization routines in bios32.c. + */ + + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +/* + * We can't just blindly use 64K for machines with EISA busses; they + * may also have PCI-PCI bridges present, and then we'd configure the + * bridge incorrectly. + * + * Also, we start at 0x8000 or 0x9000, in hopes to get all devices' + * IO space areas allocated *before* 0xC000; this is because certain + * BIOSes (Millennium for one) use PCI Config space "mechanism #2" + * accesses to probe the bus. If a device's registers appear at 0xC000, + * it may see an INx/OUTx at that address during BIOS emulation of the + * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense. + * + * Note that we may need this stuff for SRM_SETUP also, since certain + * SRM consoles screw up and allocate I/O space addresses > 64K behind + * PCI-to_PCI bridges, which can't pass I/O addresses larger than 64K, + * AFAIK. + */ + +#define EISA_DEFAULT_IO_BASE 0x9000 /* start above 8th slot */ +#define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */ + +/* + * An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address + * that get passed through the PCI<->ISA bridge chip. Although this causes + * us to set the PCI->Mem window bases lower than normal, we still allocate + * PCI bus devices' memory addresses *below* the low DMA mapping window, + * and hope they fit below 64Mb (to avoid conflicts), and so that they can + * be accessed via SPARSE space. + * + * We accept the risk that a broken Myrinet card will be put into a true XL + * and thus can more easily run into the problem described below. + */ +#define XL_DEFAULT_MEM_BASE (16*MB + 2*MB) /* 16M to 64M-1 is avail */ + +/* + * We try to make this address *always* have more than 1 bit set. + * this is so that devices like the broken Myrinet card will always have + * a PCI memory address that will never match a IDSEL address in + * PCI Config space, which can cause problems with early rev cards. + * + * However, APECS and LCA have only 34 bits for physical addresses, thus + * limiting PCI bus memory addresses for SPARSE access to be less than 128Mb. + */ +#define APECS_AND_LCA_DEFAULT_MEM_BASE (64*MB + 2*MB) + +/* + * We try to make this address *always* have more than 1 bit set. + * this is so that devices like the broken Myrinet card will always have + * a PCI memory address that will never match a IDSEL address in + * PCI Config space, which can cause problems with early rev cards. + * + * Because CIA and PYXIS and T2 have more bits for physical addresses, + * they support an expanded range of SPARSE memory addresses. + */ +#define DEFAULT_MEM_BASE (128*MB + 16*MB) + + +/* + * PCI_MODIFY + * + * If this 0, then do not write to any of the PCI registers, merely + * read them (i.e., use configuration as determined by SRM). The SRM + * seem do be doing a less than perfect job in configuring PCI + * devices, so for now we do it ourselves. Reconfiguring PCI devices + * breaks console (RPB) callbacks, but those don't work properly with + * 64 bit addresses anyways. + * + * The accepted convention seems to be that the console (POST + * software) should fully configure boot devices and configure the + * interrupt routing of *all* devices. In particular, the base + * addresses of non-boot devices need not be initialized. For + * example, on the AXPpci33 board, the base address a #9 GXE PCI + * graphics card reads as zero (this may, however, be due to a bug in + * the graphics card---there have been some rumor that the #9 BIOS + * incorrectly resets that address to 0...). + */ + +#define PCI_MODIFY (!alpha_use_srm_setup) + + +/* + * A small note about bridges and interrupts. The DECchip 21050 (and + * later) adheres to the PCI-PCI bridge specification. This says that + * the interrupts on the other side of a bridge are swizzled in the + * following manner: + * + * Dev Interrupt Interrupt + * Pin on Pin on + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + * + * The following code swizzles for exactly one bridge. The routine + * common_swizzle below handles multiple bridges. But there are a + * couple boards that do strange things, so we define this here. + */ + +static inline unsigned char +bridge_swizzle(unsigned char pin, unsigned int slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +extern void layout_all_busses(unsigned long io_base, unsigned long mem_base); +extern void enable_ide(long ide_base); + +struct pci_dev; + +extern void +common_pci_fixup(int (*map_irq)(struct pci_dev *dev, int slot, int pin), + int (*swizzle)(struct pci_dev *dev, int *pin)); + +extern int common_swizzle(struct pci_dev *dev, int *pinp); + +/* The following macro is used to implement the table-based irq mapping + function for all single-bus Alphas. */ + +#define COMMON_TABLE_LOOKUP \ +({ long _ctl_ = -1; \ + if (slot >= min_idsel && slot <= max_idsel && pin < irqs_per_slot) \ + _ctl_ = irq_tab[slot - min_idsel][pin]; \ + _ctl_; }) diff --git a/arch/alpha/kernel/apecs.c b/arch/alpha/kernel/core_apecs.c index 2bbdf0062..d2633bef1 100644 --- a/arch/alpha/kernel/apecs.c +++ b/arch/alpha/kernel/core_apecs.c @@ -1,5 +1,7 @@ /* - * Code common to all APECS chips. + * linux/arch/alpha/kernel/core_apecs.c + * + * Code common to all APECS core logic chips. * * Rewritten for Apecs from the lca.c from: * @@ -11,21 +13,24 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/init.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/hwrpb.h> #include <asm/ptrace.h> +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_apecs.h> +#undef __EXTERN_INLINE + +#include "proto.h" + /* * NOTE: Herein lie back-to-back mb instructions. They are magic. * One plausible explanation is that the i/o controller does not properly * handle the system transaction. Another involves timing. Ho hum. */ -extern struct hwrpb_struct *hwrpb; -extern asmlinkage void wrmces(unsigned long mces); - /* * BIOS32-style PCI interface: */ @@ -38,14 +43,10 @@ extern asmlinkage void wrmces(unsigned long mces); #define vuip volatile unsigned int * -static volatile unsigned int apecs_mcheck_expected = 0; -static volatile unsigned int apecs_mcheck_taken = 0; +volatile unsigned int apecs_mcheck_expected = 0; +volatile unsigned int apecs_mcheck_taken = 0; static unsigned int apecs_jd, apecs_jd1, apecs_jd2; -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT; -unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT; -#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -82,15 +83,16 @@ unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT; * * Notes: * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). + * (e.g., SCSI and Ethernet). * * The register selects a DWORD (32 bit) register offset. Hence it * doesn't get shifted by 2 bits as we want to "drop" the bottom two * bits. */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, + unsigned char *type1) { unsigned long addr; @@ -121,40 +123,25 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, return 0; } - -static unsigned int conf_read(unsigned long addr, unsigned char type1) +static unsigned int +conf_read(unsigned long addr, unsigned char type1) { unsigned long flags; unsigned int stat0, value; - unsigned int haxr2 = 0; /* to keep gcc quiet */ - -#ifdef CONFIG_ALPHA_SRM - /* some SRMs step on these registers during a machine check: */ - register long s0 asm ("9"); - register long s1 asm ("10"); - register long s2 asm ("11"); - register long s3 asm ("12"); - register long s4 asm ("13"); - register long s5 asm ("14"); - asm volatile ("# %0" : "r="(s0)); - asm volatile ("# %0" : "r="(s1)); - asm volatile ("# %0" : "r="(s2)); - asm volatile ("# %0" : "r="(s3)); - asm volatile ("# %0" : "r="(s4)); - asm volatile ("# %0" : "r="(s5)); -#endif + unsigned int haxr2 = 0; save_flags(flags); /* avoid getting hit by machine check */ cli(); DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vuip)APECS_IOC_DCSR; *(vuip)APECS_IOC_DCSR = stat0; mb(); DBG(("conf_read: APECS DCSR was 0x%x\n", stat0)); - /* if Type1 access, must set HAE #2 */ + + /* If Type1 access, must set HAE #2. */ if (type1) { haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); @@ -166,10 +153,13 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) apecs_mcheck_expected = 1; apecs_mcheck_taken = 0; mb(); - /* access configuration space: */ - value = *(vuip)addr; - mb(); - mb(); /* magic */ + + /* Access configuration space. */ + + /* Some SRMs step on these registers during a machine check. */ + asm volatile("ldl %0,%1; mb; mb" : "=r"(value) : "m"(*(vuip)addr) + : "$9", "$10", "$11", "$12", "$13", "$14", "memory"); + if (apecs_mcheck_taken) { apecs_mcheck_taken = 0; value = 0xffffffffU; @@ -187,16 +177,18 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) */ draina(); - /* now look for any errors */ + /* Now look for any errors. */ stat0 = *(vuip)APECS_IOC_DCSR; DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0)); - if (stat0 & 0xffe0U) { /* is any error bit set? */ - /* if not NDEV, print status */ + + /* Is any error bit set? */ + if (stat0 & 0xffe0U) { + /* If not NDEV, print status. */ if (!(stat0 & 0x0800)) { printk("apecs.c:conf_read: got stat0=%x\n", stat0); } - /* reset error status: */ + /* Reset error status. */ *(vuip)APECS_IOC_DCSR = stat0; mb(); wrmces(0x7); /* reset machine check */ @@ -204,40 +196,32 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) } #endif - /* if Type1 access, must reset HAE #2 so normal IO space ops work */ + /* If Type1 access, must reset HAE #2 so normal IO space ops work. */ if (type1) { *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); } restore_flags(flags); -#ifdef CONFIG_ALPHA_SRM - /* some SRMs step on these registers during a machine check: */ - asm volatile ("# %0" :: "r"(s0)); - asm volatile ("# %0" :: "r"(s1)); - asm volatile ("# %0" :: "r"(s2)); - asm volatile ("# %0" :: "r"(s3)); - asm volatile ("# %0" :: "r"(s4)); - asm volatile ("# %0" :: "r"(s5)); -#endif + return value; } - -static void conf_write(unsigned long addr, unsigned int value, unsigned char type1) +static void +conf_write(unsigned long addr, unsigned int value, unsigned char type1) { unsigned long flags; unsigned int stat0; - unsigned int haxr2 = 0; /* to keep gcc quiet */ + unsigned int haxr2 = 0; save_flags(flags); /* avoid getting hit by machine check */ cli(); - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vuip)APECS_IOC_DCSR; *(vuip)APECS_IOC_DCSR = stat0; mb(); - /* if Type1 access, must set HAE #2 */ + /* If Type1 access, must set HAE #2. */ if (type1) { haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); @@ -247,7 +231,8 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ draina(); apecs_mcheck_expected = 1; mb(); - /* access configuration space: */ + + /* Access configuration space. */ *(vuip)addr = value; mb(); mb(); /* magic */ @@ -263,22 +248,24 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ */ draina(); - /* now look for any errors */ + /* Now look for any errors. */ stat0 = *(vuip)APECS_IOC_DCSR; - if (stat0 & 0xffe0U) { /* is any error bit set? */ - /* if not NDEV, print status */ + + /* Is any error bit set? */ + if (stat0 & 0xffe0U) { + /* If not NDEV, print status. */ if (!(stat0 & 0x0800)) { printk("apecs.c:conf_write: got stat0=%x\n", stat0); } - /* reset error status: */ + /* Reset error status. */ *(vuip)APECS_IOC_DCSR = stat0; mb(); wrmces(0x7); /* reset machine check */ } #endif - /* if Type1 access, must reset HAE #2 so normal IO space ops work */ + /* If Type1 access, must reset HAE #2 so normal IO space ops work. */ if (type1) { *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); @@ -286,9 +273,8 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ restore_flags(flags); } - -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int +apecs_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; @@ -296,9 +282,8 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, *value = 0xff; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x00; @@ -307,9 +292,8 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +int +apecs_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; @@ -317,13 +301,10 @@ int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, *value = 0xffff; - if (where & 0x1) { + if (where & 0x1) return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x08; @@ -331,195 +312,138 @@ int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +int +apecs_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; unsigned char type1; *value = 0xffffffff; - if (where & 0x3) { + if (where & 0x3) return PCIBIOS_BAD_REGISTER_NUMBER; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } addr |= (pci_addr << 5) + 0x18; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int +apecs_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x00; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +int +apecs_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x08; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +int +apecs_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) { unsigned long addr = APECS_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x18; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end) +void __init +apecs_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - -#ifdef CONFIG_ALPHA_XL - /* - * Set up the PCI->physical memory translation windows. - * For the XL we *must* use both windows, in order to - * maximize the amount of physical memory that can be used - * to DMA from the ISA bus, and still allow PCI bus devices - * access to all of host memory. - * - * see <asm/apecs.h> for window bases and sizes. - * - * this restriction due to the true XL motherboards' 82379AB SIO - * PCI<->ISA bridge chip which passes only 27 bits of address... - */ - - *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB1R = 0; - - *(vuip)APECS_IOC_PB2R = 1U<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB2R = 0; - -#else /* CONFIG_ALPHA_XL */ -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 1 for enabled and mapped to 0 */ - if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) && (*(vuip)APECS_IOC_TB1R == 0)) + switch (alpha_use_srm_setup) { - APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U; - APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U; - APECS_DMA_WIN_SIZE += 0x00100000U; -#if 0 - printk("apecs_init: using Window 1 settings\n"); - printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n", - *(vuip)APECS_IOC_PB1R, - *(vuip)APECS_IOC_PM1R, - *(vuip)APECS_IOC_TB1R); -#endif - } - else /* check window 2 for enabled and mapped to 0 */ - if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) && (*(vuip)APECS_IOC_TB2R == 0)) - { - APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U; - APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U; - APECS_DMA_WIN_SIZE += 0x00100000U; -#if 0 - printk("apecs_init: using Window 2 settings\n"); - printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n", - *(vuip)APECS_IOC_PB2R, - *(vuip)APECS_IOC_PM2R, - *(vuip)APECS_IOC_TB2R); + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 1 for enabled and mapped to 0. */ + if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) + && (*(vuip)APECS_IOC_TB1R == 0)) { + APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U; + APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U; + APECS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("apecs_init: using Window 1 settings\n"); + printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n", + *(vuip)APECS_IOC_PB1R, + *(vuip)APECS_IOC_PM1R, + *(vuip)APECS_IOC_TB1R); #endif - } - else /* we must use our defaults... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, window 2 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. Window 1 - * goes at 1 GB and is 1 GB large. - */ - *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ + break; + } - *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB1R = 0; + /* Check window 2 for enabled and mapped to 0. */ + if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) + && (*(vuip)APECS_IOC_TB2R == 0)) { + APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U; + APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U; + APECS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("apecs_init: using Window 2 settings\n"); + printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n", + *(vuip)APECS_IOC_PB2R, + *(vuip)APECS_IOC_PM2R, + *(vuip)APECS_IOC_TB2R); +#endif + break; + } + + /* Otherwise, we must use our defaults. */ + APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT; + APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, window 2 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. Window 1 + * goes at 1 GB and is 1 GB large. + */ + *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ + + *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); + *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB1R = 0; + break; } -#endif /* CONFIG_ALPHA_XL */ -#ifdef CONFIG_ALPHA_CABRIOLET -#ifdef NO_LONGER_NEEDED_I_HOPE /* - * JAE: HACK!!! for now, hardwire if configured... - * davidm: Older miniloader versions don't set the clock frequency - * right, so hardcode it for now. + * Finally, clear the HAXR2 register, which gets used + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... */ - if (hwrpb->sys_type == ST_DEC_EB64P) { - hwrpb->sys_type = ST_DEC_EBPC64; - } - if (hwrpb->cycle_freq == 0) { - hwrpb->cycle_freq = 275000000; - } - - /* update checksum: */ - { - unsigned long *l, sum; - - sum = 0; - for (l = (unsigned long *) hwrpb; - l < (unsigned long *) &hwrpb->chksum; - ++l) - sum += *l; - hwrpb->chksum = sum; - } -#endif /* NO_LONGER_NEEDED_I_HOPE */ -#endif /* CONFIG_ALPHA_CABRIOLET */ - - /* - * Finally, clear the HAXR2 register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... - */ - { -#if 0 - unsigned int haxr2 = *(vuip)APECS_IOC_HAXR2; mb(); - if (haxr2) printk("apecs_init: HAXR2 was 0x%x\n", haxr2); -#endif - *(vuip)APECS_IOC_HAXR2 = 0; mb(); - } - - - return mem_start; + *(vuip)APECS_IOC_HAXR2 = 0; mb(); } -int apecs_pci_clr_err(void) +int +apecs_pci_clr_err(void) { apecs_jd = *(vuip)APECS_IOC_DCSR; if (apecs_jd & 0xffe0L) { @@ -534,21 +458,24 @@ int apecs_pci_clr_err(void) return 0; } -void apecs_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +void +apecs_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) { struct el_common *mchk_header; - struct el_procdata *mchk_procdata; + struct el_apecs_procdata *mchk_procdata; struct el_apecs_sysdata_mcheck *mchk_sysdata; unsigned long *ptr; int i; - mchk_header = (struct el_common *)la_ptr; - mchk_procdata = (struct el_procdata *) - (la_ptr + mchk_header->proc_offset - sizeof(mchk_procdata->paltemp)); - mchk_sysdata = - (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); + + mchk_procdata = (struct el_apecs_procdata *) + (la_ptr + mchk_header->proc_offset + - sizeof(mchk_procdata->paltemp)); + + mchk_sysdata = (struct el_apecs_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); #ifdef DEBUG printk("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", @@ -563,23 +490,15 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); } -#endif /* DEBUG */ +#endif /* * Check if machine check is due to a badaddr() and if so, * ignore the machine check. */ -#ifdef CONFIG_ALPHA_MIKASA -#define MCHK_NO_DEVSEL 0x205L -#define MCHK_NO_TABT 0x204L - if (apecs_mcheck_expected && - (((unsigned int)mchk_header->code == MCHK_NO_DEVSEL) || - ((unsigned int)mchk_header->code == MCHK_NO_TABT)) - ) - { -#else - if (apecs_mcheck_expected && (mchk_sysdata->epic_dcsr && 0x0c00UL)) { -#endif + + if (apecs_mcheck_expected + && (mchk_sysdata->epic_dcsr & 0x0c00UL)) { apecs_mcheck_expected = 0; apecs_mcheck_taken = 1; mb(); @@ -591,7 +510,8 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, DBG(("apecs_machine_check: EXPECTED\n")); } else if (vector == 0x620 || vector == 0x630) { - wrmces(0x1f); /* disable correctable from now on */ + /* Disable correctable from now on. */ + wrmces(0x1f); mb(); draina(); printk("apecs_machine_check: HW correctable (0x%lx)\n", @@ -611,8 +531,8 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr, ptr = (unsigned long *)la_ptr; for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%lx %lx %lx\n", - i*sizeof(long), ptr[i], ptr[i+1]); + printk(KERN_CRIT " +%lx %lx %lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); } #if 0 /* doesn't work with MILO */ diff --git a/arch/alpha/kernel/cia.c b/arch/alpha/kernel/core_cia.c index 57fae7d87..9f290bf80 100644 --- a/arch/alpha/kernel/cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -1,5 +1,7 @@ /* - * Code common to all CIA chips. + * linux/arch/alpha/kernel/core_cia.c + * + * Code common to all CIA core logic chips. * * Written by David A Rusling (david.rusling@reo.mts.dec.com). * December 1995. @@ -10,12 +12,17 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/system.h> -#include <asm/io.h> -#include <asm/hwrpb.h> #include <asm/ptrace.h> -#include <asm/mmu_context.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_cia.h> +#undef __EXTERN_INLINE + +#include "proto.h" /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -23,7 +30,6 @@ * handle the system transaction. Another involves timing. Ho hum. */ -extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); /* @@ -42,16 +48,16 @@ extern asmlinkage void wrmces(unsigned long mces); * BIOS32-style PCI interface: */ -/* #define DEBUG_MCHECK */ -/* #define DEBUG_CONFIG */ +#define DEBUG_MCHECK 0 +#define DEBUG_CONFIG 0 /* #define DEBUG_DUMP_REGS */ -#ifdef DEBUG_MCHECK +#if DEBUG_MCHECK # define DBGM(args) printk args #else # define DBGM(args) #endif -#ifdef DEBUG_CONFIG +#if DEBUG_CONFIG # define DBGC(args) printk args #else # define DBGC(args) @@ -63,11 +69,6 @@ static volatile unsigned int CIA_mcheck_expected = 0; static volatile unsigned int CIA_mcheck_taken = 0; static unsigned int CIA_jd; -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT; -unsigned int CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT; -unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3; -#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -104,15 +105,16 @@ unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3; * * Notes: * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). + * (e.g., SCSI and Ethernet). * * The register selects a DWORD (32 bit) register offset. Hence it * doesn't get shifted by 2 bits as we want to "drop" the bottom two * bits. */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, + unsigned char *type1) { unsigned long addr; @@ -123,7 +125,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, if (bus == 0) { int device = device_fn >> 3; - /* type 0 configuration cycle: */ + /* Type 0 configuration cycle. */ if (device > 20) { DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n", @@ -134,7 +136,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, *type1 = 0; addr = (device_fn << 8) | (where); } else { - /* type 1 configuration cycle: */ + /* Type 1 configuration cycle. */ *type1 = 1; addr = (bus << 16) | (device_fn << 8) | (where); } @@ -143,12 +145,12 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, return 0; } - -static unsigned int conf_read(unsigned long addr, unsigned char type1) +static unsigned int +conf_read(unsigned long addr, unsigned char type1) { unsigned long flags; unsigned int stat0, value; - unsigned int cia_cfg = 0; /* to keep gcc quiet */ + unsigned int cia_cfg = 0; value = 0xffffffffU; mb(); @@ -158,12 +160,13 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vuip)CIA_IOC_CIA_ERR; *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); DBGC(("conf_read: CIA ERR was 0x%x\n", stat0)); - /* if Type1 access, must set CIA CFG */ + + /* If Type1 access, must set CIA CFG. */ if (type1) { cia_cfg = *(vuip)CIA_IOC_CFG; *(vuip)CIA_IOC_CFG = cia_cfg | 1; @@ -176,7 +179,8 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) CIA_mcheck_expected = 1; CIA_mcheck_taken = 0; mb(); - /* access configuration space: */ + + /* Access configuration space. */ value = *(vuip)addr; mb(); mb(); /* magic */ @@ -189,17 +193,17 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) mb(); #if 0 - /* - this code might be necessary if machine checks aren't taken, - but I can't get it to work on CIA-2, so its disabled. - */ + /* This code might be necessary if machine checks aren't taken, + but I can't get it to work on CIA-2, so its disabled. */ draina(); - /* now look for any errors */ + /* Now look for any errors. */ stat0 = *(vuip)CIA_IOC_CIA_ERR; DBGC(("conf_read: CIA ERR after read 0x%x\n", stat0)); - if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */ - /* if not MAS_ABT, print status */ + + /* Is any error bit set? */ + if (stat0 & 0x8FEF0FFFU) { + /* If not MAS_ABT, print status. */ if (!(stat0 & 0x0080)) { printk("CIA.c:conf_read: got stat0=%x\n", stat0); } @@ -212,7 +216,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) } #endif - /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { *(vuip)CIA_IOC_CFG = cia_cfg & ~1; mb(); @@ -224,23 +228,23 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) return value; } - -static void conf_write(unsigned long addr, unsigned int value, - unsigned char type1) +static void +conf_write(unsigned long addr, unsigned int value, unsigned char type1) { unsigned long flags; unsigned int stat0; - unsigned int cia_cfg = 0; /* to keep gcc quiet */ + unsigned int cia_cfg = 0; save_flags(flags); /* avoid getting hit by machine check */ cli(); - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vuip)CIA_IOC_CIA_ERR; *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); DBGC(("conf_write: CIA ERR was 0x%x\n", stat0)); - /* if Type1 access, must set CIA CFG */ + + /* If Type1 access, must set CIA CFG. */ if (type1) { cia_cfg = *(vuip)CIA_IOC_CFG; *(vuip)CIA_IOC_CFG = cia_cfg | 1; @@ -251,7 +255,8 @@ static void conf_write(unsigned long addr, unsigned int value, draina(); CIA_mcheck_expected = 1; mb(); - /* access configuration space: */ + + /* Access configuration space. */ *(vuip)addr = value; mb(); mb(); /* magic */ @@ -260,22 +265,22 @@ static void conf_write(unsigned long addr, unsigned int value, mb(); #if 0 - /* - * This code might be necessary if machine checks aren't taken, - * but I can't get it to work on CIA-2, so its disabled. - */ + /* This code might be necessary if machine checks aren't taken, + but I can't get it to work on CIA-2, so its disabled. */ draina(); /* Now look for any errors */ stat0 = *(vuip)CIA_IOC_CIA_ERR; DBGC(("conf_write: CIA ERR after write 0x%x\n", stat0)); - if (stat0 & 0x8FEF0FFFU) { /* is any error bit set? */ + + /* Is any error bit set? */ + if (stat0 & 0x8FEF0FFFU) { /* If not MAS_ABT, print status */ if (!(stat0 & 0x0080)) { printk("CIA.c:conf_read: got stat0=%x\n", stat0); } - /* reset error status: */ + /* Reset error status. */ *(vuip)CIA_IOC_CIA_ERR = stat0; mb(); wrmces(0x7); /* reset machine check */ @@ -283,7 +288,7 @@ static void conf_write(unsigned long addr, unsigned int value, } #endif - /* if Type1 access, must reset IOC CFG so normal IO space ops work */ + /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { *(vuip)CIA_IOC_CFG = cia_cfg & ~1; mb(); @@ -293,9 +298,8 @@ static void conf_write(unsigned long addr, unsigned int value, restore_flags(flags); } - -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int +cia_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; @@ -303,20 +307,16 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, *value = 0xff; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x00; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +int +cia_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; @@ -324,91 +324,85 @@ int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, *value = 0xffff; - if (where & 0x1) { + if (where & 0x1) return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x08; - *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +int +cia_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; unsigned char type1; *value = 0xffffffff; - if (where & 0x3) { + if (where & 0x3) return PCIBIOS_BAD_REGISTER_NUMBER; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } addr |= (pci_addr << 5) + 0x18; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int +cia_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x00; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +int +cia_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x08; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +int +cia_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) { unsigned long addr = CIA_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x18; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) +void __init +cia_init_arch(unsigned long *mem_start, unsigned long *mem_end) { unsigned int cia_tmp; @@ -416,49 +410,49 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) { unsigned int temp; temp = *(vuip)CIA_IOC_CIA_REV; mb(); - printk("CIA_init: CIA_REV was 0x%x\n", temp); + printk("cia_init: CIA_REV was 0x%x\n", temp); temp = *(vuip)CIA_IOC_PCI_LAT; mb(); - printk("CIA_init: CIA_PCI_LAT was 0x%x\n", temp); + printk("cia_init: CIA_PCI_LAT was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); - printk("CIA_init: CIA_CTRL was 0x%x\n", temp); + printk("cia_init: CIA_CTRL was 0x%x\n", temp); temp = *(vuip)0xfffffc8740000140UL; mb(); - printk("CIA_init: CIA_CTRL1 was 0x%x\n", temp); + printk("cia_init: CIA_CTRL1 was 0x%x\n", temp); temp = *(vuip)CIA_IOC_HAE_MEM; mb(); - printk("CIA_init: CIA_HAE_MEM was 0x%x\n", temp); + printk("cia_init: CIA_HAE_MEM was 0x%x\n", temp); temp = *(vuip)CIA_IOC_HAE_IO; mb(); - printk("CIA_init: CIA_HAE_IO was 0x%x\n", temp); + printk("cia_init: CIA_HAE_IO was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CFG; mb(); - printk("CIA_init: CIA_CFG was 0x%x\n", temp); + printk("cia_init: CIA_CFG was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CACK_EN; mb(); - printk("CIA_init: CIA_CACK_EN was 0x%x\n", temp); + printk("cia_init: CIA_CACK_EN was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CFG; mb(); - printk("CIA_init: CIA_CFG was 0x%x\n", temp); + printk("cia_init: CIA_CFG was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CIA_DIAG; mb(); - printk("CIA_init: CIA_DIAG was 0x%x\n", temp); + printk("cia_init: CIA_DIAG was 0x%x\n", temp); temp = *(vuip)CIA_IOC_DIAG_CHECK; mb(); - printk("CIA_init: CIA_DIAG_CHECK was 0x%x\n", temp); + printk("cia_init: CIA_DIAG_CHECK was 0x%x\n", temp); temp = *(vuip)CIA_IOC_PERF_MONITOR; mb(); - printk("CIA_init: CIA_PERF_MONITOR was 0x%x\n", temp); + printk("cia_init: CIA_PERF_MONITOR was 0x%x\n", temp); temp = *(vuip)CIA_IOC_PERF_CONTROL; mb(); - printk("CIA_init: CIA_PERF_CONTROL was 0x%x\n", temp); + printk("cia_init: CIA_PERF_CONTROL was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CIA_ERR; mb(); - printk("CIA_init: CIA_ERR was 0x%x\n", temp); + printk("cia_init: CIA_ERR was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CIA_STAT; mb(); - printk("CIA_init: CIA_STAT was 0x%x\n", temp); + printk("cia_init: CIA_STAT was 0x%x\n", temp); temp = *(vuip)CIA_IOC_MCR; mb(); - printk("CIA_init: CIA_MCR was 0x%x\n", temp); + printk("cia_init: CIA_MCR was 0x%x\n", temp); temp = *(vuip)CIA_IOC_CIA_CTRL; mb(); - printk("CIA_init: CIA_CTRL was 0x%x\n", temp); + printk("cia_init: CIA_CTRL was 0x%x\n", temp); temp = *(vuip)CIA_IOC_ERR_MASK; mb(); - printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp); + printk("cia_init: CIA_ERR_MASK was 0x%x\n", temp); temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb(); - printk("CIA_init: W0_BASE was 0x%x\n", temp); + printk("cia_init: W0_BASE was 0x%x\n", temp); temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb(); - printk("CIA_init: W1_BASE was 0x%x\n", temp); + printk("cia_init: W1_BASE was 0x%x\n", temp); temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb(); - printk("CIA_init: W2_BASE was 0x%x\n", temp); + printk("cia_init: W2_BASE was 0x%x\n", temp); temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb(); - printk("CIA_init: W3_BASE was 0x%x\n", temp); + printk("cia_init: W3_BASE was 0x%x\n", temp); } #endif /* DEBUG_DUMP_REGS */ @@ -471,152 +465,147 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end) mb(); cia_tmp = *(vuip)CIA_IOC_CIA_CTRL; - cia_tmp |= 0x400; /* turn on FILL_ERR to get mchecks */ + cia_tmp |= 0x400; /* turn on FILL_ERR to get mchecks */ *(vuip)CIA_IOC_CIA_CTRL = cia_tmp; mb(); -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 0 for enabled and mapped to 0 */ - if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) && - (*(vuip)CIA_IOC_PCI_T0_BASE == 0)) + switch (alpha_use_srm_setup) { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 0 for enabled and mapped to 0 */ + if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) + && (*(vuip)CIA_IOC_PCI_T0_BASE == 0)) { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; #if 1 - printk("cia_init: using Window 0 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W0_BASE, - *(vuip)CIA_IOC_PCI_W0_MASK, - *(vuip)CIA_IOC_PCI_T0_BASE); + printk("cia_init: using Window 0 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W0_BASE, + *(vuip)CIA_IOC_PCI_W0_MASK, + *(vuip)CIA_IOC_PCI_T0_BASE); #endif - } - else /* check window 1 for enabled and mapped to 0 */ - if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) && - (*(vuip)CIA_IOC_PCI_T1_BASE == 0)) - { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; + break; + } + + /* Check window 1 for enabled and mapped to 0. */ + if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) + && (*(vuip)CIA_IOC_PCI_T1_BASE == 0)) { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; #if 1 - printk("cia_init: using Window 1 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W1_BASE, - *(vuip)CIA_IOC_PCI_W1_MASK, - *(vuip)CIA_IOC_PCI_T1_BASE); + printk("cia_init: using Window 1 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W1_BASE, + *(vuip)CIA_IOC_PCI_W1_MASK, + *(vuip)CIA_IOC_PCI_T1_BASE); #endif - } - else /* check window 2 for enabled and mapped to 0 */ - if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) && - (*(vuip)CIA_IOC_PCI_T2_BASE == 0)) - { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) + && (*(vuip)CIA_IOC_PCI_T2_BASE == 0)) { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; #if 1 - printk("cia_init: using Window 2 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W2_BASE, - *(vuip)CIA_IOC_PCI_W2_MASK, - *(vuip)CIA_IOC_PCI_T2_BASE); + printk("cia_init: using Window 2 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W2_BASE, + *(vuip)CIA_IOC_PCI_W2_MASK, + *(vuip)CIA_IOC_PCI_T2_BASE); #endif - } - else /* check window 3 for enabled and mapped to 0 */ - if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) && - (*(vuip)CIA_IOC_PCI_T3_BASE == 0)) - { - CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U; - CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U; - CIA_DMA_WIN_SIZE += 0x00100000U; + break; + } + + /* Check window 3 for enabled and mapped to 0. */ + if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) + && (*(vuip)CIA_IOC_PCI_T3_BASE == 0)) { + CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U; + CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U; + CIA_DMA_WIN_SIZE += 0x00100000U; #if 1 - printk("cia_init: using Window 3 settings\n"); - printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)CIA_IOC_PCI_W3_BASE, - *(vuip)CIA_IOC_PCI_W3_MASK, - *(vuip)CIA_IOC_PCI_T3_BASE); + printk("cia_init: using Window 3 settings\n"); + printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)CIA_IOC_PCI_W3_BASE, + *(vuip)CIA_IOC_PCI_W3_MASK, + *(vuip)CIA_IOC_PCI_T3_BASE); #endif - } - else /* we must use our defaults which were pre-initialized... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, we may - * want to use them to do scatter/gather DMA. Window 0 - * goes at 1 GB and is 1 GB large. - */ - - *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE & 0xfff00000U); - *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN_SIZE - 1) & 0xfff00000U; - *(vuip)CIA_IOC_PCI_T0_BASE = 0; - - *(vuip)CIA_IOC_PCI_W1_BASE = 0x0; - *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; - *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; - } + break; + } - /* - * check ASN in HWRPB for validity, report if bad - */ - if (hwrpb->max_asn != MAX_ASN) { - printk("CIA_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); - hwrpb->max_asn = MAX_ASN; + /* Otherwise, we must use our defaults. */ + CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT; + CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 1,2 and 3 are disabled. In the future, + * we may want to use them to do scatter/gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + + *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); + *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)CIA_IOC_PCI_T0_BASE = 0; + + *(vuip)CIA_IOC_PCI_W1_BASE = 0x0; + *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; + *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; + break; } /* * Next, clear the CIA_CFG register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... */ - { - unsigned int cia_cfg = *((vuip)CIA_IOC_CFG); mb(); - if (cia_cfg) { - printk("CIA_init: CFG was 0x%x\n", cia_cfg); - *((vuip)CIA_IOC_CFG) = 0; mb(); - } - } + *((vuip)CIA_IOC_CFG) = 0; mb(); - { - unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); - unsigned int cia_hae_io = *((vuip)CIA_IOC_HAE_IO); -#if 0 - printk("CIA_init: HAE_MEM was 0x%x\n", cia_hae_mem); - printk("CIA_init: HAE_IO was 0x%x\n", cia_hae_io); -#endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* - sigh... For the SRM setup, unless we know apriori what the HAE - contents will be, we need to setup the arbitrary region bases - so we can test against the range of addresses and tailor the - region chosen for the SPARSE memory access. - - see include/asm-alpha/cia.h for the SPARSE mem read/write - */ - cia_sm_base_r1 = (cia_hae_mem ) & 0xe0000000UL; /* region 1 */ - cia_sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; /* region 2 */ - cia_sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; /* region 3 */ - - /* - Set the HAE cache, so that setup_arch() code - will use the SRM setting always. Our readb/writeb - code in cia.h expects never to have to change - the contents of the HAE. - */ - hae.cache = cia_hae_mem; -#else /* SRM_SETUP */ - *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); - cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); - *((vuip)CIA_IOC_HAE_IO) = 0; mb(); - cia_hae_io = *((vuip)CIA_IOC_HAE_IO); -#endif /* SRM_SETUP */ + + /* + * Sigh... For the SRM setup, unless we know apriori what the HAE + * contents will be, we need to setup the arbitrary region bases + * so we can test against the range of addresses and tailor the + * region chosen for the SPARSE memory access. + * + * See include/asm-alpha/cia.h for the SPARSE mem read/write. + */ + if (alpha_use_srm_setup) { + unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM); + + alpha_mv.sm_base_r1 = (cia_hae_mem ) & 0xe0000000UL; + alpha_mv.sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; + alpha_mv.sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; + + /* + * Set the HAE cache, so that setup_arch() code + * will use the SRM setting always. Our readb/writeb + * code in cia.h expects never to have to change + * the contents of the HAE. + */ + alpha_mv.hae_cache = cia_hae_mem; + + alpha_mv.mv_readb = cia_srm_readb; + alpha_mv.mv_readw = cia_srm_readw; + alpha_mv.mv_writeb = cia_srm_writeb; + alpha_mv.mv_writew = cia_srm_writew; + } else { + *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); + *((vuip)CIA_IOC_HAE_MEM); /* read it back. */ + *((vuip)CIA_IOC_HAE_IO) = 0; mb(); + *((vuip)CIA_IOC_HAE_IO); /* read it back. */ } - - return mem_start; } -int cia_pci_clr_err(void) +static int +cia_pci_clr_err(void) { CIA_jd = *(vuip)CIA_IOC_CIA_ERR; DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd)); @@ -625,11 +614,12 @@ int cia_pci_clr_err(void) return 0; } -void cia_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +void +cia_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) { struct el_common *mchk_header; - struct el_procdata *mchk_procdata; + struct el_CIA_procdata *mchk_procdata; struct el_CIA_sysdata_mcheck *mchk_sysdata; unsigned long * ptr; const char * reason; @@ -637,8 +627,10 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, long i; mchk_header = (struct el_common *)la_ptr; - mchk_procdata = (struct el_procdata *) + + mchk_procdata = (struct el_CIA_procdata *) (la_ptr + mchk_header->proc_offset); + mchk_sysdata = (struct el_CIA_sysdata_mcheck *) (la_ptr + mchk_header->sys_offset); @@ -651,7 +643,7 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear)); -#ifdef DEBUG_MCHECK +#if DEBUG_MCHECK { unsigned long *ptr; int i; @@ -686,7 +678,7 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, switch ((unsigned int) mchk_header->code) { case MCHK_K_TPERR: reason = "tag parity error"; break; case MCHK_K_TCPERR: reason = "tag control parity error"; break; - case MCHK_K_HERR: reason = "generic hard error"; break; + case MCHK_K_HERR: reason = "generic hard error"; break; case MCHK_K_ECC_C: reason = "correctable ECC error"; break; case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; @@ -694,7 +686,7 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, case 0x96: reason = "i-cache read retryable error"; break; case 0x98: reason = "processor detected hard error"; break; - /* system specific (these are for Alcor, at least): */ + /* System specific (these are for Alcor, at least): */ case 0x203: reason = "system detected uncorrectable ECC error"; break; case 0x205: reason = "parity error detected by CIA"; break; case 0x207: reason = "non-existent memory error"; break; @@ -720,16 +712,16 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr, wrmces(rdmces()); /* reset machine check pending flag */ mb(); - printk(KERN_CRIT " CIA machine check: %s%s\n", + printk(KERN_CRIT "CIA machine check: %s%s\n", reason, mchk_header->retry ? " (retryable)" : ""); printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx pc=0x%lx\n", vector, la_ptr, regs->pc); - /* dump the the logout area to give all info: */ + /* Dump the logout area to give all info. */ ptr = (unsigned long *)la_ptr; for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%8lx %016lx %016lx\n", + printk(KERN_CRIT " +%8lx %016lx %016lx\n", i*sizeof(long), ptr[i], ptr[i+1]); } } diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/core_lca.c index a0b8aea8d..fe1e77952 100644 --- a/arch/alpha/kernel/lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -1,5 +1,7 @@ /* - * Code common to all LCA chips. + * linux/arch/alpha/kernel/core_lca.c + * + * Code common to all LCA core logic chips. * * Written by David Mosberger (davidm@cs.arizona.edu) with some code * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit @@ -9,18 +11,24 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/init.h> +#include <linux/tty.h> #include <asm/ptrace.h> #include <asm/system.h> +#include <asm/smp.h> + +#define __EXTERN_INLINE inline #include <asm/io.h> +#include <asm/core_lca.h> +#undef __EXTERN_INLINE + +#include "proto.h" /* * BIOS32-style PCI interface: */ -#define vulp volatile unsigned long * -#define vuip volatile unsigned int * - /* * Machine check reasons. Defined according to PALcode sources * (osf.h and platform.h). @@ -37,6 +45,7 @@ #define MCHK_K_DCPERR 0x0092 #define MCHK_K_ICPERR 0x0094 + /* * Platform-specific machine-check reasons: */ @@ -44,10 +53,6 @@ #define MCHK_K_SIO_IOCHK 0x206 /* all platforms so far */ #define MCHK_K_DCSR 0x208 /* all but Noname */ -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT; -unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT; -#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -84,14 +89,15 @@ unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT; * * Notes: * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). + * (e.g., SCSI and Ethernet). * * The register selects a DWORD (32 bit) register offset. Hence it * doesn't get shifted by 2 bits as we want to "drop" the bottom two * bits. */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr) + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr) { unsigned long addr; @@ -99,7 +105,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, int device = device_fn >> 3; int func = device_fn & 0x7; - /* type 0 configuration cycle: */ + /* Type 0 configuration cycle. */ if (device > 12) { return -1; @@ -108,7 +114,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, *(vulp)LCA_IOC_CONF = 0; addr = (1 << (11 + device)) | (func << 8) | where; } else { - /* type 1 configuration cycle: */ + /* Type 1 configuration cycle. */ *(vulp)LCA_IOC_CONF = 1; addr = (bus << 16) | (device_fn << 8) | where; } @@ -116,8 +122,8 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, return 0; } - -static unsigned int conf_read(unsigned long addr) +static unsigned int +conf_read(unsigned long addr) { unsigned long flags, code, stat0; unsigned int value; @@ -125,13 +131,12 @@ static unsigned int conf_read(unsigned long addr) save_flags(flags); cli(); - /* reset status register to avoid loosing errors: */ + /* Reset status register to avoid loosing errors. */ stat0 = *(vulp)LCA_IOC_STAT0; *(vulp)LCA_IOC_STAT0 = stat0; mb(); - /* access configuration space: */ - + /* Access configuration space. */ value = *(vuip)addr; draina(); @@ -143,10 +148,12 @@ static unsigned int conf_read(unsigned long addr) printk("lca.c:conf_read: got stat0=%lx\n", stat0); } - /* reset error status: */ + /* Reset error status. */ *(vulp)LCA_IOC_STAT0 = stat0; mb(); - wrmces(0x7); /* reset machine check */ + + /* Reset machine check. */ + wrmces(0x7); value = 0xffffffff; } @@ -154,21 +161,20 @@ static unsigned int conf_read(unsigned long addr) return value; } - -static void conf_write(unsigned long addr, unsigned int value) +static void +conf_write(unsigned long addr, unsigned int value) { unsigned long flags, code, stat0; save_flags(flags); /* avoid getting hit by machine check */ cli(); - /* reset status register to avoid loosing errors: */ + /* Reset status register to avoid loosing errors. */ stat0 = *(vulp)LCA_IOC_STAT0; *(vulp)LCA_IOC_STAT0 = stat0; mb(); - /* access configuration space: */ - + /* Access configuration space. */ *(vuip)addr = value; draina(); @@ -180,163 +186,170 @@ static void conf_write(unsigned long addr, unsigned int value) printk("lca.c:conf_write: got stat0=%lx\n", stat0); } - /* reset error status: */ + /* Reset error status. */ *(vulp)LCA_IOC_STAT0 = stat0; mb(); - wrmces(0x7); /* reset machine check */ + + /* Reset machine check. */ + wrmces(0x7); } restore_flags(flags); } - -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int +lca_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; *value = 0xff; - if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x00; *value = conf_read(addr) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +int +lca_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; *value = 0xffff; - if (where & 0x1) { + if (where & 0x1) return PCIBIOS_BAD_REGISTER_NUMBER; - } - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x08; *value = conf_read(addr) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +int +lca_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; *value = 0xffffffff; - if (where & 0x3) { + if (where & 0x3) return PCIBIOS_BAD_REGISTER_NUMBER; - } - if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x18; *value = conf_read(addr); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int +lca_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x00; conf_write(addr, value << ((where & 3) * 8)); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +int +lca_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x08; conf_write(addr, value << ((where & 3) * 8)); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +int +lca_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; - if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x18; conf_write(addr, value << ((where & 3) * 8)); return PCIBIOS_SUCCESSFUL; } - -unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) +void __init +lca_init_arch(unsigned long *mem_start, unsigned long *mem_end) { -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 0 for enabled and mapped to 0 */ - if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) && - (*(vulp)LCA_IOC_T_BASE0 == 0)) + switch (alpha_use_srm_setup) { - LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL; - LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL; - LCA_DMA_WIN_SIZE += 1; -#if 1 - printk("lca_init: using Window 0 settings\n"); - printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)LCA_IOC_W_BASE0, - *(vulp)LCA_IOC_W_MASK0, - *(vulp)LCA_IOC_T_BASE0); + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 0 for enabled and mapped to 0. */ + if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) + && (*(vulp)LCA_IOC_T_BASE0 == 0)) { + LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL; + LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL; + LCA_DMA_WIN_SIZE += 1; +#if 0 + printk("lca_init: using Window 0 settings\n"); + printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)LCA_IOC_W_BASE0, + *(vulp)LCA_IOC_W_MASK0, + *(vulp)LCA_IOC_T_BASE0); #endif - } - else /* check window 2 for enabled and mapped to 0 */ - if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) && - (*(vulp)LCA_IOC_T_BASE1 == 0)) - { - LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL; - LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL; - LCA_DMA_WIN_SIZE += 1; + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) + && (*(vulp)LCA_IOC_T_BASE1 == 0)) { + LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL; + LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL; + LCA_DMA_WIN_SIZE += 1; #if 1 - printk("lca_init: using Window 1 settings\n"); - printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)LCA_IOC_W_BASE1, - *(vulp)LCA_IOC_W_MASK1, - *(vulp)LCA_IOC_T_BASE1); + printk("lca_init: using Window 1 settings\n"); + printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)LCA_IOC_W_BASE1, + *(vulp)LCA_IOC_W_MASK1, + *(vulp)LCA_IOC_T_BASE1); #endif - } - else /* we must use our defaults... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, window 1 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. Window 0 - * goes at 1 GB and is 1 GB large. - */ - *(vulp)LCA_IOC_W_BASE1 = 0UL<<33; + break; + } - *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE; - *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1; - *(vulp)LCA_IOC_T_BASE0 = 0; + /* Otherwise, we must use our defaults. */ + LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT; + LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, window 1 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + *(vulp)LCA_IOC_W_BASE1 = 0UL<<33; + + *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE_DEFAULT; + *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE_DEFAULT - 1; + *(vulp)LCA_IOC_T_BASE0 = 0; + break; } /* @@ -345,10 +358,8 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) * data parity errors. */ *(vulp)LCA_IOC_PAR_DIS = 1UL<<5; - return mem_start; } - /* * Constants used during machine-check handling. I suppose these * could be moved into lca.h but I don't see much reason why anybody @@ -373,12 +384,12 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) #define IOC_LOST ( 1<<5) #define IOC_P_NBR ((__u32) ~((1<<13) - 1)) - -void mem_error (unsigned long esr, unsigned long ear) +static void +mem_error (unsigned long esr, unsigned long ear) { printk(" %s %s error to %s occurred at address %x\n", - *((esr & ESR_CEE) ? "Correctable" : - (esr & ESR_UEE) ? "Uncorrectable" : "A"), + ((esr & ESR_CEE) ? "Correctable" : + (esr & ESR_UEE) ? "Uncorrectable" : "A"), (esr & ESR_WRE) ? "write" : "read", (esr & ESR_SOR) ? "memory" : "b-cache", (unsigned) (ear & 0x1ffffff8)); @@ -396,8 +407,8 @@ void mem_error (unsigned long esr, unsigned long ear) } } - -void ioc_error (__u32 stat0, __u32 stat1) +static void +ioc_error (__u32 stat0, __u32 stat1) { static const char * const pci_cmd[] = { "Interrupt Acknowledge", "Special", "I/O Read", "I/O Write", @@ -427,9 +438,9 @@ void ioc_error (__u32 stat0, __u32 stat1) } } - -void lca_machine_check (unsigned long vector, unsigned long la, - struct pt_regs *regs) +void +lca_machine_check (unsigned long vector, unsigned long la, + struct pt_regs *regs) { unsigned long * ptr; const char * reason; @@ -440,6 +451,7 @@ void lca_machine_check (unsigned long vector, unsigned long la, printk(KERN_CRIT "lca: machine check (la=0x%lx,pc=0x%lx)\n", la, regs->pc); el.c = (struct el_common *) la; + /* * The first quadword after the common header always seems to * be the machine check reason---don't know why this isn't @@ -504,7 +516,7 @@ void lca_machine_check (unsigned long vector, unsigned long la, printk(KERN_CRIT " Unknown errorlog size %d\n", el.c->size); } - /* dump the the logout area to give all info: */ + /* Dump the logout area to give all info. */ ptr = (unsigned long *) la; for (i = 0; i < el.c->size / sizeof(long); i += 2) { @@ -523,11 +535,11 @@ lca_clock_print(void) { long pmr_reg; - pmr_reg = READ_PMR; + pmr_reg = LCA_READ_PMR; printk("Status of clock control:\n"); - printk("\tPrimary clock divisor\t0x%x\n", GET_PRIMARY(pmr_reg)); - printk("\tOverride clock divisor\t0x%x\n", GET_OVERRIDE(pmr_reg)); + printk("\tPrimary clock divisor\t0x%lx\n", LCA_GET_PRIMARY(pmr_reg)); + printk("\tOverride clock divisor\t0x%lx\n", LCA_GET_OVERRIDE(pmr_reg)); printk("\tInterrupt override is %s\n", (pmr_reg & LCA_PMR_INTO) ? "on" : "off"); printk("\tDMA override is %s\n", @@ -540,8 +552,8 @@ lca_get_clock(void) { long pmr_reg; - pmr_reg = READ_PMR; - return(GET_PRIMARY(pmr_reg)); + pmr_reg = LCA_READ_PMR; + return(LCA_GET_PRIMARY(pmr_reg)); } @@ -550,9 +562,9 @@ lca_clock_fiddle(int divisor) { long pmr_reg; - pmr_reg = READ_PMR; - SET_PRIMARY_CLOCK(pmr_reg, divisor); + pmr_reg = LCA_READ_PMR; + LCA_SET_PRIMARY_CLOCK(pmr_reg, divisor); /* lca_norm_clock = divisor; */ - WRITE_PMR(pmr_reg); + LCA_WRITE_PMR(pmr_reg); mb(); } diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c new file mode 100644 index 000000000..0e101eba8 --- /dev/null +++ b/arch/alpha/kernel/core_mcpcia.c @@ -0,0 +1,970 @@ +/* + * linux/arch/alpha/kernel/core_mcpcia.c + * + * Code common to all MCbus-PCI Adaptor core logic chipsets + * + * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/pci.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_mcpcia.h> +#undef __EXTERN_INLINE + +#include "proto.h" + +/* + * NOTE: Herein lie back-to-back mb instructions. They are magic. + * One plausible explanation is that the i/o controller does not properly + * handle the system transaction. Another involves timing. Ho hum. + */ + +extern asmlinkage void wrmces(unsigned long mces); + +/* + * BIOS32-style PCI interface: + */ + +#undef DEBUG_CFG + +#ifdef DEBUG_CFG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + +#undef DEBUG_PCI + +#ifdef DEBUG_PCI +# define DBG_PCI(args) printk args +#else +# define DBG_PCI(args) +#endif + +#define DEBUG_MCHECK + +#ifdef DEBUG_MCHECK +# define DBG_MCK(args) printk args +# define DEBUG_MCHECK_DUMP +#else +# define DBG_MCK(args) +#endif + +#define vuip volatile unsigned int * +#define vulp volatile unsigned long * + +static volatile unsigned int MCPCIA_mcheck_expected[NR_CPUS]; +static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS]; +static unsigned int MCPCIA_jd[NR_CPUS]; + +#define MCPCIA_MAX_HOSES 2 +static int mcpcia_num_hoses = 0; + +static int pci_probe_enabled = 0; /* disable to start */ + +static struct linux_hose_info *mcpcia_root = NULL, *mcpcia_last_hose; + +static inline unsigned long long_align(unsigned long addr) +{ + return ((addr + (sizeof(unsigned long) - 1)) & + ~(sizeof(unsigned long) - 1)); +} + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address and setup the MCPCIA_HAXR2 register + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static unsigned int +conf_read(unsigned long addr, unsigned char type1, + struct linux_hose_info *hose) +{ + unsigned long flags; + unsigned long hoseno = hose->pci_hose_index; + unsigned int stat0, value, temp, cpu; + + cpu = smp_processor_id(); + + save_and_cli(flags); + + DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n", + addr, type1, hoseno)); + + /* Reset status register to avoid losing errors. */ + stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); + *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); + temp = *(vuip)MCPCIA_CAP_ERR(hoseno); + DBG_CFG(("conf_read: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); + + mb(); + draina(); + MCPCIA_mcheck_expected[cpu] = 1; + MCPCIA_mcheck_taken[cpu] = 0; + mb(); + + /* Access configuration space. */ + value = *((vuip)addr); + mb(); + mb(); /* magic */ + + if (MCPCIA_mcheck_taken[cpu]) { + MCPCIA_mcheck_taken[cpu] = 0; + value = 0xffffffffU; + mb(); + } + MCPCIA_mcheck_expected[cpu] = 0; + mb(); + + DBG_CFG(("conf_read(): finished\n")); + + restore_flags(flags); + return value; +} + +static void +conf_write(unsigned long addr, unsigned int value, unsigned char type1, + struct linux_hose_info *hose) +{ + unsigned long flags; + unsigned long hoseno = hose->pci_hose_index; + unsigned int stat0, temp, cpu; + + cpu = smp_processor_id(); + + save_and_cli(flags); /* avoid getting hit by machine check */ + + /* Reset status register to avoid losing errors. */ + stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); + *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); + temp = *(vuip)MCPCIA_CAP_ERR(hoseno); + DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); + + draina(); + MCPCIA_mcheck_expected[cpu] = 1; + mb(); + + /* Access configuration space. */ + *((vuip)addr) = value; + mb(); + mb(); /* magic */ + temp = *(vuip)MCPCIA_CAP_ERR(hoseno); /* read to force the write */ + MCPCIA_mcheck_expected[cpu] = 0; + mb(); + + DBG_CFG(("conf_write(): finished\n")); + restore_flags(flags); +} + +static int +mk_conf_addr(struct linux_hose_info *hose, + u8 bus, u8 device_fn, u8 where, + unsigned long *pci_addr, unsigned char *type1) +{ + unsigned long addr; + + if (!pci_probe_enabled) /* if doing standard pci_init(), ignore */ + return -1; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + /* Type 1 configuration cycle for *ALL* busses. */ + *type1 = 1; + + if (hose->pci_first_busno == bus) + bus = 0; + addr = (bus << 16) | (device_fn << 8) | (where); + addr <<= 5; /* swizzle for SPARSE */ + addr |= hose->pci_config_space; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +/* FIXME: At some point we should update these routines to use the new + PCI interface, which can jump through these hoops for us. */ + +static inline int +hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xff; + + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x00; + *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +static inline int +hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xffff; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x08; + *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +static inline int +hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xffffffff; + + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x18; + *value = conf_read(addr, type1, hose); + return PCIBIOS_SUCCESSFUL; +} + +static inline int +hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x00; + conf_write(addr, value << ((where & 3) * 8), type1, hose); + return PCIBIOS_SUCCESSFUL; +} + +static inline int +hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x08; + conf_write(addr, value << ((where & 3) * 8), type1, hose); + return PCIBIOS_SUCCESSFUL; +} + +static inline int +hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, + struct linux_hose_info *hose) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= 0x18; + conf_write(addr, value << ((where & 3) * 8), type1, hose); + return PCIBIOS_SUCCESSFUL; +} + +int +mcpcia_pcibios_read_config_byte (u8 bus, u8 devfn, u8 where, u8 *value) +{ + return hose_read_config_byte(bus, devfn, where, value, bus2hose[bus]); +} + +int +mcpcia_pcibios_read_config_word (u8 bus, u8 devfn, u8 where, u16 *value) +{ + return hose_read_config_word(bus, devfn, where, value, bus2hose[bus]); +} + +int +mcpcia_pcibios_read_config_dword (u8 bus, u8 devfn, u8 where, u32 *value) +{ + return hose_read_config_dword(bus, devfn, where, value, bus2hose[bus]); +} + +int +mcpcia_pcibios_write_config_byte (u8 bus, u8 devfn, u8 where, u8 value) +{ + return hose_write_config_byte(bus, devfn, where, value, bus2hose[bus]); +} + +int +mcpcia_pcibios_write_config_word (u8 bus, u8 devfn, u8 where, u16 value) +{ + return hose_write_config_word(bus, devfn, where, value, bus2hose[bus]); +} + +int +mcpcia_pcibios_write_config_dword (u8 bus, u8 devfn, u8 where, u32 val) +{ + return hose_write_config_dword(bus, devfn, where, val, bus2hose[bus]); +} + +void __init +mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + struct linux_hose_info *hose; + unsigned int mcpcia_err; + unsigned int pci_rev; + int h; + + *mem_start = long_align(*mem_start); + + for (h = 0; h < NR_CPUS; h++) { + MCPCIA_mcheck_expected[h] = 0; + MCPCIA_mcheck_taken[h] = 0; + } + + /* First, find how many hoses we have. */ + for (h = 0; h < MCPCIA_MAX_HOSES; h++) { + pci_rev = *(vuip)MCPCIA_REV(h); +#if 0 + printk("mcpcia_init: got 0x%x for PCI_REV for hose %d\n", + pci_rev, h); +#endif + if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) { + mcpcia_num_hoses++; + + hose = (struct linux_hose_info *)*mem_start; + *mem_start = long_align(*mem_start + sizeof(*hose)); + + memset(hose, 0, sizeof(*hose)); + + if (mcpcia_root) + mcpcia_last_hose->next = hose; + else + mcpcia_root = hose; + mcpcia_last_hose = hose; + + hose->pci_io_space = MCPCIA_IO(h); + hose->pci_mem_space = MCPCIA_DENSE(h); + hose->pci_config_space = MCPCIA_CONF(h); + hose->pci_sparse_space = MCPCIA_SPARSE(h); + hose->pci_hose_index = h; + hose->pci_first_busno = 255; + hose->pci_last_busno = 0; + } + } + +#if 1 + printk("mcpcia_init: found %d hoses\n", mcpcia_num_hoses); +#endif + + /* Now do init for each hose. */ + for (hose = mcpcia_root; hose; hose = hose->next) { + h = hose->pci_hose_index; +#if 0 + printk("mcpcia_init: -------- hose %d --------\n",h); + printk("MCPCIA_REV 0x%x\n", *(vuip)MCPCIA_REV(h)); + printk("MCPCIA_WHOAMI 0x%x\n", *(vuip)MCPCIA_WHOAMI(h)); + printk("MCPCIA_HAE_MEM 0x%x\n", *(vuip)MCPCIA_HAE_MEM(h)); + printk("MCPCIA_HAE_IO 0x%x\n", *(vuip)MCPCIA_HAE_IO(h)); + printk("MCPCIA_HAE_DENSE 0x%x\n", *(vuip)MCPCIA_HAE_DENSE(h)); + printk("MCPCIA_INT_CTL 0x%x\n", *(vuip)MCPCIA_INT_CTL(h)); + printk("MCPCIA_INT_REQ 0x%x\n", *(vuip)MCPCIA_INT_REQ(h)); + printk("MCPCIA_INT_TARG 0x%x\n", *(vuip)MCPCIA_INT_TARG(h)); + printk("MCPCIA_INT_ADR 0x%x\n", *(vuip)MCPCIA_INT_ADR(h)); + printk("MCPCIA_INT_ADR_EXT 0x%x\n", *(vuip)MCPCIA_INT_ADR_EXT(h)); + printk("MCPCIA_INT_MASK0 0x%x\n", *(vuip)MCPCIA_INT_MASK0(h)); + printk("MCPCIA_INT_MASK1 0x%x\n", *(vuip)MCPCIA_INT_MASK1(h)); + printk("MCPCIA_HBASE 0x%x\n", *(vuip)MCPCIA_HBASE(h)); +#endif + + /* + * Set up error reporting. Make sure CPU_PE is OFF in the mask. + */ +#if 0 + mcpcia_err = *(vuip)MCPCIA_ERR_MASK(h); + mcpcia_err &= ~4; + *(vuip)MCPCIA_ERR_MASK(h) = mcpcia_err; + mb(); + mcpcia_err = *(vuip)MCPCIA_ERR_MASK; +#endif + + mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); + mcpcia_err |= 0x0006; /* master/target abort */ + *(vuip)MCPCIA_CAP_ERR(h) = mcpcia_err; + mb() ; + mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); + + switch (alpha_use_srm_setup) + { + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 0 for enabled and mapped to 0. */ + if (((*(vuip)MCPCIA_W0_BASE(h) & 3) == 1) + && (*(vuip)MCPCIA_T0_BASE(h) == 0) + && ((*(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { + MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W0_BASE(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("mcpcia_init: using Window 0 settings\n"); + printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)MCPCIA_W0_BASE(h), + *(vuip)MCPCIA_W0_MASK(h), + *(vuip)MCPCIA_T0_BASE(h)); +#endif + break; + } + + /* Check window 1 for enabled and mapped to 0. */ + if (((*(vuip)MCPCIA_W1_BASE(h) & 3) == 1) + && (*(vuip)MCPCIA_T1_BASE(h) == 0) + && ((*(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { + MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W1_BASE(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("mcpcia_init: using Window 1 settings\n"); + printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)MCPCIA_W1_BASE(h), + *(vuip)MCPCIA_W1_MASK(h), + *(vuip)MCPCIA_T1_BASE(h)); +#endif + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if (((*(vuip)MCPCIA_W2_BASE(h) & 3) == 1) + && (*(vuip)MCPCIA_T2_BASE(h) == 0) + && ((*(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { + MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W2_BASE(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("mcpcia_init: using Window 2 settings\n"); + printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)MCPCIA_W2_BASE(h), + *(vuip)MCPCIA_W2_MASK(h), + *(vuip)MCPCIA_T2_BASE(h)); +#endif + break; + } + + /* Check window 3 for enabled and mapped to 0. */ + if (((*(vuip)MCPCIA_W3_BASE(h) & 3) == 1) + && (*(vuip)MCPCIA_T3_BASE(h) == 0) + && ((*(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U) > 0x0ff00000U)) { + MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W3_BASE(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U; + MCPCIA_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("mcpcia_init: using Window 3 settings\n"); + printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)MCPCIA_W3_BASE(h), + *(vuip)MCPCIA_W3_MASK(h), + *(vuip)MCPCIA_T3_BASE(h)); +#endif + break; + } + + /* Otherwise, we must use our defaults. */ + MCPCIA_DMA_WIN_BASE = MCPCIA_DMA_WIN_BASE_DEFAULT; + MCPCIA_DMA_WIN_SIZE = MCPCIA_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 1,2 and 3 are disabled. In the + * future, we may want to use them to do scatter/ + * gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + + *(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); + *(vuip)MCPCIA_W0_MASK(h) = (MCPCIA_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)MCPCIA_T0_BASE(h) = 0; + + *(vuip)MCPCIA_W1_BASE(h) = 0x0 ; + *(vuip)MCPCIA_W2_BASE(h) = 0x0 ; + *(vuip)MCPCIA_W3_BASE(h) = 0x0 ; + + *(vuip)MCPCIA_HBASE(h) = 0x0 ; + mb(); + break; + } +#if 0 + { + unsigned int mcpcia_int_ctl = *((vuip)MCPCIA_INT_CTL(h)); + printk("mcpcia_init: INT_CTL was 0x%x\n", mcpcia_int_ctl); + *(vuip)MCPCIA_INT_CTL(h) = 1U; mb(); + mcpcia_int_ctl = *(vuip)MCPCIA_INT_CTL(h); + } +#endif + + /* + * Sigh... For the SRM setup, unless we know apriori what the HAE + * contents will be, we need to setup the arbitrary region bases + * so we can test against the range of addresses and tailor the + * region chosen for the SPARSE memory access. + * + * See include/asm-alpha/mcpcia.h for the SPARSE mem read/write. + */ + if (alpha_use_srm_setup) { + unsigned int mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h); + + alpha_mv.sm_base_r1 = (mcpcia_hae_mem ) & 0xe0000000UL; + alpha_mv.sm_base_r2 = (mcpcia_hae_mem << 16) & 0xf8000000UL; + alpha_mv.sm_base_r3 = (mcpcia_hae_mem << 24) & 0xfc000000UL; + + /* + * Set the HAE cache, so that setup_arch() code + * will use the SRM setting always. Our readb/writeb + * code in mcpcia.h expects never to have to change + * the contents of the HAE. + */ + alpha_mv.hae_cache = mcpcia_hae_mem; + + alpha_mv.mv_readb = mcpcia_srm_readb; + alpha_mv.mv_readw = mcpcia_srm_readw; + alpha_mv.mv_writeb = mcpcia_srm_writeb; + alpha_mv.mv_writew = mcpcia_srm_writew; + } else { + *(vuip)MCPCIA_HAE_MEM(h) = 0U; mb(); + *(vuip)MCPCIA_HAE_MEM(h); /* read it back. */ + *(vuip)MCPCIA_HAE_IO(h) = 0; mb(); + *(vuip)MCPCIA_HAE_IO(h); /* read it back. */ + } + } +} + +static int +mcpcia_pci_clr_err(int h) +{ + unsigned int cpu = smp_processor_id(); + + MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); +#if 0 + DBG_MCK(("MCPCIA_pci_clr_err: MCPCIA CAP_ERR(%d) after read 0x%x\n", + h, MCPCIA_jd[cpu])); +#endif + *(vuip)MCPCIA_CAP_ERR(h) = 0xffffffff; mb(); /* clear them all */ + MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); + return 0; +} + +static void +mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout) +{ + struct el_common_EV5_uncorrectable_mcheck *frame; + int i; + + frame = &logout->procdata; + + /* Print PAL fields */ + for (i = 0; i < 24; i += 2) { + printk("\tpal temp[%d-%d]\t\t= %16lx %16lx\n\r", + i, i+1, frame->paltemp[i], frame->paltemp[i+1]); + } + for (i = 0; i < 8; i += 2) { + printk("\tshadow[%d-%d]\t\t= %16lx %16lx\n\r", + i, i+1, frame->shadow[i], + frame->shadow[i+1]); + } + printk("\tAddr of excepting instruction\t= %16lx\n\r", + frame->exc_addr); + printk("\tSummary of arithmetic traps\t= %16lx\n\r", + frame->exc_sum); + printk("\tException mask\t\t\t= %16lx\n\r", + frame->exc_mask); + printk("\tBase address for PALcode\t= %16lx\n\r", + frame->pal_base); + printk("\tInterrupt Status Reg\t\t= %16lx\n\r", + frame->isr); + printk("\tCURRENT SETUP OF EV5 IBOX\t= %16lx\n\r", + frame->icsr); + printk("\tI-CACHE Reg %s parity error\t= %16lx\n\r", + (frame->ic_perr_stat & 0x800L) ? + "Data" : "Tag", + frame->ic_perr_stat); + printk("\tD-CACHE error Reg\t\t= %16lx\n\r", + frame->dc_perr_stat); + if (frame->dc_perr_stat & 0x2) { + switch (frame->dc_perr_stat & 0x03c) { + case 8: + printk("\t\tData error in bank 1\n\r"); + break; + case 4: + printk("\t\tData error in bank 0\n\r"); + break; + case 20: + printk("\t\tTag error in bank 1\n\r"); + break; + case 10: + printk("\t\tTag error in bank 0\n\r"); + break; + } + } + printk("\tEffective VA\t\t\t= %16lx\n\r", + frame->va); + printk("\tReason for D-stream\t\t= %16lx\n\r", + frame->mm_stat); + printk("\tEV5 SCache address\t\t= %16lx\n\r", + frame->sc_addr); + printk("\tEV5 SCache TAG/Data parity\t= %16lx\n\r", + frame->sc_stat); + printk("\tEV5 BC_TAG_ADDR\t\t\t= %16lx\n\r", + frame->bc_tag_addr); + printk("\tEV5 EI_ADDR: Phys addr of Xfer\t= %16lx\n\r", + frame->ei_addr); + printk("\tFill Syndrome\t\t\t= %16lx\n\r", + frame->fill_syndrome); + printk("\tEI_STAT reg\t\t\t= %16lx\n\r", + frame->ei_stat); + printk("\tLD_LOCK\t\t\t\t= %16lx\n\r", + frame->ld_lock); +} + +void +mcpcia_machine_check(unsigned long type, unsigned long la_ptr, + struct pt_regs * regs) +{ +#if 0 + printk("mcpcia machine check ignored\n") ; +#else + struct el_common *mchk_header; + struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout; + unsigned int cpu = smp_processor_id(); + int h = 0; + + mchk_header = (struct el_common *)la_ptr; + mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr; + +#if 0 + DBG_MCK(("mcpcia_machine_check: type=0x%lx la_ptr=0x%lx\n", + type, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); +#endif + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + mb(); + mb(); /* magic */ + if (MCPCIA_mcheck_expected[cpu]) { +#if 0 + DBG_MCK(("MCPCIA machine check expected\n")); +#endif + MCPCIA_mcheck_expected[cpu] = 0; + MCPCIA_mcheck_taken[cpu] = 1; + mb(); + mb(); /* magic */ + draina(); + mcpcia_pci_clr_err(h); + wrmces(0x7); + mb(); + } +#if 1 + else { + printk("MCPCIA machine check NOT expected on CPU %d\n", cpu); + DBG_MCK(("mcpcia_machine_check: type=0x%lx pc=0x%lx" + " code=0x%lx\n", + type, regs->pc, mchk_header->code)); + + MCPCIA_mcheck_expected[cpu] = 0; + MCPCIA_mcheck_taken[cpu] = 1; + mb(); + mb(); /* magic */ + draina(); + mcpcia_pci_clr_err(h); + wrmces(0x7); + mb(); +#ifdef DEBUG_MCHECK_DUMP + if (type == 0x620) + printk("MCPCIA machine check: system CORRECTABLE!\n"); + else if (type == 0x630) + printk("MCPCIA machine check: processor CORRECTABLE!\n"); + else + mcpcia_print_uncorrectable(mchk_logout); +#endif /* DEBUG_MCHECK_DUMP */ + } +#endif +#endif +} + +/*==========================================================================*/ + +#define PRIMARY(b) ((b)&0xff) +#define SECONDARY(b) (((b)>>8)&0xff) +#define SUBORDINATE(b) (((b)>>16)&0xff) + +static int __init +hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus) +{ + unsigned int devfn, l, class; + unsigned char hdr_type = 0; + unsigned int found = 0; + + for (devfn = 0; devfn < 0xff; ++devfn) { + if (PCI_FUNC(devfn) == 0) { + hose_read_config_byte(bus, devfn, PCI_HEADER_TYPE, + &hdr_type, hose); + } else if (!(hdr_type & 0x80)) { + /* not a multi-function device */ + continue; + } + + /* Check if there is anything here. */ + hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l, hose); + if (l == 0xffffffff || l == 0x00000000) { + hdr_type = 0; + continue; + } + + /* See if this is a bridge device. */ + hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION, + &class, hose); + + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + unsigned int busses; + + found++; + + hose_read_config_dword(bus, devfn, PCI_PRIMARY_BUS, + &busses, hose); + + DBG_PCI(("hose_scan_bridges: hose %d bus %d " + "slot %d busses 0x%x\n", + hose->pci_hose_index, bus, PCI_SLOT(devfn), + busses)); + + /* + * Do something with first_busno and last_busno + */ + if (hose->pci_first_busno > PRIMARY(busses)) { + hose->pci_first_busno = PRIMARY(busses); + DBG_PCI(("hose_scan_bridges: hose %d bus %d " + "slot %d change first to %d\n", + hose->pci_hose_index, bus, + PCI_SLOT(devfn), PRIMARY(busses))); + } + if (hose->pci_last_busno < SUBORDINATE(busses)) { + hose->pci_last_busno = SUBORDINATE(busses); + DBG_PCI(("hose_scan_bridges: hose %d bus %d " + "slot %d change last to %d\n", + hose->pci_hose_index, bus, + PCI_SLOT(devfn), + SUBORDINATE(busses))); + } + /* + * Now scan everything underneath the bridge. + */ + hose_scan_bridges(hose, SECONDARY(busses)); + } + } + return found; +} + +static void __init +hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus) +{ + unsigned int devfn, l, class; + unsigned char hdr_type = 0; + + for (devfn = 0; devfn < 0xff; ++devfn) { + if (PCI_FUNC(devfn) == 0) { + hose_read_config_byte(bus, devfn, PCI_HEADER_TYPE, + &hdr_type, hose); + } else if (!(hdr_type & 0x80)) { + /* not a multi-function device */ + continue; + } + + /* Check if there is anything here. */ + hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l, hose); + if (l == 0xffffffff || l == 0x00000000) { + hdr_type = 0; + continue; + } + + /* See if this is a bridge device. */ + hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION, + &class, hose); + + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + unsigned int busses; + + hose_read_config_dword(bus, devfn, PCI_PRIMARY_BUS, + &busses, hose); + + /* + * First reconfigure everything underneath the bridge. + */ + hose_reconfigure_bridges(hose, (busses >> 8) & 0xff); + + /* + * Unconfigure this bridges bus numbers, + * pci_scan_bus() will fix this up properly. + */ + busses &= 0xff000000; + hose_write_config_dword(bus, devfn, PCI_PRIMARY_BUS, + busses, hose); + } + } +} + +static void __init +mcpcia_fixup_busno(struct linux_hose_info *hose, unsigned char bus) +{ + unsigned int nbus; + + /* + * First, scan for all bridge devices underneath this hose, + * to determine the first and last busnos. + */ + if (!hose_scan_bridges(hose, 0)) { + /* none found, exit */ + hose->pci_first_busno = bus; + hose->pci_last_busno = bus; + } else { + /* + * Reconfigure all bridge devices underneath this hose. + */ + hose_reconfigure_bridges(hose, hose->pci_first_busno); + } + + /* + * Now reconfigure the hose to it's new bus number and set up + * our bus2hose mapping for this hose. + */ + nbus = hose->pci_last_busno - hose->pci_first_busno; + + hose->pci_first_busno = bus; + + DBG_PCI(("mcpcia_fixup_busno: hose %d startbus %d nbus %d\n", + hose->pci_hose_index, bus, nbus)); + + do { + bus2hose[bus++] = hose; + } while (nbus-- > 0); +} + +static void __init +mcpcia_probe(struct linux_hose_info *hose) +{ + static struct pci_bus *pchain = NULL; + struct pci_bus *pbus = &hose->pci_bus; + static unsigned char busno = 0; + + /* + * Hoses include child PCI bridges in bus-range property, + * but we don't scan each of those ourselves, Linux generic PCI + * probing code will find child bridges and link them into this + * hose's root PCI device hierarchy. + */ + + pbus->number = pbus->secondary = busno; + pbus->sysdata = hose; + + mcpcia_fixup_busno(hose, busno); + + pbus->subordinate = pci_scan_bus(pbus); /* the original! */ + + /* + * Set the maximum subordinate bus of this hose. + */ + hose->pci_last_busno = pbus->subordinate; +#if 0 + hose_write_config_byte(busno, 0, 0x41, hose->pci_last_busno, hose); +#endif + busno = pbus->subordinate + 1; + + /* + * Fixup the chain of primary PCI busses. + */ + if (pchain) { + pchain->next = &hose->pci_bus; + pchain = pchain->next; + } else { + pchain = &pci_root; + memcpy(pchain, &hose->pci_bus, sizeof(pci_root)); + } +} + +void __init +mcpcia_pci_fixup(void) +{ + struct linux_hose_info *hose; + + /* Turn on Config space access finally! */ + pci_probe_enabled = 1; + + /* For each hose, probe and setup the devices on the hose. */ + for (hose = mcpcia_root; hose; hose = hose->next) + mcpcia_probe(hose); +} diff --git a/arch/alpha/kernel/core_pyxis.c b/arch/alpha/kernel/core_pyxis.c new file mode 100644 index 000000000..ab49de096 --- /dev/null +++ b/arch/alpha/kernel/core_pyxis.c @@ -0,0 +1,634 @@ +/* + * linux/arch/alpha/kernel/core_pyxis.c + * + * Code common to all PYXIS core logic chips. + * + * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_pyxis.h> +#undef __EXTERN_INLINE + +#include "proto.h" + +/* NOTE: Herein are back-to-back mb instructions. They are magic. + One plausible explanation is that the I/O controller does not properly + handle the system transaction. Another involves timing. Ho hum. */ + +extern asmlinkage void wrmces(unsigned long mces); + +/* + * BIOS32-style PCI interface: + */ + +#ifdef DEBUG +# define DBG(args) printk args +#else +# define DBG(args) +#endif + +#define DEBUG_MCHECK +#ifdef DEBUG_MCHECK +# define DBG_MCK(args) printk args +#define DEBUG_MCHECK_DUMP +#else +# define DBG_MCK(args) +#endif + + +static volatile unsigned int PYXIS_mcheck_expected = 0; +static volatile unsigned int PYXIS_mcheck_taken = 0; +static unsigned int PYXIS_jd; + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address and setup the PYXIS_HAXR2 register + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + + DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (bus == 0) { + int device; + + device = device_fn >> 3; + /* Type 0 configuration cycle. */ +#if NOT_NOW + if (device > 20) { + DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", + device)); + return -1; + } +#endif + *type1 = 0; + addr = (device_fn << 8) | (where); + } else { + /* Type 1 configuration cycle. */ + *type1 = 1; + addr = (bus << 16) | (device_fn << 8) | (where); + } + *pci_addr = addr; + DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static unsigned int +conf_read(unsigned long addr, unsigned char type1) +{ + unsigned long flags; + unsigned int stat0, value, temp; + unsigned int pyxis_cfg = 0; + + save_and_cli(flags); /* avoid getting hit by machine check */ + + DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); + + /* Reset status register to avoid losing errors. */ + stat0 = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = stat0; mb(); + temp = *(vuip)PYXIS_ERR; /* re-read to force write */ + DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0)); + + /* If Type1 access, must set PYXIS CFG. */ + if (type1) { + pyxis_cfg = *(vuip)PYXIS_CFG; + *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); + temp = *(vuip)PYXIS_CFG; /* re-read to force write */ + DBG(("conf_read: TYPE1 access\n")); + } + + mb(); + draina(); + PYXIS_mcheck_expected = 1; + PYXIS_mcheck_taken = 0; + mb(); + + /* Access configuration space. */ + value = *(vuip)addr; + mb(); + mb(); /* magic */ + + if (PYXIS_mcheck_taken) { + PYXIS_mcheck_taken = 0; + value = 0xffffffffU; + mb(); + } + PYXIS_mcheck_expected = 0; + mb(); + + /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ + if (type1) { + *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); + temp = *(vuip)PYXIS_CFG; /* re-read to force write */ + } + + DBG(("conf_read(): finished\n")); + + restore_flags(flags); + return value; +} + +static void +conf_write(unsigned long addr, unsigned int value, unsigned char type1) +{ + unsigned long flags; + unsigned int stat0, temp; + unsigned int pyxis_cfg = 0; + + save_and_cli(flags); /* avoid getting hit by machine check */ + + /* Reset status register to avoid losing errors. */ + stat0 = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = stat0; mb(); + temp = *(vuip)PYXIS_ERR; /* re-read to force write */ + DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0)); + + /* If Type1 access, must set PYXIS CFG. */ + if (type1) { + pyxis_cfg = *(vuip)PYXIS_CFG; + *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); + temp = *(vuip)PYXIS_CFG; /* re-read to force write */ + DBG(("conf_read: TYPE1 access\n")); + } + + draina(); + PYXIS_mcheck_expected = 1; + mb(); + + /* Access configuration space. */ + *(vuip)addr = value; + mb(); + mb(); /* magic */ + temp = *(vuip)PYXIS_ERR; /* do a PYXIS read to force the write */ + PYXIS_mcheck_expected = 0; + mb(); + + /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ + if (type1) { + *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); + temp = *(vuip)PYXIS_CFG; /* re-read to force write */ + } + + DBG(("conf_write(): finished\n")); + restore_flags(flags); +} + +int +pyxis_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xff; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x00; + *value = conf_read(addr, type1) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +int +pyxis_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffff; + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x08; + *value = conf_read(addr, type1) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + +int +pyxis_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + *value = 0xffffffff; + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x18; + *value = conf_read(addr, type1); + return PCIBIOS_SUCCESSFUL; +} + +int +pyxis_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x00; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + +int +pyxis_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x08; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + +int +pyxis_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) +{ + unsigned long addr = PYXIS_CONF; + unsigned long pci_addr; + unsigned char type1; + + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + addr |= (pci_addr << 5) + 0x18; + conf_write(addr, value << ((where & 3) * 8), type1); + return PCIBIOS_SUCCESSFUL; +} + +void __init +pyxis_enable_errors (void) +{ + unsigned int pyxis_err; + +#if 0 + printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK); + printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR); + printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ); + printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK); + printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE); + printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO); + printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG); + printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT); +#endif + + /* + * Set up error reporting. Make sure CPU_PE is OFF in the mask. + */ + pyxis_err = *(vuip)PYXIS_ERR_MASK; + pyxis_err &= ~4; + *(vuip)PYXIS_ERR_MASK = pyxis_err; mb(); + pyxis_err = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ + + pyxis_err = *(vuip)PYXIS_ERR ; + pyxis_err |= 0x180; /* master/target abort */ + *(vuip)PYXIS_ERR = pyxis_err; mb(); + pyxis_err = *(vuip)PYXIS_ERR; /* re-read to force write */ +} + +int __init +pyxis_srm_window_setup (void) +{ + switch (alpha_use_srm_setup) + { + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 0 for enabled and mapped to 0. */ + if (((*(vuip)PYXIS_W0_BASE & 3) == 1) + && (*(vuip)PYXIS_T0_BASE == 0) + && ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U)) { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 0 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W0_BASE, + *(vuip)PYXIS_W0_MASK, + *(vuip)PYXIS_T0_BASE); +#endif + break; + } + + /* Check window 1 for enabled and mapped to 0. */ + if (((*(vuip)PYXIS_W1_BASE & 3) == 1) + && (*(vuip)PYXIS_T1_BASE == 0) + && ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U)) { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 1 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W1_BASE, + *(vuip)PYXIS_W1_MASK, + *(vuip)PYXIS_T1_BASE); +#endif + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if (((*(vuip)PYXIS_W2_BASE & 3) == 1) + && (*(vuip)PYXIS_T2_BASE == 0) + && ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U)) { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 2 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W2_BASE, + *(vuip)PYXIS_W2_MASK, + *(vuip)PYXIS_T2_BASE); +#endif + break; + } + + /* Check window 3 for enabled and mapped to 0. */ + if (((*(vuip)PYXIS_W3_BASE & 3) == 1) + && (*(vuip)PYXIS_T3_BASE == 0) + && ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U)) { + PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U; + PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U; + PYXIS_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("pyxis_init: using Window 3 settings\n"); + printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", + *(vuip)PYXIS_W3_BASE, + *(vuip)PYXIS_W3_MASK, + *(vuip)PYXIS_T3_BASE); +#endif + break; + } + + /* Otherwise, we must use our defaults. */ + PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT; + PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + return 0; + } + return 1; +} + +void __init +pyxis_native_window_setup(void) +{ + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 1,2 and 3 are disabled. In the future, we may + * want to use them to do scatter/gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + + *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); + *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)PYXIS_T0_BASE = 0; + + *(vuip)PYXIS_W1_BASE = 0x0 ; + *(vuip)PYXIS_W2_BASE = 0x0 ; + *(vuip)PYXIS_W3_BASE = 0x0 ; + mb(); +} + +void __init +pyxis_finish_init_arch(void) +{ + /* + * Next, clear the PYXIS_CFG register, which gets used + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... + */ + { + unsigned int pyxis_cfg, temp; + pyxis_cfg = *(vuip)PYXIS_CFG; mb(); + if (pyxis_cfg != 0) { +#if 1 + printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg); +#endif + *(vuip)PYXIS_CFG = 0; mb(); + temp = *(vuip)PYXIS_CFG; /* re-read to force write */ + } + } + + /* + * Sigh... For the SRM setup, unless we know apriori what the HAE + * contents will be, we need to setup the arbitrary region bases + * so we can test against the range of addresses and tailor the + * region chosen for the SPARSE memory access. + * + * See include/asm-alpha/pyxis.h for the SPARSE mem read/write. + */ + if (alpha_use_srm_setup) { + unsigned int pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; + + alpha_mv.sm_base_r1 = (pyxis_hae_mem ) & 0xe0000000UL; + alpha_mv.sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL; + alpha_mv.sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL; + + /* + * Set the HAE cache, so that setup_arch() code + * will use the SRM setting always. Our readb/writeb + * code in pyxis.h expects never to have to change + * the contents of the HAE. + */ + alpha_mv.hae_cache = pyxis_hae_mem; + +#ifndef CONFIG_ALPHA_GENERIC + /* In a generic kernel, we can always use BWIO. */ + alpha_mv.mv_readb = pyxis_srm_readb; + alpha_mv.mv_readw = pyxis_srm_readw; + alpha_mv.mv_writeb = pyxis_srm_writeb; + alpha_mv.mv_writew = pyxis_srm_writew; +#endif + } else { + *(vuip)PYXIS_HAE_MEM = 0U; mb(); + *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ + *(vuip)PYXIS_HAE_IO = 0; mb(); + *(vuip)PYXIS_HAE_IO; /* re-read to force write */ + } + + /* + * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for + * enabling byte/word PCI bus space(s) access. + */ + { + unsigned int ctrl1; + ctrl1 = *(vuip) PYXIS_CTRL1; + if (!(ctrl1 & 1)) { +#if 1 + printk("PYXIS_init: enabling byte/word PCI space\n"); +#endif + *(vuip) PYXIS_CTRL1 = ctrl1 | 1; mb(); + ctrl1 = *(vuip)PYXIS_CTRL1; /* re-read */ + } + } +} + +void __init +pyxis_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + pyxis_enable_errors(); + if (!pyxis_srm_window_setup()) + pyxis_native_window_setup(); + pyxis_finish_init_arch(); +} + +static int +pyxis_pci_clr_err(void) +{ + PYXIS_jd = *(vuip)PYXIS_ERR; + DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd)); + *(vuip)PYXIS_ERR = 0x0180; mb(); + PYXIS_jd = *(vuip)PYXIS_ERR; /* re-read to force write */ + return 0; +} + +void +pyxis_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + struct el_common *mchk_header; + struct el_PYXIS_sysdata_mcheck *mchk_sysdata; + + mchk_header = (struct el_common *)la_ptr; + + mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); + +#if 0 + DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear)); +#endif +#ifdef DEBUG_MCHECK_DUMP + { + unsigned long *ptr; + int i; + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + } + } +#endif /* DEBUG_MCHECK_DUMP */ + + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + mb(); + mb(); /* magic */ + if (PYXIS_mcheck_expected) { + DBG(("PYXIS machine check expected\n")); + PYXIS_mcheck_expected = 0; + PYXIS_mcheck_taken = 1; + mb(); + mb(); /* magic */ + draina(); + pyxis_pci_clr_err(); + wrmces(0x7); + mb(); + } +#if 1 + else { + printk("PYXIS machine check NOT expected\n") ; + DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x" + " sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + PYXIS_mcheck_expected = 0; + PYXIS_mcheck_taken = 1; + mb(); + mb(); /* magic */ + draina(); + pyxis_pci_clr_err(); + wrmces(0x7); + mb(); + } +#endif +} diff --git a/arch/alpha/kernel/t2.c b/arch/alpha/kernel/core_t2.c index 69ca71404..13adb7bdf 100644 --- a/arch/alpha/kernel/t2.c +++ b/arch/alpha/kernel/core_t2.c @@ -1,5 +1,7 @@ /* - * Code common to all T2 chips. + * linux/arch/alpha/kernel/core_t2.c + * + * Code common to all T2 core logic chips. * * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com). * December 1996. @@ -7,17 +9,22 @@ * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com) * */ -#include <linux/kernel.h> #include <linux/config.h> +#include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/sched.h> +#include <linux/init.h> +#include <asm/ptrace.h> #include <asm/system.h> + +#define __EXTERN_INLINE #include <asm/io.h> -#include <asm/hwrpb.h> -#include <asm/ptrace.h> -#include <asm/mmu_context.h> +#include <asm/core_t2.h> +#undef __EXTERN_INLINE + +#include "proto.h" /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -25,9 +32,6 @@ * handle the system transaction. Another involves timing. Ho hum. */ -extern struct hwrpb_struct *hwrpb; -extern asmlinkage void wrmces(unsigned long mces); - /* * Machine check reasons. Defined according to PALcode sources * (osf.h and platform.h). @@ -56,17 +60,9 @@ extern asmlinkage void wrmces(unsigned long mces); # define DBGMC(args) #endif -#define vulp volatile unsigned long * -#define vuip volatile unsigned int * - static volatile unsigned int T2_mcheck_expected[NR_CPUS]; static volatile unsigned int T2_mcheck_taken[NR_CPUS]; -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT; -unsigned int T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT; -unsigned long t2_sm_base; -#endif /* SRM_SETUP */ /* * Given a bus, device, and function number, compute resulting @@ -103,15 +99,16 @@ unsigned long t2_sm_base; * * Notes: * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). + * (e.g., SCSI and Ethernet). * * The register selects a DWORD (32 bit) register offset. Hence it * doesn't get shifted by 2 bits as we want to "drop" the bottom two * bits. */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, + unsigned char *type1) { unsigned long addr; @@ -122,7 +119,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, if (bus == 0) { int device = device_fn >> 3; - /* type 0 configuration cycle: */ + /* Type 0 configuration cycle. */ if (device > 8) { DBG(("mk_conf_addr: device (%d)>20, returning -1\n", @@ -133,7 +130,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, *type1 = 0; addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where); } else { - /* type 1 configuration cycle: */ + /* Type 1 configuration cycle. */ *type1 = 1; addr = (bus << 16) | (device_fn << 8) | (where); } @@ -142,12 +139,12 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn, return 0; } - -static unsigned int conf_read(unsigned long addr, unsigned char type1) +static unsigned int +conf_read(unsigned long addr, unsigned char type1) { unsigned long flags; unsigned int stat0, value, cpu; - unsigned long t2_cfg = 0; /* to keep gcc quiet */ + unsigned long t2_cfg = 0; cpu = smp_processor_id(); @@ -157,13 +154,14 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); #if 0 - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vulp)T2_IOCSR; *(vulp)T2_IOCSR = stat0; mb(); DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0)); #endif - /* if Type1 access, must set T2 CFG */ + + /* If Type1 access, must set T2 CFG. */ if (type1) { t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL; *(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg; @@ -176,10 +174,12 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) T2_mcheck_expected[cpu] = 1; T2_mcheck_taken[cpu] = 0; mb(); - /* access configuration space: */ + + /* Access configuration space. */ value = *(vuip)addr; mb(); mb(); /* magic */ + if (T2_mcheck_taken[cpu]) { T2_mcheck_taken[cpu] = 0; value = 0xffffffffU; @@ -188,7 +188,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) T2_mcheck_expected[cpu] = 0; mb(); - /* if Type1 access, must reset T2 CFG so normal IO space ops work */ + /* If Type1 access, must reset T2 CFG so normal IO space ops work. */ if (type1) { *(vulp)T2_HAE_3 = t2_cfg; mb(); @@ -199,13 +199,12 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) return value; } - -static void conf_write(unsigned long addr, unsigned int value, - unsigned char type1) +static void +conf_write(unsigned long addr, unsigned int value, unsigned char type1) { unsigned long flags; unsigned int stat0, cpu; - unsigned long t2_cfg = 0; /* to keep gcc quiet */ + unsigned long t2_cfg = 0; cpu = smp_processor_id(); @@ -213,13 +212,14 @@ static void conf_write(unsigned long addr, unsigned int value, cli(); #if 0 - /* reset status register to avoid losing errors: */ + /* Reset status register to avoid losing errors. */ stat0 = *(vulp)T2_IOCSR; *(vulp)T2_IOCSR = stat0; mb(); DBG(("conf_write: T2 ERR was 0x%x\n", stat0)); #endif - /* if Type1 access, must set T2 CFG */ + + /* If Type1 access, must set T2 CFG. */ if (type1) { t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL; *(vulp)T2_HAE_3 = t2_cfg | 0x40000000UL; @@ -231,14 +231,16 @@ static void conf_write(unsigned long addr, unsigned int value, T2_mcheck_expected[cpu] = 1; mb(); - /* access configuration space: */ + + /* Access configuration space. */ *(vuip)addr = value; mb(); mb(); /* magic */ + T2_mcheck_expected[cpu] = 0; mb(); - /* if Type1 access, must reset T2 CFG so normal IO space ops work */ + /* If Type1 access, must reset T2 CFG so normal IO space ops work. */ if (type1) { *(vulp)T2_HAE_3 = t2_cfg; mb(); @@ -248,121 +250,109 @@ static void conf_write(unsigned long addr, unsigned int value, } -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int +t2_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; *value = 0xff; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x00; - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +int +t2_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; *value = 0xffff; - - if (where & 0x1) { + if (where & 0x1) return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; addr |= (pci_addr << 5) + 0x08; - *value = conf_read(addr, type1) >> ((where & 3) * 8); return PCIBIOS_SUCCESSFUL; } - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) +int +t2_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; *value = 0xffffffff; - if (where & 0x3) { + if (where & 0x3) return PCIBIOS_BAD_REGISTER_NUMBER; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } addr |= (pci_addr << 5) + 0x18; *value = conf_read(addr, type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int +t2_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x00; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) +int +t2_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x08; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) +int +t2_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) { unsigned long addr = T2_CONF; unsigned long pci_addr; unsigned char type1; - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + addr |= (pci_addr << 5) + 0x18; conf_write(addr, value << ((where & 3) * 8), type1); return PCIBIOS_SUCCESSFUL; } - -unsigned long t2_init(unsigned long mem_start, unsigned long mem_end) +void __init +t2_init_arch(unsigned long *mem_start, unsigned long *mem_end) { unsigned long t2_err; unsigned int i; @@ -394,138 +384,129 @@ unsigned long t2_init(unsigned long mem_start, unsigned long mem_end) *(vulp)T2_TBASE2); #endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 1 for enabled and mapped to 0 */ - if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) && - (*(vulp)T2_TBASE1 == 0)) + switch (alpha_use_srm_setup) { - T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL; - T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL; - T2_DMA_WIN_SIZE += 0x00100000UL; -/* DISABLE window 2!! ?? */ + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 1 for enabled and mapped to 0. */ + if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) + && (*(vulp)T2_TBASE1 == 0)) { + T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL; + T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL; + T2_DMA_WIN_SIZE += 0x00100000UL; + /* DISABLE window 2!! ?? */ #if 1 - printk("t2_init: using Window 1 settings\n"); - printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)T2_WBASE1, - *(vulp)T2_WMASK1, - *(vulp)T2_TBASE1); + printk("t2_init: using Window 1 settings\n"); + printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)T2_WBASE1, + *(vulp)T2_WMASK1, + *(vulp)T2_TBASE1); #endif - } - else /* check window 2 for enabled and mapped to 0 */ - if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) && - (*(vulp)T2_TBASE2 == 0)) - { - T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL; - T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL; - T2_DMA_WIN_SIZE += 0x00100000UL; -/* DISABLE window 1!! ?? */ + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) + && (*(vulp)T2_TBASE2 == 0)) { + T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL; + T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL; + T2_DMA_WIN_SIZE += 0x00100000UL; + /* DISABLE window 1!! ?? */ #if 1 - printk("t2_init: using Window 2 settings\n"); - printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", - *(vulp)T2_WBASE2, - *(vulp)T2_WMASK2, - *(vulp)T2_TBASE2); + printk("t2_init: using Window 2 settings\n"); + printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)T2_WBASE2, + *(vulp)T2_WMASK2, + *(vulp)T2_TBASE2); #endif - } - else /* we must use our defaults... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, window 2 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. Window 1 - * goes at 1 GB and is 1 GB large. - */ - - /* WARNING!! must correspond to the DMA_WIN params!!! */ - *(vulp)T2_WBASE1 = 0x400807ffU; - *(vulp)T2_WMASK1 = 0x3ff00000U; - *(vulp)T2_TBASE1 = 0; - - *(vulp)T2_WBASE2 = 0x0; - *(vulp)T2_HBASE = 0x0; - } + break; + } - /* - * check ASN in HWRPB for validity, report if bad - */ - if (hwrpb->max_asn != MAX_ASN) { - printk("T2_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); - hwrpb->max_asn = MAX_ASN; + /* Otherwise, we must use our defaults. */ + T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT; + T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, window 2 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. + * + * Window 1 goes at 1 GB and is 1 GB large. + */ + + /* WARNING!! must correspond to the DMA_WIN params!!! */ + *(vulp)T2_WBASE1 = 0x400807ffU; + *(vulp)T2_WMASK1 = 0x3ff00000U; + *(vulp)T2_TBASE1 = 0; + + *(vulp)T2_WBASE2 = 0x0; + *(vulp)T2_HBASE = 0x0; + break; } /* - * Finally, clear the T2_HAE_3 register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... + * Sigh... For the SRM setup, unless we know apriori what the HAE + * contents will be, we need to setup the arbitrary region bases + * so we can test against the range of addresses and tailor the + * region chosen for the SPARSE memory access. + * + * See include/asm-alpha/t2.h for the SPARSE mem read/write. */ - { - unsigned long t2_hae_1 = *(vulp)T2_HAE_1; - unsigned long t2_hae_2 = *(vulp)T2_HAE_2; - unsigned long t2_hae_3 = *(vulp)T2_HAE_3; - unsigned long t2_hae_4 = *(vulp)T2_HAE_4; -#if 1 - printk("T2_init: HAE1 was 0x%lx\n", t2_hae_1); - printk("T2_init: HAE2 was 0x%lx\n", t2_hae_2); - printk("T2_init: HAE3 was 0x%lx\n", t2_hae_3); - printk("T2_init: HAE4 was 0x%lx\n", t2_hae_4); -#endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* - * sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. - * - * see include/asm-alpha/t2.h for the SPARSE mem read/write - */ - t2_sm_base = (t2_hae_1 << 27) & 0xf8000000UL; - /* - Set the HAE cache, so that setup_arch() code - will use the SRM setting always. Our readb/writeb - code in .h expects never to have to change - the contents of the HAE. - */ - hae.cache = t2_hae_1; -#else /* SRM_SETUP */ - *(vulp)T2_HAE_1 = 0; mb(); - *(vulp)T2_HAE_2 = 0; mb(); - *(vulp)T2_HAE_3 = 0; mb(); + if (alpha_use_srm_setup) { + unsigned long t2_hae_1 = *(vulp)T2_HAE_1; + + alpha_mv.sm_base_r1 = (t2_hae_1 << 27) & 0xf8000000UL; + + /* + * Set the HAE cache, so that setup_arch() code + * will use the SRM setting always. Our readb/writeb + * code in .h expects never to have to change + * the contents of the HAE. + */ + alpha_mv.hae_cache = t2_hae_1; + + alpha_mv.mv_readb = t2_srm_readb; + alpha_mv.mv_readw = t2_srm_readw; + alpha_mv.mv_writeb = t2_srm_writeb; + alpha_mv.mv_writew = t2_srm_writew; + } else { + *(vulp)T2_HAE_1 = 0; mb(); + *(vulp)T2_HAE_2 = 0; mb(); + *(vulp)T2_HAE_3 = 0; mb(); #if 0 - *(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */ + *(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */ #endif -#endif /* SRM_SETUP */ } - - return mem_start; } #define SIC_SEIC (1UL << 33) /* System Event Clear */ -static struct sable_cpu_csr *sable_cpu_regs[4] = { - (struct sable_cpu_csr *)CPU0_BASE, - (struct sable_cpu_csr *)CPU1_BASE, - (struct sable_cpu_csr *)CPU2_BASE, - (struct sable_cpu_csr *)CPU3_BASE, -}; - -int t2_clear_errors(void) +static int +t2_clear_errors(void) { unsigned int cpu = smp_processor_id(); + static struct sable_cpu_csr *cpu_regs = NULL; + + switch (cpu) + { + case 0: cpu_regs = (struct sable_cpu_csr *)T2_CPU0_BASE; break; + case 1: cpu_regs = (struct sable_cpu_csr *)T2_CPU1_BASE; break; + case 2: cpu_regs = (struct sable_cpu_csr *)T2_CPU2_BASE; break; + case 3: cpu_regs = (struct sable_cpu_csr *)T2_CPU3_BASE; break; + } DBGMC(("???????? t2_clear_errors\n")); - sable_cpu_regs[cpu]->sic &= ~SIC_SEIC; + cpu_regs->sic &= ~SIC_SEIC; /* - * clear cpu errors + * clear CPU errors */ - sable_cpu_regs[cpu]->bcce |= sable_cpu_regs[cpu]->bcce; - sable_cpu_regs[cpu]->cbe |= sable_cpu_regs[cpu]->cbe; - sable_cpu_regs[cpu]->bcue |= sable_cpu_regs[cpu]->bcue; - sable_cpu_regs[cpu]->dter |= sable_cpu_regs[cpu]->dter; + cpu_regs->bcce |= cpu_regs->bcce; + cpu_regs->cbe |= cpu_regs->cbe; + cpu_regs->bcue |= cpu_regs->bcue; + cpu_regs->dter |= cpu_regs->dter; *(vulp)T2_CERR1 |= *(vulp)T2_CERR1; *(vulp)T2_PERR1 |= *(vulp)T2_PERR1; @@ -535,8 +516,9 @@ int t2_clear_errors(void) return 0; } -void t2_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) +void +t2_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) { struct el_t2_logout_header *mchk_header; struct el_t2_procdata_mcheck *mchk_procdata; @@ -556,9 +538,9 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr, mchk_header->elfl_sysoffset, mchk_header->elfl_procoffset)); mchk_sysdata = (struct el_t2_sysdata_mcheck *) - (la_ptr + mchk_header->elfl_sysoffset); + (la_ptr + mchk_header->elfl_sysoffset); mchk_procdata = (struct el_t2_procdata_mcheck *) - (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32); + (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32); DBGMC((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset, @@ -607,7 +589,7 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr, case 0x96: reason = "i-cache read retryable error"; break; case 0x98: reason = "processor detected hard error"; break; - /* System specific (these are for Alcor, at least): */ + /* System specific (these are for Alcor, at least): */ case 0x203: reason = "system detected uncorrectable ECC error"; break; case 0x205: reason = "parity error detected by T2"; break; case 0x207: reason = "non-existent memory error"; break; @@ -636,7 +618,7 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr, printk(KERN_CRIT " T2 machine check: %s%s\n", reason, mchk_header->elfl_retry ? " (retryable)" : ""); - /* dump the the logout area to give all info: */ + /* Dump the logout area to give all info. */ ptr = (unsigned long *)la_ptr; for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) { diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c new file mode 100644 index 000000000..382a97647 --- /dev/null +++ b/arch/alpha/kernel/core_tsunami.c @@ -0,0 +1,446 @@ +/* + * linux/arch/alpha/kernel/core_tsunami.c + * + * Code common to all TSUNAMI core logic chips. + * + * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com). + * + */ +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_tsunami.h> +#undef __EXTERN_INLINE + +#include "proto.h" + +/* + * NOTE: Herein lie back-to-back mb instructions. They are magic. + * One plausible explanation is that the I/O controller does not properly + * handle the system transaction. Another involves timing. Ho hum. + */ + +/* + * BIOS32-style PCI interface: + */ + +#ifdef DEBUG +# define DBG(args) printk args +#else +# define DBG(args) +#endif + +#define DEBUG_MCHECK +#ifdef DEBUG_MCHECK +# define DBG_MCK(args) printk args +#define DEBUG_MCHECK_DUMP +#else +# define DBG_MCK(args) +#endif + +static volatile unsigned int TSUNAMI_mcheck_expected[NR_CPUS]; +static volatile unsigned int TSUNAMI_mcheck_taken[NR_CPUS]; +static unsigned int TSUNAMI_jd[NR_CPUS]; + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address + * accordingly. It is therefore not safe to have concurrent + * invocations to configuration space access routines, but there + * really shouldn't be any need for this. + * + * Note that all config space accesses use Type 1 address format. + * + * Note also that type 1 is determined by non-zero bus number. + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + + DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + if (bus == 0) { + *type1 = 0; + } else { + /* Type 1 configuration cycle. */ + *type1 = 1; + } + addr = (bus << 16) | (device_fn << 8) | (where); + *pci_addr = addr; + DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +int +tsunami_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xff; + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)(addr+TSUNAMI_PCI0_CONF)); + return PCIBIOS_SUCCESSFUL; +} + +int +tsunami_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xffff; + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)(addr+TSUNAMI_PCI0_CONF)); + return PCIBIOS_SUCCESSFUL; +} + +int +tsunami_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + *value = 0xffffffff; + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)(addr+TSUNAMI_PCI0_CONF); + return PCIBIOS_SUCCESSFUL; +} + +int +tsunami_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)(addr+TSUNAMI_PCI0_CONF)); + return PCIBIOS_SUCCESSFUL; +} + +int +tsunami_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)(addr+TSUNAMI_PCI0_CONF)); + return PCIBIOS_SUCCESSFUL; +} + +int +tsunami_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)(addr+TSUNAMI_PCI0_CONF) = value; + return PCIBIOS_SUCCESSFUL; +} + +void __init +tsunami_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + unsigned long tsunami_err; + unsigned int i; + +#if 0 + printk("tsunami_init: CChip registers:\n"); + printk("CSR_CSC 0x%lx\n", *(vulp)TSUNAMI_CSR_CSC); + printk("CSR_MTR 0x%lx\n", *(vulp)TSUNAMI_CSR_MTR); + printk("CSR_MISC 0x%lx\n", *(vulp)TSUNAMI_CSR_MISC); + printk("CSR_DIM0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM0); + printk("CSR_DIM1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM1); + printk("CSR_DIR0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR0); + printk("CSR_DIR1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR1); + printk("CSR_DRIR 0x%lx\n", *(vulp)TSUNAMI_CSR_DRIR); + + printk("tsunami_init: DChip registers:\n"); + printk("CSR_DSC 0x%lx\n", *(vulp)TSUNAMI_CSR_DSC); + printk("CSR_STR 0x%lx\n", *(vulp)TSUNAMI_CSR_STR); + printk("CSR_DREV 0x%lx\n", *(vulp)TSUNAMI_CSR_DREV); + + printk("tsunami_init: PChip registers:\n"); + printk("PCHIP0_WSBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA0); + printk("PCHIP0_WSBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA1); + printk("PCHIP0_WSBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA2); + printk("PCHIP0_WSBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA3); + printk("PCHIP0_WSM0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM0); + printk("PCHIP0_WSM1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM1); + printk("PCHIP0_WSM2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM2); + printk("PCHIP0_WSM3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM3); + printk("PCHIP0_TBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA0); + printk("PCHIP0_TBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA1); + printk("PCHIP0_TBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA2); + printk("PCHIP0_TBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA3); + printk("PCHIP0_PCTL 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PCTL); + printk("PCHIP0_PLAT 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PLAT); + printk("PCHIP0_PERROR 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERROR); + printk("PCHIP0_PERRMASK 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERRMASK); +#endif + + for (i = 0; i < NR_CPUS; i++) { + TSUNAMI_mcheck_expected[i] = 0; + TSUNAMI_mcheck_taken[i] = 0; + } + +#ifdef NOT_YET + /* + * Set up error reporting. Make sure CPU_PE is OFF in the mask. + */ + tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK; + tsunami_err &= ~20; + *(vulp)TSUNAMI_PCHIP0_PERRMASK = tsunami_err; + mb(); + tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK; + + tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ; + tsunami_err |= 0x40; /* master/target abort */ + *(vulp)TSUNAMI_PCHIP0_PERROR = tsunami_err ; + mb() ; + tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ; +#endif /* NOT_YET */ + + switch (alpha_use_srm_setup) + { + default: +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP) + /* Check window 0 for enabled and mapped to 0. */ + if (((*(vulp)TSUNAMI_PCHIP0_WSBA0 & 3) == 1) + && (*(vulp)TSUNAMI_PCHIP0_TBA0 == 0) + && ((*(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U) > 0x0ff00000U)) { + TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA0 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("tsunami_init: using Window 0 settings\n"); + printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)TSUNAMI_PCHIP0_WSBA0, + *(vulp)TSUNAMI_PCHIP0_WSM0, + *(vulp)TSUNAMI_PCHIP0_TBA0); +#endif + break; + } + + /* Check window 1 for enabled and mapped to 0. */ + if (((*(vulp)TSUNAMI_PCHIP0_WSBA1 & 3) == 1) + && (*(vulp)TSUNAMI_PCHIP0_TBA1 == 0) + && ((*(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U) > 0x0ff00000U)) { + TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA1 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("tsunami_init: using Window 1 settings\n"); + printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)TSUNAMI_PCHIP0_WSBA1, + *(vulp)TSUNAMI_PCHIP0_WSM1, + *(vulp)TSUNAMI_PCHIP0_TBA1); +#endif + break; + } + + /* Check window 2 for enabled and mapped to 0. */ + if (((*(vulp)TSUNAMI_PCHIP0_WSBA2 & 3) == 1) + && (*(vulp)TSUNAMI_PCHIP0_TBA2 == 0) + && ((*(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U) > 0x0ff00000U)) { + TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA2 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("tsunami_init: using Window 2 settings\n"); + printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)TSUNAMI_PCHIP0_WSBA2, + *(vulp)TSUNAMI_PCHIP0_WSM2, + *(vulp)TSUNAMI_PCHIP0_TBA2); +#endif + break; + } + + /* Check window 3 for enabled and mapped to 0. */ + if (((*(vulp)TSUNAMI_PCHIP0_WSBA3 & 3) == 1) + && (*(vulp)TSUNAMI_PCHIP0_TBA3 == 0) + && ((*(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U) > 0x0ff00000U)) { + TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA3 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U; + TSUNAMI_DMA_WIN_SIZE += 0x00100000U; +#if 1 + printk("tsunami_init: using Window 3 settings\n"); + printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n", + *(vulp)TSUNAMI_PCHIP0_WSBA3, + *(vulp)TSUNAMI_PCHIP0_WSM3, + *(vulp)TSUNAMI_PCHIP0_TBA3); +#endif + break; + } + + /* Otherwise, we must use our defaults. */ + TSUNAMI_DMA_WIN_BASE = TSUNAMI_DMA_WIN_BASE_DEFAULT; + TSUNAMI_DMA_WIN_SIZE = TSUNAMI_DMA_WIN_SIZE_DEFAULT; +#endif + case 0: + /* + * Set up the PCI->physical memory translation windows. + * For now, windows 1,2 and 3 are disabled. In the future, + * we may want to use them to do scatter/gather DMA. + * + * Window 0 goes at 1 GB and is 1 GB large. + */ + + *(vulp)TSUNAMI_PCHIP0_WSBA0 + = 1L | (TSUNAMI_DMA_WIN_BASE_DEFAULT & 0xfff00000U); + *(vulp)TSUNAMI_PCHIP0_WSM0 + = (TSUNAMI_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000UL; + *(vulp)TSUNAMI_PCHIP0_TBA0 = 0UL; + + *(vulp)TSUNAMI_PCHIP0_WSBA1 = 0UL; + *(vulp)TSUNAMI_PCHIP0_WSBA2 = 0UL; + *(vulp)TSUNAMI_PCHIP0_WSBA3 = 0UL; + mb(); + } +} + +static int +tsunami_pci_clr_err(void) +{ + unsigned int cpu = smp_processor_id(); + + TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR); + DBG(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n",TSUNAMI_jd[cpu])); + *((vulp)TSUNAMI_PCHIP0_PERROR) = 0x040; mb(); + TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR); + return 0; +} + +void +tsunami_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ +#if 1 + printk("TSUNAMI machine check ignored\n") ; +#else + struct el_common *mchk_header; + struct el_TSUNAMI_sysdata_mcheck *mchk_sysdata; + unsigned int cpu = smp_processor_id(); + + mchk_header = (struct el_common *)la_ptr; + + mchk_sysdata = (struct el_TSUNAMI_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); + +#if 0 + DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + DBG_MCK(("tsunami_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + TSUNAMI_mcheck_expected[cpu], mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear)); +#endif +#ifdef DEBUG_MCHECK_DUMP + { + unsigned long *ptr; + int i; + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + } + } +#endif /* DEBUG_MCHECK_DUMP */ + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + mb(); + mb(); /* magic */ + if (TSUNAMI_mcheck_expected[cpu]) { + DBG(("TSUNAMI machine check expected\n")); + TSUNAMI_mcheck_expected[cpu] = 0; + TSUNAMI_mcheck_taken[cpu] = 1; + mb(); + mb(); /* magic */ + draina(); + tsunami_pci_clr_err(); + wrmces(0x7); + mb(); + } +#if 1 + else { + printk("TSUNAMI machine check NOT expected\n") ; + DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr)); + DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset)); + TSUNAMI_mcheck_expected[cpu] = 0; + TSUNAMI_mcheck_taken[cpu] = 1; + mb(); + mb(); /* magic */ + draina(); + tsunami_pci_clr_err(); + wrmces(0x7); + mb(); + } +#endif +#endif +} diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 0bbc71926..79b0d818c 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -15,7 +15,7 @@ #define osf_vfork sys_fork /* - * These offsets must match with "struct hae" in io.h: + * These offsets must match with alpha_mv in <asm/machvec.h>. */ #define HAE_CACHE 0 #define HAE_REG 8 @@ -30,10 +30,12 @@ /* * task structure offsets */ -#define TASK_STATE 0 -#define TASK_FLAGS 8 -#define TASK_SIGPENDING 16 -#define TASK_SIZE 24 +#define TASK_STATE 0 +#define TASK_FLAGS 8 +#define TASK_SIGPENDING 16 +#define TASK_ADDR_LIMIT 24 +#define TASK_EXEC_DOMAIN 32 +#define TASK_NEED_RESCHED 40 /* * task flags (must match include/linux/sched.h): @@ -107,7 +109,7 @@ stq $3,24($30); \ stq $4,32($30); \ stq $28,144($30); \ - lda $2,hae; \ + lda $2,alpha_mv; \ stq $5,40($30); \ stq $6,48($30); \ stq $7,56($30); \ @@ -128,7 +130,7 @@ stq $18,176($30) #define RESTORE_ALL \ - lda $19,hae; \ + lda $19,alpha_mv; \ ldq $0,0($30); \ ldq $1,8($30); \ ldq $2,16($30); \ @@ -264,7 +266,7 @@ kernel_clone: stq $18,40($30) bis $31,2,$0 /* Register v0: syscall nr for fork() */ SAVE_ALL - jsr $26,sys_clone + bsr $26,sys_clone stq $0,0($30) br $31,ret_from_sys_call .end kernel_clone @@ -559,6 +561,7 @@ sys_clone: .globl alpha_switch_to .ent alpha_switch_to alpha_switch_to: + .prologue 0 bsr $1,do_switch_stack call_pal PAL_swpctx lda $16,-2($31) @@ -615,8 +618,7 @@ ret_from_handle_bh: and $0,8,$0 beq $0,restore_all ret_from_reschedule: - lda $0,need_resched - ldl $2,0($0) + ldq $2,TASK_NEED_RESCHED($8) lda $4,init_task_union bne $2,reschedule xor $4,$8,$4 @@ -923,7 +925,7 @@ sys_call_table: .quad alpha_ni_syscall .quad alpha_ni_syscall /* 110 */ .quad sys_sigsuspend - .quad sys_ni_syscall + .quad osf_sigstack .quad sys_recvmsg .quad sys_sendmsg .quad alpha_ni_syscall /* 115 */ @@ -1046,7 +1048,7 @@ sys_call_table: .quad alpha_ni_syscall .quad sys_getpgid .quad sys_getsid - .quad alpha_ni_syscall /* 235 */ + .quad sys_sigaltstack /* 235 */ .quad alpha_ni_syscall .quad alpha_ni_syscall .quad alpha_ni_syscall @@ -1133,7 +1135,7 @@ sys_call_table: .quad sys_sysinfo .quad sys_sysctl .quad sys_idle /* 320 */ - .quad sys_umount + .quad sys_oldumount .quad sys_swapon .quad sys_times .quad sys_personality @@ -1179,6 +1181,7 @@ sys_call_table: .quad sys_getrusage .quad sys_wait4 /* 365 */ .quad sys_adjtimex - .quad sys_ni_syscall - .quad sys_ni_syscall - .quad sys_ni_syscall /* 369 */ + .quad sys_getcwd + .quad sys_capget + .quad sys_capset + .quad sys_ni_syscall /* 370 */ diff --git a/arch/alpha/kernel/es1888.c b/arch/alpha/kernel/es1888.c new file mode 100644 index 000000000..10115ac8d --- /dev/null +++ b/arch/alpha/kernel/es1888.c @@ -0,0 +1,47 @@ +/* + * linux/arch/alpha/kernel/es1888.c + * + * Init the built-in ES1888 sound chip (SB16 compatible) + */ + +#include <linux/init.h> +#include <asm/io.h> +#include "proto.h" + +void __init +es1888_init(void) +{ + /* Sequence of IO reads to init the audio controller */ + inb(0x0229); + inb(0x0229); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x0229); + inb(0x022b); + inb(0x0229); + inb(0x0220); /* This sets the base address to 0x220 */ + + /* Sequence to set DMA channels */ + outb(0x01, 0x0226); /* reset */ + inb(0x0226); /* pause */ + outb(0x00, 0x0226); /* release reset */ + while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/ + continue; + inb(0x022a); /* pause */ + outb(0xc6, 0x022c); /* enable extended mode */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0xb1, 0x022c); /* setup for write to Interrupt CR */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0x14, 0x022c); /* set IRQ 5 */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0xb2, 0x022c); /* setup for write to DMA CR */ + while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ + continue; + outb(0x18, 0x022c); /* set DMA channel 1 */ +} diff --git a/arch/alpha/kernel/fpreg.c b/arch/alpha/kernel/fpreg.c index 502144058..6da94c0cb 100644 --- a/arch/alpha/kernel/fpreg.c +++ b/arch/alpha/kernel/fpreg.c @@ -4,62 +4,58 @@ * (C) Copyright 1998 Linus Torvalds */ +#ifdef __alpha_cix__ +#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); +#else +#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); +#endif + unsigned long alpha_read_fp_reg (unsigned long reg) { - unsigned long r; + unsigned long val; switch (reg) { - case 0: asm ("stt $f0,%0" : "m="(r)); break; - case 1: asm ("stt $f1,%0" : "m="(r)); break; - case 2: asm ("stt $f2,%0" : "m="(r)); break; - case 3: asm ("stt $f3,%0" : "m="(r)); break; - case 4: asm ("stt $f4,%0" : "m="(r)); break; - case 5: asm ("stt $f5,%0" : "m="(r)); break; - case 6: asm ("stt $f6,%0" : "m="(r)); break; - case 7: asm ("stt $f7,%0" : "m="(r)); break; - case 8: asm ("stt $f8,%0" : "m="(r)); break; - case 9: asm ("stt $f9,%0" : "m="(r)); break; - case 10: asm ("stt $f10,%0" : "m="(r)); break; - case 11: asm ("stt $f11,%0" : "m="(r)); break; - case 12: asm ("stt $f12,%0" : "m="(r)); break; - case 13: asm ("stt $f13,%0" : "m="(r)); break; - case 14: asm ("stt $f14,%0" : "m="(r)); break; - case 15: asm ("stt $f15,%0" : "m="(r)); break; - case 16: asm ("stt $f16,%0" : "m="(r)); break; - case 17: asm ("stt $f17,%0" : "m="(r)); break; - case 18: asm ("stt $f18,%0" : "m="(r)); break; - case 19: asm ("stt $f19,%0" : "m="(r)); break; - case 20: asm ("stt $f20,%0" : "m="(r)); break; - case 21: asm ("stt $f21,%0" : "m="(r)); break; - case 22: asm ("stt $f22,%0" : "m="(r)); break; - case 23: asm ("stt $f23,%0" : "m="(r)); break; - case 24: asm ("stt $f24,%0" : "m="(r)); break; - case 25: asm ("stt $f25,%0" : "m="(r)); break; - case 26: asm ("stt $f26,%0" : "m="(r)); break; - case 27: asm ("stt $f27,%0" : "m="(r)); break; - case 28: asm ("stt $f28,%0" : "m="(r)); break; - case 29: asm ("stt $f29,%0" : "m="(r)); break; - case 30: asm ("stt $f30,%0" : "m="(r)); break; - case 31: asm ("stt $f31,%0" : "m="(r)); break; - default: - break; + case 0: STT( 0, val); break; + case 1: STT( 1, val); break; + case 2: STT( 2, val); break; + case 3: STT( 3, val); break; + case 4: STT( 4, val); break; + case 5: STT( 5, val); break; + case 6: STT( 6, val); break; + case 7: STT( 7, val); break; + case 8: STT( 8, val); break; + case 9: STT( 9, val); break; + case 10: STT(10, val); break; + case 11: STT(11, val); break; + case 12: STT(12, val); break; + case 13: STT(13, val); break; + case 14: STT(14, val); break; + case 15: STT(15, val); break; + case 16: STT(16, val); break; + case 17: STT(17, val); break; + case 18: STT(18, val); break; + case 19: STT(19, val); break; + case 20: STT(20, val); break; + case 21: STT(21, val); break; + case 22: STT(22, val); break; + case 23: STT(23, val); break; + case 24: STT(24, val); break; + case 25: STT(25, val); break; + case 26: STT(26, val); break; + case 27: STT(27, val); break; + case 28: STT(28, val); break; + case 29: STT(29, val); break; + case 30: STT(30, val); break; + case 31: STT(31, val); break; } - return r; + return val; } -#if 1 -/* - * This is IMHO the better way of implementing LDT(). But it - * has the disadvantage that gcc 2.7.0 refuses to compile it - * (invalid operand constraints), so instead, we use the uglier - * macro below. - */ -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",%0" : : "m"(val)); +#ifdef __alpha_cix__ +#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); #else -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",0(%0)" : : "r"(&val)); +#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); #endif void @@ -98,7 +94,5 @@ alpha_write_fp_reg (unsigned long reg, unsigned long val) case 29: LDT(29, val); break; case 30: LDT(30, val); break; case 31: LDT(31, val); break; - default: - break; } } diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index a6bcd616d..92e11a82e 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -7,7 +7,6 @@ * the kernel global pointer and jump to the kernel entry-point. */ -#define __ASSEMBLY__ #include <asm/system.h> #define halt call_pal PAL_halt @@ -21,6 +20,7 @@ swapper_pg_dir=SWAPPER_PGD .ent __start _stext: __start: + .prologue 0 br $27,1f 1: ldgp $29,0($27) /* We need to get current loaded up with our first task... */ @@ -39,6 +39,7 @@ __start: /* on entry here from SRM console, the HWPCB of this processor */ /* has been loaded, and $27 contains the task pointer */ __start_cpu: + .prologue 0 /* first order of business, load the GP */ br $26,1f 1: ldgp $29,0($26) @@ -57,6 +58,7 @@ __start_cpu: .globl wrent .ent wrent wrent: + .prologue 0 call_pal PAL_wrent ret ($26) .end wrent @@ -65,6 +67,7 @@ wrent: .globl wrkgp .ent wrkgp wrkgp: + .prologue 0 call_pal PAL_wrkgp ret ($26) .end wrkgp @@ -73,6 +76,7 @@ wrkgp: .globl wrusp .ent wrusp wrusp: + .prologue 0 call_pal PAL_wrusp ret ($26) .end wrusp @@ -81,6 +85,7 @@ wrusp: .globl rdusp .ent rdusp rdusp: + .prologue 0 call_pal PAL_rdusp ret ($26) .end rdusp @@ -89,6 +94,7 @@ rdusp: .globl rdmces .ent rdmces rdmces: + .prologue 0 call_pal PAL_rdmces ret ($26) .end rdmces @@ -97,6 +103,7 @@ rdmces: .globl wrmces .ent wrmces wrmces: + .prologue 0 call_pal PAL_wrmces ret ($26) .end wrmces @@ -105,6 +112,7 @@ wrmces: .globl whami .ent whami whami: + .prologue 0 call_pal PAL_whami ret ($26) .end whami @@ -127,6 +135,7 @@ wripir: .globl cserve_ena .ent cserve_ena cserve_ena: + .prologue 0 bis $16,$16,$17 lda $16,52($31) call_pal PAL_cserve @@ -137,6 +146,7 @@ cserve_ena: .globl cserve_dis .ent cserve_dis cserve_dis: + .prologue 0 bis $16,$16,$17 lda $16,53($31) call_pal PAL_cserve diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index bcac2da2b..0fee440e1 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -25,14 +25,17 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/bitops.h> -#include <asm/dma.h> +#include <asm/machvec.h> + +#include "proto.h" +#include "irq.h" #define vulp volatile unsigned long * #define vuip volatile unsigned int * -extern void timer_interrupt(struct pt_regs * regs); -extern void cserve_update_hw(unsigned long, unsigned long); -extern void handle_ipi(struct pt_regs *); +unsigned int local_irq_count[NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; + #define RTC_IRQ 8 #ifdef CONFIG_RTC @@ -45,497 +48,169 @@ extern void handle_ipi(struct pt_regs *); # error Unable to handle more than 64 irq levels. #endif -/* PROBE_MASK is the bitset of irqs that we consider for autoprobing: */ -#if defined(CONFIG_ALPHA_P2K) - /* always mask out unused timer irq 0 and RTC irq 8 */ -# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL) -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) - /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */ -# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL) -#elif defined(CONFIG_ALPHA_RUFFIAN) - /* must leave timer irq 0 in the mask */ -# define PROBE_MASK ((1UL << NR_IRQS) - 1) -#elif NR_IRQS == 64 - /* always mask out unused timer irq 0: */ -# define PROBE_MASK (~1UL) +#ifdef CONFIG_ALPHA_GENERIC +#define ACTUAL_NR_IRQS alpha_mv.nr_irqs #else - /* always mask out unused timer irq 0: */ -# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL) +#define ACTUAL_NR_IRQS NR_IRQS #endif /* Reserved interrupts. These must NEVER be requested by any driver! - */ -#define IS_RESERVED_IRQ(irq) ((irq)==2) /* IRQ 2 used by hw cascade */ + IRQ 2 used by hw cascade */ +#define IS_RESERVED_IRQ(irq) ((irq)==2) -/* - * Shadow-copy of masked interrupts. - * The bits are used as follows: - * 0.. 7 first (E)ISA PIC (irq level 0..7) - * 8..15 second (E)ISA PIC (irq level 8..15) - * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT) - * or PYXIS (e.g. Miata, PC164-LX): - * 16..47 PCI interrupts 0..31 (int at xxx_INT_MASK) - * Mikasa: - * 16..31 PCI interrupts 0..15 (short at I/O port 536) - * Other systems (not Mikasa) with 16 PCI interrupt lines: - * 16..23 PCI interrupts 0.. 7 (char at I/O port 26) - * 24..31 PCI interrupts 8..15 (char at I/O port 27) - * Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164): - * 16..32 PCI interrupts 0..31 (int at I/O port 804) - * For SABLE, which is really baroque, we manage 40 IRQ's, but the - * hardware really only supports 24, not via normal ISA PIC, - * but cascaded custom 8259's, etc. - * 0-7 (char at 536) - * 8-15 (char at 53a) - * 16-23 (char at 53c) - */ -static unsigned long irq_mask = ~0UL; -#ifdef CONFIG_ALPHA_SABLE /* - * Note that the vector reported by the SRM PALcode corresponds to the - * interrupt mask bits, but we have to manage via more normal IRQs. - * - * We have to be able to go back and forth between MASK bits and IRQ: - * these tables help us do so. + * Shadow-copy of masked interrupts. */ -static char sable_irq_to_mask[NR_IRQS] = { - -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */ - -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */ - 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */ -}; -#define IRQ_TO_MASK(irq) (sable_irq_to_mask[(irq)]) -static char sable_mask_to_irq[NR_IRQS] = { - 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */ - 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */ - 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */ -}; -#else /* CONFIG_ALPHA_SABLE */ -#define IRQ_TO_MASK(irq) (irq) -#endif /* CONFIG_ALPHA_SABLE */ +unsigned long alpha_irq_mask = ~0UL; /* - * Update the hardware with the irq mask passed in MASK. The function - * exploits the fact that it is known that only bit IRQ has changed. + * The ack_irq routine used by 80% of the systems. */ -static inline void -sable_update_hw(unsigned long irq, unsigned long mask) +void +generic_ack_irq(unsigned long irq) { - /* The "irq" argument is really the mask bit number */ - switch (irq) { - case 16 ... 23: - outb(mask >> 16, 0x53d); - break; - case 8 ... 15: - outb(mask >> 8, 0x53b); - break; - case 0 ... 7: - outb(mask, 0x537); - break; + if (irq < 16) { + /* Ack the interrupt making it the lowest priority */ + /* First the slave .. */ + if (irq > 7) { + outb(0xE0 | (irq - 8), 0xa0); + irq = 2; + } + /* .. then the master */ + outb(0xE0 | irq, 0x20); } } -static inline void -noritake_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 32 ... 47: - outw(~(mask >> 32), 0x54c); - break; - case 16 ... 31: - outw(~(mask >> 16), 0x54a); - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} +/* + * Dispatch device interrupts. + */ -#ifdef CONFIG_ALPHA_MIATA -static inline void -miata_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 47: - /* Make CERTAIN none of the bogus ints get enabled... */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & ~0x4000000000000e3bUL; - mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} -#endif +/* Handle ISA interrupt via the PICs. */ -#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) -static inline void -alcor_and_xlt_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 47: - /* On Alcor, at least, lines 20..30 are not connected and can - generate spurrious interrupts if we turn them on while IRQ - probing. So explicitly mask them out. */ - mask |= 0x7ff000000000UL; - - /* Note inverted sense of mask bits: */ - *(vuip)GRU_INT_MASK = ~(mask >> 16); - mb(); - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} +#if defined(CONFIG_ALPHA_GENERIC) +# define IACK_SC alpha_mv.iack_sc +#elif defined(CONFIG_ALPHA_APECS) +# define IACK_SC APECS_IACK_SC +#elif defined(CONFIG_ALPHA_LCA) +# define IACK_SC LCA_IACK_SC +#elif defined(CONFIG_ALPHA_CIA) +# define IACK_SC CIA_IACK_SC +#elif defined(CONFIG_ALPHA_PYXIS) +# define IACK_SC PYXIS_IACK_SC +#elif defined(CONFIG_ALPHA_TSUNAMI) +# define IACK_SC TSUNAMI_PCI0_IACK_SC +#else + /* This is bogus but necessary to get it to compile on all platforms. */ +# define IACK_SC 1L #endif -static inline void -mikasa_update_hw(unsigned long irq, unsigned long mask) +void +isa_device_interrupt(unsigned long vector, struct pt_regs * regs) { - switch (irq) { - case 16 ... 31: - outw(~(mask >> 16), 0x536); /* note invert */ - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} - -#if defined(CONFIG_ALPHA_RUFFIAN) -static inline void -ruffian_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 47: - /* Note inverted sense of mask bits: */ - /* Make CERTAIN none of the bogus ints get enabled... */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; +#if 1 + /* + * Generate a PCI interrupt acknowledge cycle. The PIC will + * respond with the interrupt vector of the highest priority + * interrupt that is pending. The PALcode sets up the + * interrupts vectors such that irq level L generates vector L. + */ + int j = *(vuip) IACK_SC; + j &= 0xff; + if (j == 7) { + if (!(inb(0x20) & 0x80)) { + /* It's only a passive release... */ + return; + } } -} -#endif /* RUFFIAN */ - -#if defined(CONFIG_ALPHA_SX164) -static inline void -sx164_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 39: -#if defined(CONFIG_ALPHA_SRM) - cserve_update_hw(irq, mask); + handle_irq(j, j, regs); #else - /* make CERTAIN none of the bogus ints get enabled */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & ~0x000000000000003bUL; mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; -#endif /* SRM */ - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } + unsigned long pic; -} -#endif /* SX164 */ + /* + * It seems to me that the probability of two or more *device* + * interrupts occurring at almost exactly the same time is + * pretty low. So why pay the price of checking for + * additional interrupts here if the common case can be + * handled so much easier? + */ + /* + * The first read of gives you *all* interrupting lines. + * Therefore, read the mask register and and out those lines + * not enabled. Note that some documentation has 21 and a1 + * write only. This is not true. + */ + pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ + pic &= ~alpha_irq_mask; /* apply mask */ + pic &= 0xFFFB; /* mask out cascade & hibits */ -#if defined(CONFIG_ALPHA_DP264) -static inline void -dp264_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 63: - /* make CERTAIN none of the bogus ints get enabled */ - /* HACK ALERT! only CPU#0 is used currently */ - *(vulp)TSUNAMI_CSR_DIM0 = - ~(mask) & ~0x0000000000000000UL; mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)TSUNAMI_CSR_DIM0; - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; + while (pic) { + int j = ffz(~pic); + pic &= pic - 1; + handle_irq(j, j, regs); } +#endif } -#endif /* DP264 */ -#if defined(CONFIG_ALPHA_RAWHIDE) -static inline void -rawhide_update_hw(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 16 ... 39: /* PCI bus 0 with EISA bridge */ - *(vuip)MCPCIA_INT_MASK0(0) = - (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(0); - break; - case 40 ... 63: /* PCI bus 1 with builtin NCR810 SCSI */ - *(vuip)MCPCIA_INT_MASK0(1) = - (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(1); - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} -#endif /* RAWHIDE */ +/* Handle interrupts from the SRM, assuming no additional weirdness. */ -/* - * HW update code for the following platforms: - * - * CABRIOLET (AlphaPC64) - * EB66P - * EB164 - * PC164 - * LX164 - */ -static inline void -update_hw_35(unsigned long irq, unsigned long mask) +void +srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - switch (irq) { - case 16 ... 34: -#if defined(CONFIG_ALPHA_SRM) - cserve_update_hw(irq, mask); -#else /* SRM */ - outl(irq_mask >> 16, 0x804); -#endif /* SRM */ - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; - } -} + int irq, ack; + unsigned long flags; -static inline void -update_hw_32(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 24 ... 31: - outb(mask >> 24, 0x27); - break; - case 16 ... 23: - outb(mask >> 16, 0x26); - break; - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; -} -} + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; -static inline void -update_hw_16(unsigned long irq, unsigned long mask) -{ - switch (irq) { - case 8 ... 15: /* ISA PIC2 */ - outb(mask >> 8, 0xA1); - break; - case 0 ... 7: /* ISA PIC1 */ - outb(mask, 0x21); - break; -} + handle_irq(irq, ack, regs); + __restore_flags(flags); } + /* - * We manipulate the hardware ourselves. + * Initial irq handlers. */ -static void update_hw(unsigned long irq, unsigned long mask) -{ -#if defined(CONFIG_ALPHA_SABLE) - sable_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_MIATA) - miata_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_NORITAKE) - noritake_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) - alcor_and_xlt_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_MIKASA) - mikasa_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_SX164) - sx164_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_RUFFIAN) - ruffian_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_DP264) - dp264_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_RAWHIDE) - rawhide_update_hw(irq, mask); -#elif defined(CONFIG_ALPHA_CABRIOLET) || \ - defined(CONFIG_ALPHA_EB66P) || \ - defined(CONFIG_ALPHA_EB164) || \ - defined(CONFIG_ALPHA_PC164) || \ - defined(CONFIG_ALPHA_LX164) - update_hw_35(irq, mask); -#elif defined(CONFIG_ALPHA_EB66) || \ - defined(CONFIG_ALPHA_EB64P) - update_hw_32(irq, mask); -#elif NR_IRQS == 16 - update_hw_16(irq, mask); -#else -#error "How do I update the IRQ hardware?" -#endif -} +static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL}; +static struct irqaction *irq_action[NR_IRQS]; -static inline void mask_irq(unsigned long irq) + +static inline void +mask_irq(unsigned long irq) { - irq_mask |= (1UL << irq); - update_hw(irq, irq_mask); + alpha_mv.update_irq_hw(irq, alpha_irq_mask |= 1UL << irq, 0); } -static inline void unmask_irq(unsigned long irq) +static inline void +unmask_irq(unsigned long irq) { - irq_mask &= ~(1UL << irq); - update_hw(irq, irq_mask); + alpha_mv.update_irq_hw(irq, alpha_irq_mask &= ~(1UL << irq), 1); } -void disable_irq(unsigned int irq_nr) +void +disable_irq(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); - mask_irq(IRQ_TO_MASK(irq_nr)); + mask_irq(irq_nr); restore_flags(flags); } -void enable_irq(unsigned int irq_nr) +void +enable_irq(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); - unmask_irq(IRQ_TO_MASK(irq_nr)); + unmask_irq(irq_nr); restore_flags(flags); } -/* - * Initial irq handlers. - */ -static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL}; -static struct irqaction *irq_action[NR_IRQS]; - -int get_irq_list(char *buf) -{ - int i, len = 0; - struct irqaction * action; - int cpu = smp_processor_id(); - - for (i = 0; i < NR_IRQS; i++) { - action = irq_action[i]; - if (!action) - continue; - len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.irqs[cpu][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, "\n"); - } - return len; -} - -static inline void ack_irq(int irq) -{ -#ifdef CONFIG_ALPHA_SABLE - /* Note that the "irq" here is really the mask bit number */ - switch (irq) { - case 0 ... 7: - outb(0xE0 | (irq - 0), 0x536); - outb(0xE0 | 1, 0x534); /* slave 0 */ - break; - case 8 ... 15: - outb(0xE0 | (irq - 8), 0x53a); - outb(0xE0 | 3, 0x534); /* slave 1 */ - break; - case 16 ... 24: - outb(0xE0 | (irq - 16), 0x53c); - outb(0xE0 | 4, 0x534); /* slave 2 */ - break; - } -#elif defined(CONFIG_ALPHA_RUFFIAN) - if (irq < 16) { - /* Ack PYXIS ISA interrupt. */ - *(vulp)PYXIS_INT_REQ = 1L << 7; mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_REQ; - if (irq > 7) { - outb(0x20, 0xa0); - } - outb(0x20, 0x20); - } else { - /* Ack PYXIS PCI interrupt. */ - *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_REQ; - } -#else - if (irq < 16) { - /* Ack the interrupt making it the lowest priority */ - /* First the slave .. */ - if (irq > 7) { - outb(0xE0 | (irq - 8), 0xa0); - irq = 2; - } - /* .. then the master */ - outb(0xE0 | irq, 0x20); -#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) - /* on ALCOR/XLT, need to dismiss interrupt via GRU */ - *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); - *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); -#endif /* ALCOR || XLT */ - } -#endif -} - -int check_irq(unsigned int irq) +int +check_irq(unsigned int irq) { struct irqaction **p; @@ -545,22 +220,21 @@ int check_irq(unsigned int irq) return -EBUSY; } -int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) +int +request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) { int shared = 0; struct irqaction * action, **p; unsigned long flags; - if (irq >= NR_IRQS) + if (irq >= ACTUAL_NR_IRQS) return -EINVAL; if (IS_RESERVED_IRQ(irq)) return -EINVAL; if (!handler) return -EINVAL; + p = irq_action + irq; action = *p; if (action) { @@ -580,11 +254,11 @@ int request_irq(unsigned int irq, shared = 1; } - if (irq == TIMER_IRQ) - action = &timer_irq; - else - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_KERNEL); + action = &timer_irq; + if (irq != TIMER_IRQ) { + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + } if (!action) return -ENOMEM; @@ -602,18 +276,19 @@ int request_irq(unsigned int irq, *p = action; if (!shared) - unmask_irq(IRQ_TO_MASK(irq)); + unmask_irq(irq); restore_flags(flags); return 0; } -void free_irq(unsigned int irq, void *dev_id) +void +free_irq(unsigned int irq, void *dev_id) { struct irqaction * action, **p; unsigned long flags; - if (irq >= NR_IRQS) { + if (irq >= ACTUAL_NR_IRQS) { printk("Trying to free IRQ%d\n",irq); return; } @@ -629,7 +304,7 @@ void free_irq(unsigned int irq, void *dev_id) save_and_cli(flags); *p = action->next; if (!irq[irq_action]) - mask_irq(IRQ_TO_MASK(irq)); + mask_irq(irq); restore_flags(flags); kfree(action); return; @@ -637,14 +312,29 @@ void free_irq(unsigned int irq, void *dev_id) printk("Trying to free free IRQ%d\n",irq); } -static inline void handle_nmi(struct pt_regs * regs) +int get_irq_list(char *buf) { - printk("Whee.. NMI received. Probable hardware error\n"); - printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); -} + int i, len = 0; + struct irqaction * action; + int cpu = smp_processor_id(); -unsigned int local_irq_count[NR_CPUS]; -unsigned int local_bh_count[NR_CPUS]; + for (i = 0; i < NR_IRQS; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %10u %c %s", + i, kstat.irqs[cpu][i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s%s", + (action->flags & SA_INTERRUPT) ? "+":"", + action->name); + } + len += sprintf(buf+len, "\n"); + } + return len; +} #ifdef __SMP__ /* Who has global_irq_lock. */ @@ -666,10 +356,17 @@ static unsigned long previous_irqholder = NO_PROC_ID; #define INIT_STUCK 100000000 #undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } +#define STUCK \ + if (!--stuck) { \ + printk("wait_on_irq CPU#%d stuck at %08lx, " \ + "waiting for %08lx (local=%d, global=%d)\n", \ + cpu, where, previous_irqholder, local_count, \ + atomic_read(&global_irq_count)); \ + stuck = INIT_STUCK; \ + } -static inline void wait_on_irq(int cpu, unsigned long where) +static inline void +wait_on_irq(int cpu, unsigned long where) { int stuck = INIT_STUCK; int local_count = local_irq_count[cpu]; @@ -706,10 +403,15 @@ static inline void wait_on_irq(int cpu, unsigned long where) #define INIT_STUCK 10000000 #undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} +#define STUCK \ + if (!--stuck) { \ + printk("get_irqlock stuck at %08lx, waiting for %08lx\n", \ + where, previous_irqholder); \ + stuck = INIT_STUCK; \ + } -static inline void get_irqlock(int cpu, unsigned long where) +static inline void +get_irqlock(int cpu, unsigned long where) { int stuck = INIT_STUCK; @@ -745,7 +447,8 @@ static inline void get_irqlock(int cpu, unsigned long where) previous_irqholder = where; } -void __global_cli(void) +void +__global_cli(void) { int cpu = smp_processor_id(); unsigned long where; @@ -754,27 +457,30 @@ void __global_cli(void) __cli(); if (!local_irq_count[cpu]) - get_irqlock(smp_processor_id(), where); + get_irqlock(smp_processor_id(), where); } -void __global_sti(void) +void +__global_sti(void) { int cpu = smp_processor_id(); if (!local_irq_count[cpu]) - release_irqlock(smp_processor_id()); + release_irqlock(smp_processor_id()); __sti(); } #if 0 -unsigned long __global_save_flags(void) +unsigned long +__global_save_flags(void) { return global_irq_holder == (unsigned char) smp_processor_id(); } #endif -void __global_restore_flags(unsigned long flags) +void +__global_restore_flags(unsigned long flags) { if (flags & 1) { __global_cli(); @@ -793,12 +499,17 @@ void __global_restore_flags(unsigned long flags) #define INIT_STUCK 200000000 #undef STUCK -#define STUCK \ -if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} +#define STUCK \ + if (!--stuck) { \ + printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", \ + irq, cpu,global_irq_holder); \ + stuck = INIT_STUCK; \ + } #undef VERBOSE_IRQLOCK_DEBUGGING -void irq_enter(int cpu, int irq) +void +irq_enter(int cpu, int irq) { #ifdef VERBOSE_IRQLOCK_DEBUGGING extern void smp_show_backtrace_all_cpus(void); @@ -813,10 +524,10 @@ void irq_enter(int cpu, int irq) int globl_icount = atomic_read(&global_irq_count); int local_count = local_irq_count[cpu]; - /* It is very important that we load the state variables - * before we do the first call to printk() as printk() - * could end up changing them... - */ + /* It is very important that we load the state + variables before we do the first call to + printk() as printk() could end up changing + them... */ #if 0 printk("CPU[%d]: BAD! Local IRQ's enabled," @@ -827,7 +538,7 @@ void irq_enter(int cpu, int irq) cpu, previous_irqholder, globl_locked, globl_icount, local_count); #ifdef VERBOSE_IRQLOCK_DEBUGGING - printk("Performing backtrace on all cpus," + printk("Performing backtrace on all CPUs," " write this down!\n"); smp_show_backtrace_all_cpus(); #endif @@ -838,13 +549,15 @@ void irq_enter(int cpu, int irq) } } -void irq_exit(int cpu, int irq) +void +irq_exit(int cpu, int irq) { hardirq_exit(cpu); release_irqlock(cpu); } -static void show(char * str) +static void +show(char * str) { #if 0 int i; @@ -873,7 +586,8 @@ static void show(char * str) #define MAXCOUNT 100000000 -static inline void wait_on_bh(void) +static inline void +wait_on_bh(void) { int count = MAXCOUNT; do { @@ -893,7 +607,8 @@ static inline void wait_on_bh(void) * Don't wait if we're already running in an interrupt * context or are inside a bh handler. */ -void synchronize_bh(void) +void +synchronize_bh(void) { if (atomic_read(&global_bh_count)) { int cpu = smp_processor_id(); @@ -904,7 +619,8 @@ void synchronize_bh(void) } /* There has to be a better way. */ -void synchronize_irq(void) +void +synchronize_irq(void) { int cpu = smp_processor_id(); int local_count = local_irq_count[cpu]; @@ -918,26 +634,35 @@ void synchronize_irq(void) } } -#else +#else /* !__SMP__ */ + #define irq_enter(cpu, irq) (++local_irq_count[cpu]) #define irq_exit(cpu, irq) (--local_irq_count[cpu]) -#endif -static void unexpected_irq(int irq, struct pt_regs * regs) +#endif /* __SMP__ */ + +static void +unexpected_irq(int irq, struct pt_regs * regs) { +#if 0 +#if 1 + printk("device_interrupt: unexpected interrupt %d\n", irq); +#else struct irqaction *action; int i; printk("IO device interrupt, irq = %d\n", irq); printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps); printk("Expecting: "); - for (i = 0; i < 16; i++) + for (i = 0; i < ACTUAL_NR_IRQS; i++) if ((action = irq_action[i])) while (action->handler) { printk("[%s:%d] ", action->name, i); action = action->next; } printk("\n"); +#endif +#endif #if defined(CONFIG_ALPHA_JENSEN) /* ??? Is all this just debugging, or are the inb's and outb's @@ -951,30 +676,13 @@ static void unexpected_irq(int irq, struct pt_regs * regs) #endif } -static inline void handle_irq(int irq, struct pt_regs * regs) -{ - struct irqaction * action = irq_action[irq]; - int cpu = smp_processor_id(); - - irq_enter(cpu, irq); - kstat.irqs[cpu][irq] += 1; - if (!action) { - unexpected_irq(irq, regs); - } else { - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - } - irq_exit(cpu, irq); -} - -static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) +void +handle_irq(int irq, int ack, struct pt_regs * regs) { struct irqaction * action; int cpu = smp_processor_id(); - if ((unsigned) irq > NR_IRQS) { + if ((unsigned) irq > ACTUAL_NR_IRQS) { printk("device_interrupt: illegal interrupt %d\n", irq); return; } @@ -992,8 +700,10 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) * never unmasked. The autoirq stuff depends on this (it looks * at the masks before and after doing the probing). */ - mask_irq(ack); - ack_irq(ack); + if (ack >= 0) { + mask_irq(ack); + alpha_mv.ack_irq(ack); + } if (action) { if (action->flags & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); @@ -1001,622 +711,28 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs) action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - unmask_irq(ack); + if (ack >= 0) + unmask_irq(ack); } else { -#if 1 - printk("device_interrupt: unexpected interrupt %d\n", irq); -#endif + unexpected_irq(irq, regs); } irq_exit(cpu, irq); } -#ifdef CONFIG_PCI - -/* - * Handle ISA interrupt via the PICs. - */ -static inline void isa_device_interrupt(unsigned long vector, - struct pt_regs * regs) -{ -#if defined(CONFIG_ALPHA_APECS) -# define IACK_SC APECS_IACK_SC -#elif defined(CONFIG_ALPHA_LCA) -# define IACK_SC LCA_IACK_SC -#elif defined(CONFIG_ALPHA_CIA) -# define IACK_SC CIA_IACK_SC -#elif defined(CONFIG_ALPHA_PYXIS) -# define IACK_SC PYXIS_IACK_SC -#elif defined(CONFIG_ALPHA_TSUNAMI) -# define IACK_SC TSUNAMI_PCI0_IACK_SC -#else - /* - * This is bogus but necessary to get it to compile - * on all platforms. If you try to use this on any - * other than the intended platforms, you'll notice - * real fast... - */ -# define IACK_SC 1L -#endif - int j; - -#if 1 - /* - * Generate a PCI interrupt acknowledge cycle. The PIC will - * respond with the interrupt vector of the highest priority - * interrupt that is pending. The PALcode sets up the - * interrupts vectors such that irq level L generates vector L. - */ - j = *(vuip) IACK_SC; - j &= 0xff; - if (j == 7) { - if (!(inb(0x20) & 0x80)) { - /* It's only a passive release... */ - return; - } - } - device_interrupt(j, j, regs); -#else - unsigned long pic; - - /* - * It seems to me that the probability of two or more *device* - * interrupts occurring at almost exactly the same time is - * pretty low. So why pay the price of checking for - * additional interrupts here if the common case can be - * handled so much easier? - */ - /* - * The first read of gives you *all* interrupting lines. - * Therefore, read the mask register and and out those lines - * not enabled. Note that some documentation has 21 and a1 - * write only. This is not true. - */ - pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= ~irq_mask; /* apply mask */ - pic &= 0xFFFB; /* mask out cascade & hibits */ - - while (pic) { - j = ffz(~pic); - pic &= pic - 1; - device_interrupt(j, j, regs); - } -#endif -} - -#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) -/* We have to conditionally compile this because of GRU_xxx symbols */ -static inline void -alcor_and_xlt_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary register of the GRU */ - pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS; - -#if 0 - printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8)); -#endif - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 31) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(16 + i, 16 + i, regs); - } - } - restore_flags(flags); -} -#endif /* ALCOR || XLT */ - -static inline void -cabriolet_and_eb66p_device_interrupt(unsigned long vector, - struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary registers */ - pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16); - -#if 0 - printk("[0x%04X/0x%04X]", pld, inb(0x20) | (inb(0xA0) << 8)); -#endif - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 4) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(16 + i, 16 + i, regs); - } - } - restore_flags(flags); -} - -static inline void -mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary registers */ - pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | - (((unsigned long) inb(0xa0)) << 8) | - ((unsigned long) inb(0x20)); - -#if 0 - printk("[0x%08lx]", pld); -#endif - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i < 16) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(i, i, regs); - } - } - restore_flags(flags); -} - -static inline void -eb66_and_eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary registers */ - pld = inb(0x26) | (inb(0x27) << 8); - /* - * Now, for every possible bit set, work through - * them and call the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - - if (i == 5) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(16 + i, 16 + i, regs); - } - } - restore_flags(flags); -} - -#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) -/* We have to conditionally compile this because of PYXIS_xxx symbols */ -static inline void -miata_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld, tmp; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - -#if 0 - printk("[0x%08lx/0x%08lx/0x%04x]", pld, - *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8)); -#endif - -#ifdef CONFIG_ALPHA_MIATA - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) - * then all the PCI slots/INTXs (12-31). - */ - /* Maybe HALT should only be used for SRM console boots? */ - pld &= 0x00000000fffff1c4UL; -#endif -#ifdef CONFIG_ALPHA_SX164 - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7) - * then all the PCI slots/INTXs (8-23) - */ - /* Maybe HALT should only be used for SRM console boots? */ - pld &= 0x0000000000ffffc0UL; -#endif /* SX164 */ - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) { - isa_device_interrupt(vector, regs); - } else if (i == 6) - continue; - else { /* if not timer int */ - device_interrupt(16 + i, 16 + i, regs); - } - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - tmp = *(vulp)PYXIS_INT_REQ; - } - restore_flags(flags); -} -#endif /* MIATA || SX164 */ - -static inline void -noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary registers of NORITAKE */ - pld = ((unsigned long) inw(0x54c) << 32) | - ((unsigned long) inw(0x54a) << 16) | - ((unsigned long) inb(0xa0) << 8) | - ((unsigned long) inb(0x20)); - -#if 0 - printk("[0x%08lx]", pld); -#endif - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i < 16) { - isa_device_interrupt(vector, regs); - } else { - device_interrupt(i, i, regs); - } - } - restore_flags(flags); -} - -#if defined(CONFIG_ALPHA_DP264) -/* we have to conditionally compile this because of TSUNAMI_xxx symbols */ -static inline void dp264_device_interrupt(unsigned long vector, - struct pt_regs * regs) -{ - unsigned long pld, tmp; - unsigned int i; - unsigned long flags; - - __save_and_cli(flags); - - /* Read the interrupt summary register of TSUNAMI */ - pld = (*(vulp)TSUNAMI_CSR_DIR0); - -#if 0 - printk("[0x%08lx/0x%08lx/0x%04x]", pld, - *(vulp)TSUNAMI_CSR_DIM0, - inb(0x20) | (inb(0xA0) << 8)); -#endif - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 55) { - isa_device_interrupt(vector, regs); - } else { /* if not timer int */ - device_interrupt(16 + i, 16 + i, regs); - } -#if 0 - *(vulp)TSUNAMI_CSR_DIR0 = 1UL << i; mb(); - tmp = *(vulp)TSUNAMI_CSR_DIR0; -#endif - } - __restore_flags(flags); -} -#endif /* DP264 */ - -#if defined(CONFIG_ALPHA_RAWHIDE) -/* we have to conditionally compile this because of MCPCIA_xxx symbols */ -static inline void rawhide_device_interrupt(unsigned long vector, - struct pt_regs * regs) -{ -#if 0 - unsigned long pld; - unsigned int i; - unsigned long flags; - - __save_and_cli(flags); - - /* PLACEHOLDER, perhaps never used if we always do SRM */ - - __restore_flags(flags); -#endif -} -#endif /* RAWHIDE */ - -#if defined(CONFIG_ALPHA_RUFFIAN) -static inline void -ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) - -{ - unsigned long pld; - unsigned int i; - unsigned long flags; - - save_and_cli(flags); - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - - /* For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142 (8) - * then all the PCI slots/INTXs (12-31) - * flash(5) :DWH: - */ - pld &= 0x00000000ffffff9fUL;/* was ffff7f */ - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) { - /* Copy this bit from isa_device_interrupt cause - we need to hook into int 0 for the timer. I - refuse to soil device_interrupt with ifdefs. */ - - /* Generate a PCI interrupt acknowledge cycle. - The PIC will respond with the interrupt - vector of the highest priority interrupt - that is pending. The PALcode sets up the - interrupts vectors such that irq level L - generates vector L. */ - - unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; - if (j == 7 && !(inb(0x20) & 0x80)) { - /* It's only a passive release... */ - } else if (j == 0) { - timer_interrupt(regs); - ack_irq(0); - } else { - device_interrupt(j, j, regs); - } - } else { /* if not timer int */ - device_interrupt(16 + i, 16 + i, regs); - } - - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - *(vulp)PYXIS_INT_REQ; /* read to force the write */ - } - restore_flags(flags); -} -#endif /* RUFFIAN */ - -static inline void takara_device_interrupt(unsigned long vector, - struct pt_regs * regs) -{ - unsigned long flags; - unsigned intstatus; - - save_and_cli(flags); - - /* - * The PALcode will have passed us vectors 0x800 or 0x810, - * which are fairly arbitrary values and serve only to tell - * us whether an interrupt has come in on IRQ0 or IRQ1. If - * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's - * probably ISA, but PCI interrupts can come through IRQ0 - * as well if the interrupt controller isn't in accelerated - * mode. - * - * OTOH, the accelerator thing doesn't seem to be working - * overly well, so what we'll do instead is try directly - * examining the Master Interrupt Register to see if it's a - * PCI interrupt, and if _not_ then we'll pass it on to the - * ISA handler. - */ - - intstatus = inw(0x500) & 15; - if (intstatus) { - /* - * This is a PCI interrupt. Check each bit and - * despatch an interrupt if it's set. - */ - if (intstatus & 8) device_interrupt(16+3, 16+3, regs); - if (intstatus & 4) device_interrupt(16+2, 16+2, regs); - if (intstatus & 2) device_interrupt(16+1, 16+1, regs); - if (intstatus & 1) device_interrupt(16+0, 16+0, regs); - } else - isa_device_interrupt (vector, regs); - - restore_flags(flags); -} - -#endif /* CONFIG_PCI */ - -/* - * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and - * 0x9X0 for the local motherboard interrupts.. - * - * 0x660 - NMI - * - * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) - * 0x810 - IRQ1 line printer (duh..) - * 0x860 - IRQ6 floppy disk - * 0x8E0 - IRQ14 SCSI controller - * - * 0x900 - COM1 - * 0x920 - COM2 - * 0x980 - keyboard - * 0x990 - mouse - * - * PCI-based systems are more sane: they don't have the local - * interrupts at all, and have only normal PCI interrupts from - * devices. Happily it's easy enough to do a sane mapping from the - * Jensen.. Note that this means that we may have to do a hardware - * "ack" to a different interrupt than we report to the rest of the - * world. - */ -static inline void -srm_device_interrupt(unsigned long vector, struct pt_regs * regs) -{ - int irq, ack; - unsigned long flags; - - __save_and_cli(flags); - -#ifdef __SMP__ -if (smp_processor_id()) printk("srm_device_interrupt on other CPU\n"); -#endif - - ack = irq = (vector - 0x800) >> 4; - -#ifdef CONFIG_ALPHA_JENSEN - switch (vector) { - case 0x660: handle_nmi(regs); return; - /* local device interrupts: */ - case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */ - case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */ - case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */ - case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */ - default: - if (vector > 0x900) { - printk("Unknown local interrupt %lx\n", vector); - } - } - /* irq1 is supposed to be the keyboard, silly Jensen - (is this really needed??) */ - if (irq == 1) - irq = 7; -#endif /* CONFIG_ALPHA_JENSEN */ - -#ifdef CONFIG_ALPHA_MIATA - /* - * I really hate to do this, but the MIATA SRM console ignores the - * low 8 bits in the interrupt summary register, and reports the - * vector 0x80 *lower* than I expected from the bit numbering in - * the documentation. - * This was done because the low 8 summary bits really aren't used - * for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't - * used for this purpose, as PIC interrupts are delivered as the - * vectors 0x800-0x8f0). - * But I really don't want to change the fixup code for allocation - * of IRQs, nor the irq_mask maintenance stuff, both of which look - * nice and clean now. - * So, here's this grotty hack... :-( - */ - if (irq >= 16) - ack = irq = irq + 8; -#endif /* CONFIG_ALPHA_MIATA */ - -#ifdef CONFIG_ALPHA_NORITAKE - /* - * I really hate to do this, too, but the NORITAKE SRM console also - * reports PCI vectors *lower* than I expected from the bit numbers - * in the documentation. - * But I really don't want to change the fixup code for allocation - * of IRQs, nor the irq_mask maintenance stuff, both of which look - * nice and clean now. - * So, here's this additional grotty hack... :-( - */ - if (irq >= 16) - ack = irq = irq + 1; -#endif /* CONFIG_ALPHA_NORITAKE */ - -#ifdef CONFIG_ALPHA_SABLE - irq = sable_mask_to_irq[(ack)]; -#if 0 - if (irq == 5 || irq == 9 || irq == 10 || irq == 11 || - irq == 14 || irq == 15) - printk("srm_device_interrupt: vector=0x%lx ack=0x%x" - " irq=0x%x\n", vector, ack, irq); -#endif -#endif /* CONFIG_ALPHA_SABLE */ - -#ifdef CONFIG_ALPHA_DP264 - /* - * the DP264 SRM console reports PCI interrupts with a vector - * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) - * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have - * it line up with the actual bit numbers from the DIM registers, - * which is how we manage the interrupts/mask. Sigh... - */ - if (irq >= 32) - ack = irq = irq - 16; -#endif /* DP264 */ - -#ifdef CONFIG_ALPHA_RAWHIDE - /* - * the RAWHIDE SRM console reports PCI interrupts with a vector - * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) - * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have - * it line up with the actual bit numbers from the REQ registers, - * which is how we manage the interrupts/mask. Sigh... - * - * also, PCI #1 interrupts are offset some more... :-( - */ - if (irq == 52) - ack = irq = 56; /* SCSI on PCI 1 is special */ - else { - if (irq >= 24) /* adjust all PCI interrupts down 8 */ - ack = irq = irq - 8; - if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */ - ack = irq = irq - 8; - } -#endif /* RAWHIDE */ - - device_interrupt(irq, ack, regs); - - __restore_flags(flags); -} /* * Start listening for interrupts.. */ -unsigned long probe_irq_on(void) + +unsigned long +probe_irq_on(void) { struct irqaction * action; unsigned long irqs = 0; unsigned long delay; unsigned int i; - for (i = NR_IRQS - 1; i > 0; i--) { + for (i = ACTUAL_NR_IRQS - 1; i > 0; i--) { if (!(PROBE_MASK & (1UL << i))) { continue; } @@ -1634,8 +750,8 @@ unsigned long probe_irq_on(void) for (delay = jiffies + HZ/10; delay > jiffies; ) barrier(); - /* now filter out any obviously spurious interrupts */ - return irqs & ~irq_mask; + /* Now filter out any obviously spurious interrupts. */ + return irqs & ~alpha_irq_mask; } /* @@ -1643,11 +759,13 @@ unsigned long probe_irq_on(void) * we have several candidates (but we return the lowest-numbered * one). */ -int probe_irq_off(unsigned long irqs) + +int +probe_irq_off(unsigned long irqs) { int i; - irqs &= irq_mask; + irqs &= alpha_irq_mask; if (!irqs) return 0; i = ffz(~irqs); @@ -1656,42 +774,10 @@ int probe_irq_off(unsigned long irqs) return i; } -extern void lca_machine_check (unsigned long vector, unsigned long la, - struct pt_regs *regs); -extern void apecs_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); -extern void cia_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); -extern void pyxis_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); -extern void t2_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); -extern void tsunami_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); -extern void mcpcia_machine_check(unsigned long vector, unsigned long la, - struct pt_regs * regs); - -static void -machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs) -{ -#if defined(CONFIG_ALPHA_LCA) - lca_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_APECS) - apecs_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_CIA) - cia_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_PYXIS) - pyxis_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_T2) - t2_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_TSUNAMI) - tsunami_machine_check(vector, la, regs); -#elif defined(CONFIG_ALPHA_MCPCIA) - mcpcia_machine_check(vector, la, regs); -#else - printk("Machine check\n"); -#endif -} + +/* + * The main interrupt entry point. + */ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, @@ -1701,56 +787,20 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, switch (type) { case 0: #ifdef __SMP__ -/* irq_enter(smp_processor_id(), 0); ??????? */ handle_ipi(®s); -/* irq_exit(smp_processor_id(), 0); ??????? */ return; -#else /* __SMP__ */ +#else printk("Interprocessor interrupt? You must be kidding\n"); -#endif /* __SMP__ */ +#endif break; case 1: - handle_irq(RTC_IRQ, ®s); + handle_irq(RTC_IRQ, -1, ®s); return; case 2: - machine_check(vector, la_ptr, ®s); + alpha_mv.machine_check(vector, la_ptr, ®s); return; case 3: -#if defined(CONFIG_ALPHA_JENSEN) || \ - defined(CONFIG_ALPHA_NONAME) || \ - defined(CONFIG_ALPHA_P2K) || \ - defined(CONFIG_ALPHA_SRM) - srm_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_MIATA) || \ - defined(CONFIG_ALPHA_SX164) - miata_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_NORITAKE) - noritake_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_ALCOR) || \ - defined(CONFIG_ALPHA_XLT) - alcor_and_xlt_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_CABRIOLET) || \ - defined(CONFIG_ALPHA_EB66P) || \ - defined(CONFIG_ALPHA_EB164) || \ - defined(CONFIG_ALPHA_PC164) || \ - defined(CONFIG_ALPHA_LX164) - cabriolet_and_eb66p_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_MIKASA) - mikasa_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_EB66) || \ - defined(CONFIG_ALPHA_EB64P) - eb66_and_eb64p_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_RUFFIAN) - ruffian_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_DP264) - dp264_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_RAWHIDE) - rawhide_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_TAKARA) - takara_device_interrupt(vector, ®s); -#elif NR_IRQS == 16 - isa_device_interrupt(vector, ®s); -#endif + alpha_mv.device_interrupt(vector, ®s); return; case 4: printk("Performance counter interrupt\n"); @@ -1761,226 +811,9 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps); } -extern asmlinkage void entInt(void); - -static inline void sable_init_IRQ(void) -{ - outb(irq_mask , 0x537); /* slave 0 */ - outb(irq_mask >> 8, 0x53b); /* slave 1 */ - outb(irq_mask >> 16, 0x53d); /* slave 2 */ - outb(0x44, 0x535); /* enable cascades in master */ -} - -#if defined(CONFIG_ALPHA_SX164) -static inline void sx164_init_IRQ(void) -{ -#if !defined(CONFIG_ALPHA_SRM) - /* note invert on MASK bits */ - *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); - *(vulp)PYXIS_INT_MASK; -#endif /* !SRM */ - enable_irq(16 + 6); /* enable timer */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(2); /* enable cascade */ -} -#endif /* SX164 */ - -#if defined(CONFIG_ALPHA_RUFFIAN) -static inline void ruffian_init_IRQ(void) -{ - /* invert 6&7 for i82371 */ - *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); - *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ - *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); - *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); - - outb(0x11,0xA0); - outb(0x08,0xA1); - outb(0x02,0xA1); - outb(0x01,0xA1); - outb(0xFF,0xA1); - - outb(0x11,0x20); - outb(0x00,0x21); - outb(0x04,0x21); - outb(0x01,0x21); - outb(0xFF,0x21); - - /* Send -INTA pulses to clear any pending interrupts ...*/ - *(vuip) IACK_SC; - - /* Finish writing the 82C59A PIC Operation Control Words */ - outb(0x20,0xA0); - outb(0x20,0x20); - - /* Turn on the interrupt controller, the timer interrupt */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(0); /* enable timer */ - enable_irq(2); /* enable 2nd PIC cascade */ -} -#endif /* RUFFIAN */ - -#ifdef CONFIG_ALPHA_MIATA -static inline void miata_init_IRQ(void) -{ - /* note invert on MASK bits */ - *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); /* invert */ -#if 0 - /* these break on MiataGL so we'll try not to do it at all */ - *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ - *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ -#endif - /* clear upper timer */ - *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb(); - - enable_irq(16 + 2); /* enable HALT switch - SRM only? */ - enable_irq(16 + 6); /* enable timer */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(2); /* enable cascade */ -} -#endif - -static inline void noritake_init_IRQ(void) -{ - outw(~(irq_mask >> 16), 0x54a); /* note invert */ - outw(~(irq_mask >> 32), 0x54c); /* note invert */ - enable_irq(2); /* enable cascade */ -} - -#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) -static inline void alcor_and_xlt_init_IRQ(void) -{ - *(vuip)GRU_INT_MASK = ~(irq_mask >> 16); mb(); /* note invert */ - *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */ - *(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */ - *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */ - - enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ - enable_irq(2); /* enable cascade */ -} -#endif /* ALCOR || XLT */ - -static inline void mikasa_init_IRQ(void) -{ - outw(~(irq_mask >> 16), 0x536); /* note invert */ - enable_irq(2); /* enable cascade */ -} - -#if defined(CONFIG_ALPHA_DP264) -static inline void dp264_init_IRQ(void) -{ - /* note invert on MASK bits */ - *(vulp)TSUNAMI_CSR_DIM0 = - ~(irq_mask) & ~0x0000000000000000UL; mb(); - *(vulp)TSUNAMI_CSR_DIM0; - enable_irq(55); /* enable CYPRESS interrupt controller (ISA) */ - enable_irq(2); -} -#endif /* DP264 */ - -#if defined(CONFIG_ALPHA_RAWHIDE) -static inline void rawhide_init_IRQ(void) -{ - /* HACK ALERT! only PCI busses 0 and 1 are used currently, - and routing is only to CPU #1*/ - - *(vuip)MCPCIA_INT_MASK0(0) = - (~((irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(0); - - *(vuip)MCPCIA_INT_MASK0(1) = - (~((irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); - /* ... and read it back to make sure it got written. */ - *(vuip)MCPCIA_INT_MASK0(1); - enable_irq(2); -} -#endif /* RAWHIDE */ - -static inline void takara_init_IRQ(void) -{ - unsigned int ctlreg = inl(0x500); - - ctlreg &= ~0x8000; /* return to non-accelerated mode */ - outw(ctlreg >> 16, 0x502); - outw(ctlreg & 0xFFFF, 0x500); - ctlreg = 0x05107c00; /* enable the PCI interrupt register */ - printk("Setting to 0x%08x\n", ctlreg); - outw(ctlreg >> 16, 0x502); - outw(ctlreg & 0xFFFF, 0x500); - enable_irq(2); -} - -static inline void init_IRQ_35(void) -{ -#if !defined(CONFIG_ALPHA_SRM) - outl(irq_mask >> 16, 0x804); -#endif /* !SRM */ - enable_irq(16 + 4); /* enable SIO cascade */ - enable_irq(2); /* enable cascade */ -} - -static inline void init_IRQ_32(void) -{ - outb(irq_mask >> 16, 0x26); - outb(irq_mask >> 24, 0x27); - enable_irq(16 + 5); /* enable SIO cascade */ - enable_irq(2); /* enable cascade */ -} - -static inline void init_IRQ_16(void) -{ - enable_irq(2); /* enable cascade */ -} - void __init init_IRQ(void) { wrent(entInt, 0); - -/* FIXME FIXME FIXME FIXME FIXME */ -#if !defined(CONFIG_ALPHA_DP264) - /* we need to figure out why these fail on the DP264 */ - outb(0, DMA1_RESET_REG); - outb(0, DMA2_RESET_REG); -#endif /* !DP264 */ -/* FIXME FIXME FIXME FIXME FIXME */ -#if !defined(CONFIG_ALPHA_SX164) && !defined(CONFIG_ALPHA_DP264) - outb(0, DMA1_CLR_MASK_REG); - /* we need to figure out why this fails on the SX164 */ - outb(0, DMA2_CLR_MASK_REG); -#endif /* !SX164 && !DP264 */ -/* end FIXMEs */ - -#if defined(CONFIG_ALPHA_SABLE) - sable_init_IRQ(); -#elif defined(CONFIG_ALPHA_MIATA) - miata_init_IRQ(); -#elif defined(CONFIG_ALPHA_SX164) - sx164_init_IRQ(); -#elif defined(CONFIG_ALPHA_NORITAKE) - noritake_init_IRQ(); -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) - alcor_and_xlt_init_IRQ(); -#elif defined(CONFIG_ALPHA_MIKASA) - mikasa_init_IRQ(); -#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \ - defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) || \ - defined(CONFIG_ALPHA_EB164) - init_IRQ_35(); -#elif defined(CONFIG_ALPHA_RUFFIAN) - ruffian_init_IRQ(); -#elif defined(CONFIG_ALPHA_DP264) - dp264_init_IRQ(); -#elif defined(CONFIG_ALPHA_RAWHIDE) - rawhide_init_IRQ(); -#elif defined(CONFIG_ALPHA_TAKARA) - takara_init_IRQ(); -#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) - init_IRQ_32(); -#elif NR_IRQS == 16 - init_IRQ_16(); -#else -#error "How do I initialize the interrupt hardware?" -#endif + alpha_mv.init_irq(); } diff --git a/arch/alpha/kernel/irq.h b/arch/alpha/kernel/irq.h new file mode 100644 index 000000000..08db28ec5 --- /dev/null +++ b/arch/alpha/kernel/irq.h @@ -0,0 +1,27 @@ +/* + * linux/arch/alpha/kernel/irq.h + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1998 Richard Henderson + * + * This file contains declarations and inline functions for interfacing + * with the IRQ handling routines in irq.c. + */ + + +/* FIXME FIXME FIXME FIXME FIXME */ +/* We need to figure out why these fail on the DP264 & SX164. Otherwise + we'd just do this in init_IRQ(). */ +#define STANDARD_INIT_IRQ_PROLOG \ + outb(0, DMA1_RESET_REG); \ + outb(0, DMA2_RESET_REG); \ + outb(0, DMA1_CLR_MASK_REG); \ + outb(0, DMA2_CLR_MASK_REG) + +extern unsigned long alpha_irq_mask; + +extern void generic_ack_irq(unsigned long irq); +extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs); +extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs); + +extern void handle_irq(int irq, int ack, struct pt_regs * regs); diff --git a/arch/alpha/kernel/machvec.h b/arch/alpha/kernel/machvec.h new file mode 100644 index 000000000..6ac7cc6a0 --- /dev/null +++ b/arch/alpha/kernel/machvec.h @@ -0,0 +1,137 @@ +/* + * linux/arch/alpha/kernel/machvec.h + * + * Copyright (C) 1997, 1998 Richard Henderson + * + * This file has goodies to help simplify instantiation of machine vectors. + */ + +#include <linux/config.h> + +/* Whee. TSUNAMI doesn't have an HAE. Fix things up for the GENERIC + kernel by defining the HAE address to be that of the cache. Now + we can read and write it as we like. ;-) */ +#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) + +/* Only a few systems don't define IACK_SC, handling all interrupts through + the SRM console. But splitting out that one case from IO() below + seems like such a pain. Define this to get things to compile. */ +#define JENSEN_IACK_SC 1 +#define T2_IACK_SC 1 + + +/* + * Some helpful macros for filling in the blanks. + */ + +#define CAT1(x,y) x##y +#define CAT(x,y) CAT1(x,y) + +#define DO_DEFAULT_RTC \ + rtc_port: 0x70, rtc_addr: 0x80 + +#define DO_EV4_MMU \ + max_asn: EV4_MAX_ASN, \ + mmu_context_mask: ~0UL, \ + mv_get_mmu_context: ev4_get_mmu_context, \ + mv_flush_tlb_current: ev4_flush_tlb_current, \ + mv_flush_tlb_other: ev4_flush_tlb_other, \ + mv_flush_tlb_current_page: ev4_flush_tlb_current_page + +#define DO_EV5_MMU \ + max_asn: EV5_MAX_ASN, \ + mmu_context_mask: ~0UL, \ + mv_get_mmu_context: ev5_get_mmu_context, \ + mv_flush_tlb_current: ev5_flush_tlb_current, \ + mv_flush_tlb_other: ev5_flush_tlb_other, \ + mv_flush_tlb_current_page: ev5_flush_tlb_current_page + +#define DO_EV6_MMU \ + max_asn: EV5_MAX_ASN, \ + mmu_context_mask: 0xfffffffffful, \ + mv_get_mmu_context: ev5_get_mmu_context, \ + mv_flush_tlb_current: ev5_flush_tlb_current, \ + mv_flush_tlb_other: ev5_flush_tlb_other, \ + mv_flush_tlb_current_page: ev5_flush_tlb_current_page + +#define IO_LITE(UP,low1,low2) \ + hae_register: (unsigned long *) CAT(UP,_HAE_ADDRESS), \ + iack_sc: CAT(UP,_IACK_SC), \ + mv_inb: CAT(low1,_inb), \ + mv_inw: CAT(low1,_inw), \ + mv_inl: CAT(low1,_inl), \ + mv_outb: CAT(low1,_outb), \ + mv_outw: CAT(low1,_outw), \ + mv_outl: CAT(low1,_outl), \ + mv_readb: CAT(low1,_readb), \ + mv_readw: CAT(low1,_readw), \ + mv_readl: CAT(low1,_readl), \ + mv_readq: CAT(low1,_readq), \ + mv_writeb: CAT(low1,_writeb), \ + mv_writew: CAT(low1,_writew), \ + mv_writel: CAT(low1,_writel), \ + mv_writeq: CAT(low1,_writeq), \ + mv_dense_mem: CAT(low2,_dense_mem) + +#define IO(UP,low1,low2) \ + IO_LITE(UP,low1,low2), \ + pci_read_config_byte: CAT(low2,_pcibios_read_config_byte), \ + pci_read_config_word: CAT(low2,_pcibios_read_config_word), \ + pci_read_config_dword: CAT(low2,_pcibios_read_config_dword), \ + pci_write_config_byte: CAT(low2,_pcibios_write_config_byte), \ + pci_write_config_word: CAT(low2,_pcibios_write_config_word), \ + pci_write_config_dword: CAT(low2,_pcibios_write_config_dword), \ + dma_win_base: CAT(UP,_DMA_WIN_BASE_DEFAULT), \ + dma_win_size: CAT(UP,_DMA_WIN_SIZE_DEFAULT) + +/* Any assembler that can generate a GENERIC kernel can generate BWX + instructions. So always use them for PYXIS I/O. */ + +#define DO_APECS_IO IO(APECS,apecs,apecs) +#define DO_CIA_IO IO(CIA,cia,cia) +#define DO_LCA_IO IO(LCA,lca,lca) +#define DO_MCPCIA_IO IO(MCPCIA,mcpcia,mcpcia) +#define DO_PYXIS_IO IO(PYXIS,pyxis_bw,pyxis) +#define DO_T2_IO IO(T2,t2,t2) +#define DO_TSUNAMI_IO IO(TSUNAMI,tsunami,tsunami) + +#define BUS(which) \ + mv_virt_to_bus: CAT(which,_virt_to_bus), \ + mv_bus_to_virt: CAT(which,_bus_to_virt) + +#define DO_APECS_BUS BUS(apecs) +#define DO_CIA_BUS BUS(cia) +#define DO_LCA_BUS BUS(lca) +#define DO_MCPCIA_BUS BUS(mcpcia) +#define DO_PYXIS_BUS BUS(pyxis) +#define DO_T2_BUS BUS(t2) +#define DO_TSUNAMI_BUS BUS(tsunami) + + +/* + * In a GENERIC kernel, we have lots of these vectors floating about, + * all but one of which we want to go away. In a non-GENERIC kernel, + * we want only one, ever. + * + * Accomplish this in the GENERIC kernel by puting all of the vectors + * in the .init.data section where they'll go away. We'll copy the + * one we want to the real alpha_mv vector in setup_arch. + * + * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but + * one of the vectors, which will not reside in .init.data. We then + * alias this one vector to alpha_mv, so no copy is needed. + * + * Upshot: set __initdata to nothing for non-GENERIC kernels. + */ + +#ifdef CONFIG_ALPHA_GENERIC +#define __initmv __initdata +#define ALIAS_MV(x) +#else +#define __initmv + +/* GCC actually has a syntax for defining aliases, but is under some + delusion that you shouldn't be able to declare it extern somewhere + else beforehand. Fine. We'll do it ourselves. */ +#define ALIAS_MV(system) asm(".global alpha_mv\nalpha_mv = " #system "_mv"); +#endif diff --git a/arch/alpha/kernel/mcpcia.c b/arch/alpha/kernel/mcpcia.c deleted file mode 100644 index 6a9dab59a..000000000 --- a/arch/alpha/kernel/mcpcia.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Code common to all MCbus-PCI adaptor chipsets - * - * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). - * - */ -#include <linux/kernel.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/sched.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/hwrpb.h> -#include <asm/ptrace.h> -#include <asm/mmu_context.h> -#include <asm/delay.h> - -/* - * NOTE: Herein lie back-to-back mb instructions. They are magic. - * One plausible explanation is that the i/o controller does not properly - * handle the system transaction. Another involves timing. Ho hum. - */ - -extern struct hwrpb_struct *hwrpb; -extern asmlinkage void wrmces(unsigned long mces); - -/* - * BIOS32-style PCI interface: - */ - -#ifdef CONFIG_ALPHA_MCPCIA - -#undef DEBUG_CFG - -#ifdef DEBUG_CFG -# define DBG_CFG(args) printk args -#else -# define DBG_CFG(args) -#endif - -#undef DEBUG_PCI - -#ifdef DEBUG_PCI -# define DBG_PCI(args) printk args -#else -# define DBG_PCI(args) -#endif - -#define DEBUG_MCHECK - -#ifdef DEBUG_MCHECK -# define DBG_MCK(args) printk args -# define DEBUG_MCHECK_DUMP -#else -# define DBG_MCK(args) -#endif - -#define vuip volatile unsigned int * -#define vulp volatile unsigned long * - -static volatile unsigned int MCPCIA_mcheck_expected[NR_CPUS]; -static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS]; -static unsigned int MCPCIA_jd[NR_CPUS]; - -#define MCPCIA_MAX_HOSES 2 -static int mcpcia_num_hoses = 0; - -static int pci_probe_enabled = 0; /* disable to start */ - -static struct linux_hose_info *mcpcia_root = NULL, *mcpcia_last_hose; - -struct linux_hose_info *bus2hose[256]; - -static inline unsigned long long_align(unsigned long addr) -{ - return ((addr + (sizeof(unsigned long) - 1)) & - ~(sizeof(unsigned long) - 1)); -} - -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int MCPCIA_DMA_WIN_BASE = MCPCIA_DMA_WIN_BASE_DEFAULT; -unsigned int MCPCIA_DMA_WIN_SIZE = MCPCIA_DMA_WIN_SIZE_DEFAULT; -unsigned long mcpcia_sm_base_r1, mcpcia_sm_base_r2, mcpcia_sm_base_r3; -#endif /* SRM_SETUP */ - -/* - * Given a bus, device, and function number, compute resulting - * configuration space address and setup the MCPCIA_HAXR2 register - * accordingly. It is therefore not safe to have concurrent - * invocations to configuration space access routines, but there - * really shouldn't be any need for this. - * - * Type 0: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:11 Device select bit. - * 10:8 Function number - * 7:2 Register number - * - * Type 1: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:24 reserved - * 23:16 bus number (8 bits = 128 possible buses) - * 15:11 Device number (5 bits) - * 10:8 function number - * 7:2 register number - * - * Notes: - * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). - * - * The register selects a DWORD (32 bit) register offset. Hence it - * doesn't get shifted by 2 bits as we want to "drop" the bottom two - * bits. - */ - -static unsigned int -conf_read(unsigned long addr, unsigned char type1, - struct linux_hose_info *hose) -{ - unsigned long flags; - unsigned long hoseno = hose->pci_hose_index; - unsigned int stat0, value, temp, cpu; - - cpu = smp_processor_id(); - - save_and_cli(flags); - - DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n", - addr, type1, hoseno)); - - /* reset status register to avoid losing errors: */ - stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); - *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); - DBG_CFG(("conf_read: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); - - mb(); - draina(); - MCPCIA_mcheck_expected[cpu] = 1; - MCPCIA_mcheck_taken[cpu] = 0; - mb(); - /* access configuration space: */ - value = *((vuip)addr); - mb(); - mb(); /* magic */ - if (MCPCIA_mcheck_taken[cpu]) { - MCPCIA_mcheck_taken[cpu] = 0; - value = 0xffffffffU; - mb(); - } - MCPCIA_mcheck_expected[cpu] = 0; - mb(); - - DBG_CFG(("conf_read(): finished\n")); - - restore_flags(flags); - return value; -} - - -static void -conf_write(unsigned long addr, unsigned int value, unsigned char type1, - struct linux_hose_info *hose) -{ - unsigned long flags; - unsigned long hoseno = hose->pci_hose_index; - unsigned int stat0, temp, cpu; - - cpu = smp_processor_id(); - - save_and_cli(flags); /* avoid getting hit by machine check */ - - /* reset status register to avoid losing errors: */ - stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno); - *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb(); - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); - DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0)); - - draina(); - MCPCIA_mcheck_expected[cpu] = 1; - mb(); - /* access configuration space: */ - *((vuip)addr) = value; - mb(); - mb(); /* magic */ - temp = *(vuip)MCPCIA_CAP_ERR(hoseno); /* read to force the write */ - MCPCIA_mcheck_expected[cpu] = 0; - mb(); - - DBG_CFG(("conf_write(): finished\n")); - restore_flags(flags); -} - -static int mk_conf_addr(struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) -{ - unsigned long addr; - - if (!pci_probe_enabled) /* if doing standard pci_init(), ignore */ - return -1; - - DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," - " pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); - - /* type 1 configuration cycle for *ALL* busses */ - *type1 = 1; - - if (hose->pci_first_busno == bus) - bus = 0; - addr = (bus << 16) | (device_fn << 8) | (where); - addr <<= 5; /* swizzle for SPARSE */ - addr |= hose->pci_config_space; - - *pci_addr = addr; - DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); - return 0; -} - - -int hose_read_config_byte (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) -{ - unsigned long addr; - unsigned char type1; - - *value = 0xff; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= 0x00; /* or in length */ - - *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - - -int hose_read_config_word (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) -{ - unsigned long addr; - unsigned char type1; - - *value = 0xffff; - - if (where & 0x1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= 0x08; /* or in length */ - - *value = conf_read(addr, type1, hose) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - - -int hose_read_config_dword (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) -{ - unsigned long addr; - unsigned char type1; - - *value = 0xffffffff; - - if (where & 0x3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - addr |= 0x18; /* or in length */ - - *value = conf_read(addr, type1, hose); - return PCIBIOS_SUCCESSFUL; -} - - -int hose_write_config_byte (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= 0x00; /* or in length */ - - conf_write(addr, value << ((where & 3) * 8), type1, hose); - return PCIBIOS_SUCCESSFUL; -} - - -int hose_write_config_word (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= 0x08; /* or in length */ - - conf_write(addr, value << ((where & 3) * 8), type1, hose); - return PCIBIOS_SUCCESSFUL; -} - - -int hose_write_config_dword (struct linux_hose_info *hose, - unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= 0x18; /* or in length */ - - conf_write(addr, value << ((where & 3) * 8), type1, hose); - return PCIBIOS_SUCCESSFUL; -} - -int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - return hose_read_config_byte(bus2hose[bus], bus, devfn, where, value); -} - -int pcibios_read_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - return hose_read_config_word(bus2hose[bus], bus, devfn, where, value); -} - -int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - return hose_read_config_dword(bus2hose[bus], bus, devfn, where, value); -} - -int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - return hose_write_config_byte(bus2hose[bus], bus, devfn, where, value); -} - -int pcibios_write_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - return hose_write_config_word(bus2hose[bus], bus, devfn, where, value); -} - -int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - return hose_write_config_dword(bus2hose[bus], bus, devfn, where, value); -} - -unsigned long mcpcia_init(unsigned long mem_start, unsigned long mem_end) -{ - struct linux_hose_info *hose; - unsigned int mcpcia_err; - unsigned int pci_rev; - int h; - - mem_start = long_align(mem_start); - - for (h = 0; h < NR_CPUS; h++) { - MCPCIA_mcheck_expected[h] = 0; - MCPCIA_mcheck_taken[h] = 0; - } - - /* first, find how many hoses we have */ - for (h = 0; h < MCPCIA_MAX_HOSES; h++) { - pci_rev = *(vuip)MCPCIA_REV(h); -#if 0 - printk("mcpcia_init: got 0x%x for PCI_REV for hose %d\n", - pci_rev, h); -#endif - if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) { - mcpcia_num_hoses++; - - hose = (struct linux_hose_info *)mem_start; - mem_start = long_align(mem_start + sizeof(*hose)); - - memset(hose, 0, sizeof(*hose)); - - if (mcpcia_root) - mcpcia_last_hose->next = hose; - else - mcpcia_root = hose; - mcpcia_last_hose = hose; - - hose->pci_io_space = MCPCIA_IO(h); - hose->pci_mem_space = MCPCIA_DENSE(h); - hose->pci_config_space = MCPCIA_CONF(h); - hose->pci_sparse_space = MCPCIA_SPARSE(h); - hose->pci_hose_index = h; - hose->pci_first_busno = 255; - hose->pci_last_busno = 0; - } - } - -#if 1 - printk("mcpcia_init: found %d hoses\n", mcpcia_num_hoses); -#endif - - /* now do init for each hose */ - for (hose = mcpcia_root; hose; hose = hose->next) { - h = hose->pci_hose_index; -#if 0 -#define PRINTK printk -PRINTK("mcpcia_init: -------- hose %d --------\n",h); -PRINTK("mcpcia_init: MCPCIA_REV 0x%x\n", *(vuip)MCPCIA_REV(h)); -PRINTK("mcpcia_init: MCPCIA_WHOAMI 0x%x\n", *(vuip)MCPCIA_WHOAMI(h)); -PRINTK("mcpcia_init: MCPCIA_HAE_MEM 0x%x\n", *(vuip)MCPCIA_HAE_MEM(h)); -PRINTK("mcpcia_init: MCPCIA_HAE_IO 0x%x\n", *(vuip)MCPCIA_HAE_IO(h)); -PRINTK("mcpcia_init: MCPCIA_HAE_DENSE 0x%x\n", *(vuip)MCPCIA_HAE_DENSE(h)); -PRINTK("mcpcia_init: MCPCIA_INT_CTL 0x%x\n", *(vuip)MCPCIA_INT_CTL(h)); -PRINTK("mcpcia_init: MCPCIA_INT_REQ 0x%x\n", *(vuip)MCPCIA_INT_REQ(h)); -PRINTK("mcpcia_init: MCPCIA_INT_TARG 0x%x\n", *(vuip)MCPCIA_INT_TARG(h)); -PRINTK("mcpcia_init: MCPCIA_INT_ADR 0x%x\n", *(vuip)MCPCIA_INT_ADR(h)); -PRINTK("mcpcia_init: MCPCIA_INT_ADR_EXT 0x%x\n", *(vuip)MCPCIA_INT_ADR_EXT(h)); -PRINTK("mcpcia_init: MCPCIA_INT_MASK0 0x%x\n", *(vuip)MCPCIA_INT_MASK0(h)); -PRINTK("mcpcia_init: MCPCIA_INT_MASK1 0x%x\n", *(vuip)MCPCIA_INT_MASK1(h)); -PRINTK("mcpcia_init: MCPCIA_HBASE 0x%x\n", *(vuip)MCPCIA_HBASE(h)); -#endif - - /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. - */ -#if 0 - mcpcia_err = *(vuip)MCPCIA_ERR_MASK(h); - mcpcia_err &= ~4; - *(vuip)MCPCIA_ERR_MASK(h) = mcpcia_err; - mb(); - mcpcia_err = *(vuip)MCPCIA_ERR_MASK; -#endif - - mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); - mcpcia_err |= 0x0006; /* master/target abort */ - *(vuip)MCPCIA_CAP_ERR(h) = mcpcia_err; - mb() ; - mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h); - -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 0 for enabled and mapped to 0 */ - if (((*(vuip)MCPCIA_W0_BASE(h) & 3) == 1) && - (*(vuip)MCPCIA_T0_BASE(h) == 0) && - ((*(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U) > 0x0ff00000U)) - { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W0_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init: using Window 0 settings\n"); - printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W0_BASE(h), - *(vuip)MCPCIA_W0_MASK(h), - *(vuip)MCPCIA_T0_BASE(h)); -#endif - } - else /* check window 1 for enabled and mapped to 0 */ - if (((*(vuip)MCPCIA_W1_BASE(h) & 3) == 1) && - (*(vuip)MCPCIA_T1_BASE(h) == 0) && - ((*(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U) > 0x0ff00000U)) -{ - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W1_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init: using Window 1 settings\n"); - printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W1_BASE(h), - *(vuip)MCPCIA_W1_MASK(h), - *(vuip)MCPCIA_T1_BASE(h)); -#endif - } - else /* check window 2 for enabled and mapped to 0 */ - if (((*(vuip)MCPCIA_W2_BASE(h) & 3) == 1) && - (*(vuip)MCPCIA_T2_BASE(h) == 0) && - ((*(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U) > 0x0ff00000U)) - { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W2_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init: using Window 2 settings\n"); - printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W2_BASE(h), - *(vuip)MCPCIA_W2_MASK(h), - *(vuip)MCPCIA_T2_BASE(h)); -#endif - } - else /* check window 3 for enabled and mapped to 0 */ - if (((*(vuip)MCPCIA_W3_BASE(h) & 3) == 1) && - (*(vuip)MCPCIA_T3_BASE(h) == 0) && - ((*(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U) > 0x0ff00000U)) - { - MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W3_BASE(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U; - MCPCIA_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("mcpcia_init: using Window 3 settings\n"); - printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)MCPCIA_W3_BASE(h), - *(vuip)MCPCIA_W3_MASK(h), - *(vuip)MCPCIA_T3_BASE(h)); -#endif - } - else /* we must use our defaults which were pre-initialized... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, we may - * want to use them to do scatter/gather DMA. Window 0 - * goes at 1 GB and is 1 GB large. - */ - - *(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE & 0xfff00000U); - *(vuip)MCPCIA_W0_MASK(h) = (MCPCIA_DMA_WIN_SIZE - 1) & 0xfff00000U; - *(vuip)MCPCIA_T0_BASE(h) = 0; - - *(vuip)MCPCIA_W1_BASE(h) = 0x0 ; - *(vuip)MCPCIA_W2_BASE(h) = 0x0 ; - *(vuip)MCPCIA_W3_BASE(h) = 0x0 ; - - *(vuip)MCPCIA_HBASE(h) = 0x0 ; - mb(); - } - - /* - * check ASN in HWRPB for validity, report if bad - */ - if (hwrpb->max_asn != MAX_ASN) { - printk("mcpcia_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); - hwrpb->max_asn = MAX_ASN; - } - -#if 0 - { - unsigned int mcpcia_int_ctl = *((vuip)MCPCIA_INT_CTL(h)); - printk("mcpcia_init: INT_CTL was 0x%x\n", mcpcia_int_ctl); - *(vuip)MCPCIA_INT_CTL(h) = 1U; mb(); - mcpcia_int_ctl = *(vuip)MCPCIA_INT_CTL(h); - } -#endif - - { - unsigned int mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h); - unsigned int mcpcia_hae_io = *(vuip)MCPCIA_HAE_IO(h); -#if 0 - printk("mcpcia_init: HAE_MEM was 0x%x\n", mcpcia_hae_mem); - printk("mcpcia_init: HAE_IO was 0x%x\n", mcpcia_hae_io); -#endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* - sigh... For the SRM setup, unless we know apriori what the HAE - contents will be, we need to setup the arbitrary region bases - so we can test against the range of addresses and tailor the - region chosen for the SPARSE memory access. - - see include/asm-alpha/mcpcia.h for the SPARSE mem read/write - */ - mcpcia_sm_base_r1 = (mcpcia_hae_mem ) & 0xe0000000UL;/* reg 1 */ - mcpcia_sm_base_r2 = (mcpcia_hae_mem << 16) & 0xf8000000UL;/* reg 2 */ - mcpcia_sm_base_r3 = (mcpcia_hae_mem << 24) & 0xfc000000UL;/* reg 3 */ - /* - Set the HAE cache, so that setup_arch() code - will use the SRM setting always. Our readb/writeb - code in mcpcia.h expects never to have to change - the contents of the HAE. - */ - hae.cache = mcpcia_hae_mem; -#else /* SRM_SETUP */ - *(vuip)MCPCIA_HAE_MEM(h) = 0U; mb(); - mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h); - *(vuip)MCPCIA_HAE_IO(h) = 0; mb(); - mcpcia_hae_io = *(vuip)MCPCIA_HAE_IO(h); -#endif /* SRM_SETUP */ - } - } /* end for-loop on hoses */ - return mem_start; -} - -int mcpcia_pci_clr_err(int h) -{ - unsigned int cpu = smp_processor_id(); - - MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); -#if 0 - DBG_MCK(("MCPCIA_pci_clr_err: MCPCIA CAP_ERR(%d) after read 0x%x\n", - h, MCPCIA_jd[cpu])); -#endif - *(vuip)MCPCIA_CAP_ERR(h) = 0xffffffff; mb(); /* clear them all */ - MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); - return 0; -} - -static void -mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout) -{ - struct el_common_EV5_uncorrectable_mcheck *frame; - int i; - - frame = &logout->procdata; - - /* Print PAL fields */ - for (i = 0; i < 24; i += 2) { - printk("\tpal temp[%d-%d]\t\t= %16lx %16lx\n\r", - i, i+1, frame->paltemp[i], frame->paltemp[i+1]); - } - for (i = 0; i < 8; i += 2) { - printk("\tshadow[%d-%d]\t\t= %16lx %16lx\n\r", - i, i+1, frame->shadow[i], - frame->shadow[i+1]); - } - printk("\tAddr of excepting instruction\t= %16lx\n\r", - frame->exc_addr); - printk("\tSummary of arithmetic traps\t= %16lx\n\r", - frame->exc_sum); - printk("\tException mask\t\t\t= %16lx\n\r", - frame->exc_mask); - printk("\tBase address for PALcode\t= %16lx\n\r", - frame->pal_base); - printk("\tInterrupt Status Reg\t\t= %16lx\n\r", - frame->isr); - printk("\tCURRENT SETUP OF EV5 IBOX\t= %16lx\n\r", - frame->icsr); - printk("\tI-CACHE Reg %s parity error\t= %16lx\n\r", - (frame->ic_perr_stat & 0x800L) ? - "Data" : "Tag", - frame->ic_perr_stat); - printk("\tD-CACHE error Reg\t\t= %16lx\n\r", - frame->dc_perr_stat); - if (frame->dc_perr_stat & 0x2) { - switch (frame->dc_perr_stat & 0x03c) { - case 8: - printk("\t\tData error in bank 1\n\r"); - break; - case 4: - printk("\t\tData error in bank 0\n\r"); - break; - case 20: - printk("\t\tTag error in bank 1\n\r"); - break; - case 10: - printk("\t\tTag error in bank 0\n\r"); - break; - } - } - printk("\tEffective VA\t\t\t= %16lx\n\r", - frame->va); - printk("\tReason for D-stream\t\t= %16lx\n\r", - frame->mm_stat); - printk("\tEV5 SCache address\t\t= %16lx\n\r", - frame->sc_addr); - printk("\tEV5 SCache TAG/Data parity\t= %16lx\n\r", - frame->sc_stat); - printk("\tEV5 BC_TAG_ADDR\t\t\t= %16lx\n\r", - frame->bc_tag_addr); - printk("\tEV5 EI_ADDR: Phys addr of Xfer\t= %16lx\n\r", - frame->ei_addr); - printk("\tFill Syndrome\t\t\t= %16lx\n\r", - frame->fill_syndrome); - printk("\tEI_STAT reg\t\t\t= %16lx\n\r", - frame->ei_stat); - printk("\tLD_LOCK\t\t\t\t= %16lx\n\r", - frame->ld_lock); -} - -void mcpcia_machine_check(unsigned long type, unsigned long la_ptr, - struct pt_regs * regs) -{ -#if 0 - printk("mcpcia machine check ignored\n") ; -#else - struct el_common *mchk_header; - struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout; - unsigned int cpu = smp_processor_id(); - int h = 0; - - mchk_header = (struct el_common *)la_ptr; - mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr; - -#if 0 - DBG_MCK(("mcpcia_machine_check: type=0x%lx la_ptr=0x%lx\n", - type, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); -#endif - /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. - */ - mb(); - mb(); /* magic */ - if (MCPCIA_mcheck_expected[cpu]) { -#if 0 - DBG_MCK(("MCPCIA machine check expected\n")); -#endif - MCPCIA_mcheck_expected[cpu] = 0; - MCPCIA_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - mcpcia_pci_clr_err(h); - wrmces(0x7); - mb(); - } -#if 1 - else { - printk("MCPCIA machine check NOT expected on CPU %d\n", cpu); - DBG_MCK(("mcpcia_machine_check: type=0x%lx pc=0x%lx" - " code=0x%lx\n", - type, regs->pc, mchk_header->code)); - - MCPCIA_mcheck_expected[cpu] = 0; - MCPCIA_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - mcpcia_pci_clr_err(h); - wrmces(0x7); - mb(); -#ifdef DEBUG_MCHECK_DUMP - if (type == 0x620) - printk("MCPCIA machine check: system CORRECTABLE!\n"); - else if (type == 0x630) - printk("MCPCIA machine check: processor CORRECTABLE!\n"); - else - mcpcia_print_uncorrectable(mchk_logout); -#endif /* DEBUG_MCHECK_DUMP */ - } -#endif -#endif -} - -/*==========================================================================*/ - -#define PRIMARY(b) ((b)&0xff) -#define SECONDARY(b) (((b)>>8)&0xff) -#define SUBORDINATE(b) (((b)>>16)&0xff) - -static int -hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - unsigned int found = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) == 0) { - hose_read_config_byte(hose, bus, devfn, - PCI_HEADER_TYPE, &hdr_type); - } else if (!(hdr_type & 0x80)) { - /* not a multi-function device */ - continue; - } - - /* Check if there is anything here. */ - hose_read_config_dword(hose, bus, devfn, PCI_VENDOR_ID, &l); - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; - continue; - } - - /* See if this is a bridge device. */ - hose_read_config_dword(hose, bus, devfn, - PCI_CLASS_REVISION, &class); - - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - unsigned int busses; - - found++; - - hose_read_config_dword(hose, bus, devfn, - PCI_PRIMARY_BUS, &busses); - -DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d busses 0x%x\n", - hose->pci_hose_index, bus, PCI_SLOT(devfn), busses)); - /* - * do something with first_busno and last_busno - */ - if (hose->pci_first_busno > PRIMARY(busses)) { - hose->pci_first_busno = PRIMARY(busses); -DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d change first to %d\n", - hose->pci_hose_index, bus, PCI_SLOT(devfn), PRIMARY(busses))); - } - if (hose->pci_last_busno < SUBORDINATE(busses)) { - hose->pci_last_busno = SUBORDINATE(busses); -DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d change last to %d\n", - hose->pci_hose_index, bus, PCI_SLOT(devfn), SUBORDINATE(busses))); - } - /* - * Now scan everything underneath the bridge. - */ - hose_scan_bridges(hose, SECONDARY(busses)); - } - } - return found; -} - -static void -hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) == 0) { - hose_read_config_byte(hose, bus, devfn, - PCI_HEADER_TYPE, &hdr_type); - } else if (!(hdr_type & 0x80)) { - /* not a multi-function device */ - continue; - } - - /* Check if there is anything here. */ - hose_read_config_dword(hose, bus, devfn, PCI_VENDOR_ID, &l); - if (l == 0xffffffff || l == 0x00000000) { - hdr_type = 0; - continue; - } - - /* See if this is a bridge device. */ - hose_read_config_dword(hose, bus, devfn, - PCI_CLASS_REVISION, &class); - - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - unsigned int busses; - - hose_read_config_dword(hose, bus, devfn, - PCI_PRIMARY_BUS, &busses); - - /* - * First reconfigure everything underneath the bridge. - */ - hose_reconfigure_bridges(hose, (busses >> 8) & 0xff); - - /* - * Unconfigure this bridges bus numbers, - * pci_scan_bus() will fix this up properly. - */ - busses &= 0xff000000; - hose_write_config_dword(hose, bus, devfn, - PCI_PRIMARY_BUS, busses); - } - } -} - -static void mcpcia_fixup_busno(struct linux_hose_info *hose, unsigned char bus) -{ - unsigned int nbus; - - /* - * First, scan for all bridge devices underneath this hose, - * to determine the first and last busnos. - */ - if (!hose_scan_bridges(hose, 0)) { - /* none found, exit */ - hose->pci_first_busno = bus; - hose->pci_last_busno = bus; - } else { - /* - * Reconfigure all bridge devices underneath this hose. - */ - hose_reconfigure_bridges(hose, hose->pci_first_busno); - } - - /* - * Now reconfigure the hose to it's new bus number and set up - * our bus2hose mapping for this hose. - */ - nbus = hose->pci_last_busno - hose->pci_first_busno; - - hose->pci_first_busno = bus; - -DBG_PCI(("mcpcia_fixup_busno: hose %d startbus %d nbus %d\n", - hose->pci_hose_index, bus, nbus)); - - do { - bus2hose[bus++] = hose; - } while (nbus-- > 0); -} - -static void mcpcia_probe(struct linux_hose_info *hose, - unsigned long *mem_start) -{ - static struct pci_bus *pchain = NULL; - struct pci_bus *pbus = &hose->pci_bus; - static unsigned char busno = 0; - - /* Hoses include child PCI bridges in bus-range property, - * but we don't scan each of those ourselves, Linux generic PCI - * probing code will find child bridges and link them into this - * hose's root PCI device hierarchy. - */ - - pbus->number = pbus->secondary = busno; - pbus->sysdata = hose; - - mcpcia_fixup_busno(hose, busno); - - pbus->subordinate = pci_scan_bus(pbus, mem_start); /* the original! */ - - /* - * Set the maximum subordinate bus of this hose. - */ - hose->pci_last_busno = pbus->subordinate; -#if 0 - hose_write_config_byte(hose, busno, 0, 0x41, hose->pci_last_busno); -#endif - busno = pbus->subordinate + 1; - - /* - * Fixup the chain of primary PCI busses. - */ - if (pchain) { - pchain->next = &hose->pci_bus; - pchain = pchain->next; - } else { - pchain = &pci_root; - memcpy(pchain, &hose->pci_bus, sizeof(pci_root)); - } -} - -void mcpcia_fixup(void) -{ - struct linux_hose_info *hose; - - /* turn on Config space access finally! */ - pci_probe_enabled = 1; - - /* for each hose, probe and setup the devices on the hose */ - for (hose = mcpcia_root; hose; hose = hose->next) { - mcpcia_probe(hose, &memory_start); - } -} -#endif /* CONFIG_ALPHA_MCPCIA */ diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index a63fb2be6..b3e919500 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -30,6 +30,7 @@ #include <linux/mman.h> #include <linux/shm.h> #include <linux/poll.h> +#include <linux/file.h> #include <asm/fpu.h> #include <asm/io.h> @@ -46,7 +47,7 @@ extern struct file_operations *get_chrfops(unsigned int); extern kdev_t get_unnamed_dev(void); extern void put_unnamed_dev(kdev_t); -extern asmlinkage int sys_umount(char *); +extern asmlinkage int sys_umount(char *, int); extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags); extern asmlinkage unsigned long sys_brk(unsigned long); @@ -137,13 +138,11 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, { int error; struct file *file; + struct inode *inode; struct osf_dirent_callback buf; error = -EBADF; - if (fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if (!file) goto out; @@ -154,17 +153,25 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_putf; + /* + * Get the inode's semaphore to prevent changes + * to the directory while we read it. + */ + inode = file->f_dentry->d_inode; + down(&inode->i_sem); error = file->f_op->readdir(file, &buf, osf_filldir); + up(&inode->i_sem); if (error < 0) - goto out; + goto out_putf; error = buf.error; - if (count == buf.count) - goto out; + if (count != buf.count) + error = count - buf.count; - error = count - buf.count; +out_putf: + fput(file); out: return error; } @@ -248,13 +255,17 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, lock_kernel(); if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) - printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags); + printk("%s: unimplemented OSF mmap flags %04lx\n", + current->comm, flags); if (!(flags & MAP_ANONYMOUS)) { - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ret = do_mmap(file, addr, len, prot, flags, off); + if (file) + fput(file); out: unlock_kernel(); return ret; @@ -340,11 +351,13 @@ asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned lock_kernel(); retval = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; dentry = file->f_dentry; if (dentry) retval = do_osf_statfs(dentry, buffer, bufsiz); + fput(file); out: unlock_kernel(); return retval; @@ -366,8 +379,8 @@ struct cdfs_args { int flags; uid_t exroot; /* - * this has lots more here, which linux handles with the option block - * but I'm too lazy to do the translation into ascii.. + * This has lots more here, which Linux handles with the option block + * but I'm too lazy to do the translation into ASCII. */ }; @@ -390,38 +403,41 @@ static int getdev(const char *name, int rdonly, struct dentry **dp) if (IS_ERR(dentry)) return retval; + retval = -ENOTBLK; inode = dentry->d_inode; - if (!S_ISBLK(inode->i_mode)) { - dput(dentry); - return -ENOTBLK; - } - if (IS_NODEV(inode)) { - dput(dentry); - return -EACCES; - } + if (!S_ISBLK(inode->i_mode)) + goto out_dput; + + retval = -EACCES; + if (IS_NODEV(inode)) + goto out_dput; + + retval = -ENXIO; dev = inode->i_rdev; - if (MAJOR(dev) >= MAX_BLKDEV) { - dput(dentry); - return -ENXIO; - } + if (MAJOR(dev) >= MAX_BLKDEV) + goto out_dput; + + retval = -ENODEV; fops = get_blkfops(MAJOR(dev)); - if (!fops) { - dput(dentry); - return -ENODEV; - } + if (!fops) + goto out_dput; if (fops->open) { struct file dummy; memset(&dummy, 0, sizeof(dummy)); dummy.f_dentry = dentry; dummy.f_mode = rdonly ? 1 : 3; retval = fops->open(inode, &dummy); - if (retval) { - dput(dentry); - return retval; - } + if (retval) + goto out_dput; } *dp = dentry; - return 0; + retval = 0; +out: + return retval; + +out_dput: + dput(dentry); + goto out; } static void putdev(struct dentry *dentry) @@ -435,8 +451,8 @@ static void putdev(struct dentry *dentry) /* * We can't actually handle ufs yet, so we translate UFS mounts to - * ext2fs mounts... I wouldn't mind a UFS filesystem, but the UFS - * layout is so braindead it's a major headache doing it.. + * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS + * layout is so braindead it's a major headache doing it. */ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags) { @@ -444,17 +460,19 @@ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags) struct dentry *dentry; struct cdfs_args tmp; - retval = verify_area(VERIFY_READ, args, sizeof(*args)); - if (retval) - return retval; - copy_from_user(&tmp, args, sizeof(tmp)); + retval = -EFAULT; + if (copy_from_user(&tmp, args, sizeof(tmp))) + goto out; + retval = getdev(tmp.devname, 0, &dentry); if (retval) - return retval; - retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL); + goto out; + retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, + "ext2", flags, NULL); if (retval) putdev(dentry); dput(dentry); +out: return retval; } @@ -464,17 +482,19 @@ static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags) struct dentry * dentry; struct cdfs_args tmp; - retval = verify_area(VERIFY_READ, args, sizeof(*args)); - if (retval) - return retval; - copy_from_user(&tmp, args, sizeof(tmp)); + retval = -EFAULT; + if (copy_from_user(&tmp, args, sizeof(tmp))) + goto out; + retval = getdev(tmp.devname, 1, &dentry); if (retval) - return retval; - retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL); + goto out; + retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, + "iso9660", flags, NULL); if (retval) putdev(dentry); dput(dentry); +out: return retval; } @@ -484,10 +504,8 @@ static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags) int retval; struct procfs_args tmp; - retval = verify_area(VERIFY_READ, args, sizeof(*args)); - if (retval) - return retval; - copy_from_user(&tmp, args, sizeof(tmp)); + if (copy_from_user(&tmp, args, sizeof(tmp))) + return -EFAULT; dev = get_unnamed_dev(); if (!dev) return -ENODEV; @@ -524,7 +542,7 @@ asmlinkage int osf_umount(char *path, int flag) int ret; lock_kernel(); - ret = sys_umount(path); + ret = sys_umount(path,flag); unlock_kernel(); return ret; } @@ -533,17 +551,22 @@ asmlinkage int osf_utsname(char *name) { int error; - lock_kernel(); - error = verify_area(VERIFY_WRITE, name, 5 * 32); - if (error) + down(&uts_sem); + error = -EFAULT; + if (copy_to_user(name + 0, system_utsname.sysname, 32)) + goto out; + if (copy_to_user(name + 32, system_utsname.nodename, 32)) goto out; - copy_to_user(name + 0, system_utsname.sysname, 32); - copy_to_user(name + 32, system_utsname.nodename, 32); - copy_to_user(name + 64, system_utsname.release, 32); - copy_to_user(name + 96, system_utsname.version, 32); - copy_to_user(name + 128, system_utsname.machine, 32); + if (copy_to_user(name + 64, system_utsname.release, 32)) + goto out; + if (copy_to_user(name + 96, system_utsname.version, 32)) + goto out; + if (copy_to_user(name + 128, system_utsname.machine, 32)) + goto out; + + error = 0; out: - unlock_kernel(); + up(&uts_sem); return error; } @@ -602,11 +625,13 @@ asmlinkage int osf_getdomainname(char *name, int namelen) if (namelen > 32) len = 32; + down(&uts_sem); for (i = 0; i < len; ++i) { - put_user(system_utsname.domainname[i], name + i); + __put_user(system_utsname.domainname[i], name + i); if (system_utsname.domainname[i] == '\0') break; } + up(&uts_sem); out: unlock_kernel(); return error; @@ -743,6 +768,50 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args) return error; } +asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss) +{ + unsigned long usp = rdusp(); + unsigned long oss_sp, oss_os; + int error; + + if (uoss) { + oss_sp = current->sas_ss_sp + current->sas_ss_size; + oss_os = on_sig_stack(usp); + } + + if (uss) { + void *ss_sp; + + error = -EFAULT; + if (get_user(ss_sp, &uss->ss_sp)) + goto out; + + /* If the current stack was set with sigaltstack, don't + swap stacks while we are on it. */ + error = -EPERM; + if (current->sas_ss_sp && on_sig_stack(usp)) + goto out; + + /* Since we don't know the extent of the stack, and we don't + track onstack-ness, but rather calculate it, we must + presume a size. Ho hum this interface is lossy. */ + current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; + current->sas_ss_size = SIGSTKSZ; + } + + if (uoss) { + error = -EFAULT; + if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)) + || __put_user(oss_sp, &uoss->ss_sp) + || __put_user(oss_os, &uoss->ss_onstack)) + goto out; + } + + error = 0; +out: + return error; +} + /* * The Linux kernel isn't good at returning values that look * like negative longs (they are mistaken as error values). @@ -795,10 +864,12 @@ asmlinkage long osf_sysinfo(int command, char *buf, long count) lock_kernel(); offset = command-1; if (offset >= sizeof(sysinfo_table)/sizeof(char *)) { - /* Digital unix has a few unpublished interfaces here */ + /* Digital UNIX has a few unpublished interfaces here */ printk("sysinfo(%d)", command); goto out; } + + down(&uts_sem); res = sysinfo_table[offset]; len = strlen(res)+1; if (len > count) @@ -807,6 +878,7 @@ asmlinkage long osf_sysinfo(int command, char *buf, long count) err = -EFAULT; else err = 0; + up(&uts_sem); out: unlock_kernel(); return err; diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 401a7af46..697572e7a 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -5,7 +5,7 @@ */ /* - * This file handles the architecture-dependent parts of process handling.. + * This file handles the architecture-dependent parts of process handling. */ #include <linux/config.h> @@ -28,6 +28,7 @@ #include <linux/mman.h> #include <linux/elfcore.h> #include <linux/reboot.h> +#include <linux/console.h> #ifdef CONFIG_RTC #include <linux/mc146818rtc.h> @@ -41,6 +42,9 @@ #include <asm/hwrpb.h> #include <asm/fpu.h> +#include "proto.h" +#include "bios32.h" + /* * Initial task structure. Make this a per-architecture thing, * because different architectures tend to have different @@ -62,34 +66,26 @@ union task_union init_task_union __attribute__((section("init_task"))) /* * No need to acquire the kernel lock, we're entirely local.. */ -asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage int +sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { -#if !defined(CONFIG_ALPHA_TSUNAMI) (®s)->hae = hae; -#endif return 0; } #ifdef __SMP__ /* This is being executed in task 0 'user space'. */ #define resched_needed() 1 -int cpu_idle(void *unused) +int +cpu_idle(void *unused) { extern volatile int smp_commenced; current->priority = -100; while (1) { - /* - * tq_scheduler currently assumes we're running in a process - * context (ie that we hold the kernel lock..) - */ - if (tq_scheduler) { - lock_kernel(); - run_task_queue(&tq_scheduler); - unlock_kernel(); - } + run_task_queue(&tq_scheduler); /* endless idle loop with no priority at all */ current->counter = -100; if (!smp_commenced || resched_needed()) { @@ -98,7 +94,8 @@ int cpu_idle(void *unused) } } -asmlinkage int sys_idle(void) +asmlinkage int +sys_idle(void) { if(current->pid != 0) return -EPERM; @@ -109,7 +106,8 @@ asmlinkage int sys_idle(void) #else /* __SMP__ */ -asmlinkage int sys_idle(void) +asmlinkage int +sys_idle(void) { int ret = -EPERM; @@ -120,6 +118,7 @@ asmlinkage int sys_idle(void) /* endless idle loop with no priority at all */ current->counter = -100; for (;;) { + check_pgt_cache(); schedule(); } ret = 0; @@ -129,90 +128,101 @@ out: } #endif /* __SMP__ */ -#if defined(CONFIG_ALPHA_SRM_SETUP) -extern void reset_for_srm(void); -extern unsigned long srm_hae; -#endif - -static void finish_shutdown(void) +void +generic_kill_arch (int mode, char *restart_cmd) { -#ifdef CONFIG_RTC /* reset rtc to defaults */ - unsigned char control; - unsigned long flags; - - /* i'm not sure if i really need to disable interrupts here */ - save_and_cli(flags); - - /* reset periodic interrupt frequency */ - CMOS_WRITE(0x26, RTC_FREQ_SELECT); - - /* turn on periodic interrupts */ - control = CMOS_READ(RTC_CONTROL); - control |= RTC_PIE; - CMOS_WRITE(control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + /* The following currently only has any effect on SRM. We should + fix MILO to understand it. Should be pretty easy. Also we can + support RESTART2 via the ipc_buffer machinations pictured below, + which SRM ignores. */ + + if (alpha_using_srm) { + struct percpu_struct *cpup; + unsigned long flags; + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset); + + flags = cpup->flags; + + /* Clear reason to "default"; clear "bootstrap in progress". */ + flags &= ~0x00ff0001UL; + + if (mode == LINUX_REBOOT_CMD_RESTART) { + if (!restart_cmd) { + flags |= 0x00020000UL; /* "cold bootstrap" */ + cpup->ipc_buffer[0] = 0; + } else { + flags |= 0x00030000UL; /* "warm bootstrap" */ + strncpy(cpup->ipc_buffer, restart_cmd, + sizeof(cpup->ipc_buffer)); + } + } + else { + flags |= 0x00040000UL; /* "remain halted" */ + } + + cpup->flags = flags; + mb(); + + if (alpha_use_srm_setup) { + reset_for_srm(); + set_hae(srm_hae); + } + +#ifdef CONFIG_DUMMY_CONSOLE + /* This has the effect of reseting the VGA video origin. */ + take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif -#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR) - /* who said DEC engineer's have no sense of humor? ;-)) */ - *(int *) GRU_RESET = 0x0000dead; - mb(); + } + +#ifdef CONFIG_RTC + /* Reset rtc to defaults. */ + { + unsigned char control; + unsigned long flags; + + /* I'm not sure if i really need to disable interrupts here. */ + save_and_cli(flags); + + /* Reset periodic interrupt frequency. */ + CMOS_WRITE(0x26, RTC_FREQ_SELECT); + + /* Turn on periodic interrupts. */ + control = CMOS_READ(RTC_CONTROL); + control |= RTC_PIE; + CMOS_WRITE(control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + + restore_flags(flags); + } #endif + + if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) { + /* Unfortunately, since MILO doesn't currently understand + the hwrpb bits above, we can't reliably halt the + processor and keep it halted. So just loop. */ + return; + } + halt(); } -void machine_restart(char * __unused) +void +machine_restart(char *restart_cmd) { -#if defined(CONFIG_ALPHA_SRM) - extern struct hwrpb_struct *hwrpb; - struct percpu_struct *cpup; - unsigned long flags; - - cpup = (struct percpu_struct *) - ((unsigned long)hwrpb + hwrpb->processor_offset); - flags = cpup->flags; - flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */ - flags |= 0x0000000000020000UL; /* this is "cold bootstrap" */ -/* flags |= 0x0000000000030000UL; *//* this is "warm bootstrap" */ - cpup->flags = flags; - mb(); -#if defined(CONFIG_ALPHA_SRM_SETUP) - reset_for_srm(); - set_hae(srm_hae); -#endif -#endif /* SRM */ - - finish_shutdown(); + alpha_mv.kill_arch(LINUX_REBOOT_CMD_RESTART, restart_cmd); } -void machine_halt(void) +void +machine_halt(void) { -#if defined(CONFIG_ALPHA_SRM) - extern struct hwrpb_struct *hwrpb; - struct percpu_struct *cpup; - unsigned long flags; - - cpup = (struct percpu_struct *) - ((unsigned long)hwrpb + hwrpb->processor_offset); - flags = cpup->flags; - flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */ - flags |= 0x0000000000040000UL; /* this is "remain halted" */ - cpup->flags = flags; - mb(); -#if defined(CONFIG_ALPHA_SRM_SETUP) - reset_for_srm(); - set_hae(srm_hae); -#endif - - finish_shutdown(); -#endif /* SRM */ + alpha_mv.kill_arch(LINUX_REBOOT_CMD_HALT, NULL); } void machine_power_off(void) { - /* None of the machines we support, at least, has switchable - power supplies. */ - machine_halt(); + alpha_mv.kill_arch(LINUX_REBOOT_CMD_POWER_OFF, NULL); } void show_regs(struct pt_regs * regs) @@ -254,7 +264,7 @@ void exit_thread(void) void flush_thread(void) { /* Arrange for each exec'ed process to start off with a - clean slate wrt the fpu. */ + clean slate with respect to the FPU. */ current->tss.flags &= ~IEEE_SW_MASK; wrfpcr(FPCR_DYN_NORMAL); } diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h new file mode 100644 index 000000000..f55a0edba --- /dev/null +++ b/arch/alpha/kernel/proto.h @@ -0,0 +1,131 @@ +/* Prototypes of functions used across modules here in this directory. */ + +#define vucp volatile unsigned char * +#define vusp volatile unsigned short * +#define vip volatile int * +#define vuip volatile unsigned int * +#define vulp volatile unsigned long * + +/* core_apecs.c */ +extern int apecs_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int apecs_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int apecs_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int apecs_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int apecs_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int apecs_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void apecs_init_arch(unsigned long *, unsigned long *); + +extern volatile unsigned int apecs_mcheck_expected; +extern volatile unsigned int apecs_mcheck_taken; +extern int apecs_pci_clr_err(void); +extern void apecs_machine_check(u64, u64, struct pt_regs *); + +/* core_cia.c */ +extern int cia_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int cia_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int cia_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int cia_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int cia_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int cia_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void cia_init_arch(unsigned long *, unsigned long *); +extern void cia_machine_check(u64, u64, struct pt_regs *); + +/* core_lca.c */ +extern int lca_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int lca_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int lca_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int lca_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int lca_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int lca_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void lca_init_arch(unsigned long *, unsigned long *); +extern void lca_machine_check(u64, u64, struct pt_regs *); + +/* core_mcpcia.c */ +extern int mcpcia_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int mcpcia_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int mcpcia_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int mcpcia_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int mcpcia_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int mcpcia_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void mcpcia_init_arch(unsigned long *, unsigned long *); +extern void mcpcia_machine_check(u64, u64, struct pt_regs *); +extern void mcpcia_pci_fixup(void); + +/* core_pyxis.c */ +extern int pyxis_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int pyxis_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int pyxis_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int pyxis_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int pyxis_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int pyxis_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void pyxis_enable_errors (void); +extern int pyxis_srm_window_setup (void); +extern void pyxis_native_window_setup(void); +extern void pyxis_finish_init_arch(void); +extern void pyxis_init_arch(unsigned long *, unsigned long *); +extern void pyxis_machine_check(u64, u64, struct pt_regs *); + +/* core_t2.c */ +extern int t2_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int t2_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int t2_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int t2_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int t2_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int t2_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void t2_init_arch(unsigned long *, unsigned long *); +extern void t2_machine_check(u64, u64, struct pt_regs *); + +/* core_tsunami.c */ +extern int tsunami_pcibios_read_config_byte (u8, u8, u8, u8 *value); +extern int tsunami_pcibios_read_config_word (u8, u8, u8, u16 *value); +extern int tsunami_pcibios_read_config_dword (u8, u8, u8, u32 *value); +extern int tsunami_pcibios_write_config_byte (u8, u8, u8, u8 value); +extern int tsunami_pcibios_write_config_word (u8, u8, u8, u16 value); +extern int tsunami_pcibios_write_config_dword (u8, u8, u8, u32 value); +extern void tsunami_init_arch(unsigned long *, unsigned long *); +extern void tsunami_machine_check(u64, u64, struct pt_regs *); + +/* setup.c */ +extern void init_pit_rest(void); +extern void generic_init_pit (void); +extern unsigned long srm_hae; + +/* smp.c */ +extern void setup_smp(void); +extern char *smp_info(void); +extern void handle_ipi(struct pt_regs *); + +/* bios32.c */ +extern void reset_for_srm(void); + +/* time.c */ +extern void timer_interrupt(struct pt_regs * regs); + +/* smc37c93x.c */ +extern void SMC93x_Init(void); + +/* smc37c669.c */ +extern void SMC669_Init(void); + +/* es1888.c */ +extern void es1888_init(void); + +/* fpregs.c */ +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); +extern unsigned long alpha_read_fp_reg (unsigned long reg); + +/* head.S */ +extern void wrmces(unsigned long mces); +extern void cserve_ena(unsigned long); +extern void cserve_dis(unsigned long); + +/* entry.S */ +extern void entArith(void); +extern void entIF(void); +extern void entInt(void); +extern void entMM(void); +extern void entSys(void); +extern void entUna(void); + +/* process.c */ +void generic_kill_arch (int mode, char *reboot_cmd); diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index c8b31623d..384f534af 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -13,7 +13,6 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> -#include <linux/debugreg.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -23,13 +22,13 @@ #ifdef DEBUG - enum { - DBG_MEM = (1<<0), - DBG_BPT = (1<<1), - DBG_MEM_ALL = (1<<2) - }; +enum { + DBG_MEM = (1<<0), + DBG_BPT = (1<<1), + DBG_MEM_ALL = (1<<2) +}; - int debug_mask = DBG_BPT; +int debug_mask = DBG_BPT; # define DBG(fac,args) {if ((fac) & debug_mask) printk args;} @@ -150,7 +149,7 @@ static inline int put_reg(struct task_struct *task, long regno, long data) * no checking. */ static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) + struct vm_area_struct * vma, unsigned long addr) { pgd_t * pgdir; pmd_t * pgmiddle; @@ -158,7 +157,7 @@ static unsigned long get_long(struct task_struct * tsk, unsigned long page; DBG(DBG_MEM_ALL, ("getting long at 0x%lx\n", addr)); -repeat: + repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { handle_mm_fault(tsk, vma, addr, 0); @@ -185,7 +184,7 @@ repeat: goto repeat; } page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ + /* this is a hack for non-kernel-mapped video buffers and similar */ if (MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; @@ -202,14 +201,14 @@ repeat: * even if a debugger scribbles breakpoints into it. -M.U- */ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned long data) + unsigned long addr, unsigned long data) { pgd_t *pgdir; pmd_t *pgmiddle; pte_t *pgtable; unsigned long page; -repeat: + repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { handle_mm_fault(tsk, vma, addr, 1); @@ -240,11 +239,14 @@ repeat: handle_mm_fault(tsk, vma, addr, 1); goto repeat; } -/* this is a hack for non-kernel-mapped video buffers and similar */ + + /* This is a hack for non-kernel-mapped video buffers and similar. */ if (MAP_NR(page) < max_mapnr) *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ + + /* We're bypassing pagetables, so we have to set the dirty bit + ourselves. This should also re-instate whatever read-only + mode there was before. */ set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); flush_tlb(); } @@ -279,10 +281,8 @@ static int read_long(struct task_struct * tsk, unsigned long addr, struct vm_area_struct * vma = find_extend_vma(tsk, addr); DBG(DBG_MEM_ALL, ("in read_long\n")); - if (!vma) { - printk("Unable to find vma for addr 0x%lx\n",addr); + if (!vma) return -EIO; - } if ((addr & ~PAGE_MASK) > (PAGE_SIZE - sizeof(long))) { struct vm_area_struct * vma_high = vma; unsigned long low, align; @@ -296,11 +296,11 @@ static int read_long(struct task_struct * tsk, unsigned long addr, addr -= align; low = get_long(tsk, vma, addr); if (align) { - unsigned long high; + unsigned long high; - high = get_long(tsk, vma_high, addr + sizeof(long)); - low >>= align * 8; - low |= high << (64 - align * 8); + high = get_long(tsk, vma_high, addr + sizeof(long)); + low >>= align * 8; + low |= high << (64 - align * 8); } *result = low; } else { @@ -317,7 +317,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr, * within the task area. It then calls put_long() to write a long. */ static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) + unsigned long data) { struct vm_area_struct * vma = find_extend_vma(tsk, addr); @@ -361,7 +361,7 @@ static int read_int(struct task_struct * tsk, unsigned long addr, res = read_long(tsk, addr, &l); if (res < 0) - return res; + return res; if (align == 0) { *data = l; @@ -388,7 +388,7 @@ static int write_int(struct task_struct * tsk, unsigned long addr, res = read_long(tsk, addr, &l); if (res < 0) - return res; + return res; if (align == 0) { l = (l & 0xffffffff00000000UL) | ((unsigned long) data << 0); @@ -410,7 +410,7 @@ int ptrace_set_bpt(struct task_struct * child) pc = get_reg(child, REG_PC); res = read_int(child, pc, &insn); if (res < 0) - return res; + return res; op_code = insn >> 26; if (op_code >= 0x30) { @@ -423,31 +423,31 @@ int ptrace_set_bpt(struct task_struct * child) * branch (emulation can be tricky for fp branches). */ displ = ((s32)(insn << 11)) >> 9; - child->debugreg[nsaved++] = pc + 4; + child->tss.debugreg[nsaved++] = pc + 4; if (displ) /* guard against unoptimized code */ - child->debugreg[nsaved++] = pc + 4 + displ; + child->tss.debugreg[nsaved++] = pc + 4 + displ; DBG(DBG_BPT, ("execing branch\n")); } else if (op_code == 0x1a) { reg_b = (insn >> 16) & 0x1f; - child->debugreg[nsaved++] = get_reg(child, reg_b); + child->tss.debugreg[nsaved++] = get_reg(child, reg_b); DBG(DBG_BPT, ("execing jump\n")); } else { - child->debugreg[nsaved++] = pc + 4; + child->tss.debugreg[nsaved++] = pc + 4; DBG(DBG_BPT, ("execing normal insn\n")); } /* install breakpoints: */ for (i = 0; i < nsaved; ++i) { - res = read_int(child, child->debugreg[i], &insn); + res = read_int(child, child->tss.debugreg[i], &insn); if (res < 0) - return res; - child->debugreg[i + 2] = insn; - DBG(DBG_BPT, (" -> next_pc=%lx\n", child->debugreg[i])); - res = write_int(child, child->debugreg[i], BREAKINST); + return res; + child->tss.debugreg[i + 2] = insn; + DBG(DBG_BPT, (" -> next_pc=%lx\n", child->tss.debugreg[i])); + res = write_int(child, child->tss.debugreg[i], BREAKINST); if (res < 0) - return res; + return res; } - child->debugreg[4] = nsaved; + child->tss.debugreg[4] = nsaved; return 0; } @@ -457,17 +457,18 @@ int ptrace_set_bpt(struct task_struct * child) */ int ptrace_cancel_bpt(struct task_struct * child) { - int i, nsaved = child->debugreg[4]; + int i, nsaved = child->tss.debugreg[4]; - child->debugreg[4] = 0; + child->tss.debugreg[4] = 0; if (nsaved > 2) { - printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); - nsaved = 2; + printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + nsaved = 2; } for (i = 0; i < nsaved; ++i) { - write_int(child, child->debugreg[i], child->debugreg[i + 2]); + write_int(child, child->tss.debugreg[i], + child->tss.debugreg[i + 2]); } return (nsaved != 0); } @@ -506,7 +507,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + (current->gid != child->gid)) + && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) @@ -537,107 +539,107 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, } switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - - ret = read_long(child, addr, &tmp); - DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); - if (ret < 0) - goto out; - regs.r0 = 0; /* special return: no errors */ - ret = tmp; + /* When I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + + ret = read_long(child, addr, &tmp); + DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); + if (ret < 0) goto out; - } + regs.r0 = 0; /* special return: no errors */ + ret = tmp; + goto out; + } /* read register number ADDR. */ - case PTRACE_PEEKUSR: - regs.r0 = 0; /* special return: no errors */ - DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0)); - ret = get_reg(child, addr); - goto out; + case PTRACE_PEEKUSR: + regs.r0 = 0; /* special return: no errors */ + DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0)); + ret = get_reg(child, addr); + goto out; - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data)); - ret = write_long(child, addr, data); - goto out; + /* When I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data)); + ret = write_long(child, addr, data); + goto out; - case PTRACE_POKEUSR: /* write the specified register */ - DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data)); - ret = put_reg(child, addr, data); - goto out; + case PTRACE_POKEUSR: /* write the specified register */ + DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data)); + ret = put_reg(child, addr, data); + goto out; - case PTRACE_SYSCALL: /* continue and stop at next - (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; - else - child->flags &= ~PF_TRACESYS; - child->exit_code = data; - wake_up_process(child); - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt(child); - ret = data; + case PTRACE_SYSCALL: /* continue and stop at next + (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) goto out; - } + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + wake_up_process(child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt(child); + ret = data; + goto out; + } -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - if (child->state != TASK_ZOMBIE) { - wake_up_process(child); - child->exit_code = SIGKILL; - } - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt(child); - ret = 0; - goto out; + /* + * Make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + if (child->state != TASK_ZOMBIE) { + wake_up_process(child); + child->exit_code = SIGKILL; } + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt(child); + ret = 0; + goto out; + } - case PTRACE_SINGLESTEP: { /* execute single instruction. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->debugreg[4] = -1; /* mark single-stepping */ - child->flags &= ~PF_TRACESYS; - wake_up_process(child); - child->exit_code = data; - /* give it a chance to run. */ - ret = 0; + case PTRACE_SINGLESTEP: { /* execute single instruction. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) goto out; - } + child->tss.debugreg[4] = -1; /* mark single-stepping */ + child->flags &= ~PF_TRACESYS; + wake_up_process(child); + child->exit_code = data; + /* give it a chance to run. */ + ret = 0; + goto out; + } - case PTRACE_DETACH: { /* detach a process that was attached. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process(child); - child->exit_code = data; - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt(child); - ret = 0; + case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) goto out; - } + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + wake_up_process(child); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt(child); + ret = 0; + goto out; + } - default: - ret = -EIO; - goto out; - } -out: + default: + ret = -EIO; + goto out; + } + out: unlock_kernel(); return ret; } @@ -645,7 +647,7 @@ out: asmlinkage void syscall_trace(void) { if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff --git a/arch/alpha/kernel/pyxis.c b/arch/alpha/kernel/pyxis.c deleted file mode 100644 index de3814b66..000000000 --- a/arch/alpha/kernel/pyxis.c +++ /dev/null @@ -1,663 +0,0 @@ -/* - * Code common to all PYXIS chips. - * - * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). - * - */ -#include <linux/config.h> /* CONFIG_ALPHA_RUFFIAN. */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/sched.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/hwrpb.h> -#include <asm/ptrace.h> -#include <asm/mmu_context.h> - -/* NOTE: Herein are back-to-back mb instructions. They are magic. - One plausible explanation is that the I/O controller does not properly - handle the system transaction. Another involves timing. Ho hum. */ - -extern struct hwrpb_struct *hwrpb; -extern asmlinkage void wrmces(unsigned long mces); - -/* - * BIOS32-style PCI interface: - */ - -#ifdef DEBUG -# define DBG(args) printk args -#else -# define DBG(args) -#endif - -#define DEBUG_MCHECK -#ifdef DEBUG_MCHECK -# define DBG_MCK(args) printk args -#define DEBUG_MCHECK_DUMP -#else -# define DBG_MCK(args) -#endif - -#define vulp volatile unsigned long * -#define vuip volatile unsigned int * - -static volatile unsigned int PYXIS_mcheck_expected = 0; -static volatile unsigned int PYXIS_mcheck_taken = 0; -static unsigned int PYXIS_jd; - -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT; -unsigned int PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT; -unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3; -#endif /* SRM_SETUP */ - -/* - * Given a bus, device, and function number, compute resulting - * configuration space address and setup the PYXIS_HAXR2 register - * accordingly. It is therefore not safe to have concurrent - * invocations to configuration space access routines, but there - * really shouldn't be any need for this. - * - * Type 0: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:11 Device select bit. - * 10:8 Function number - * 7:2 Register number - * - * Type 1: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:24 reserved - * 23:16 bus number (8 bits = 128 possible buses) - * 15:11 Device number (5 bits) - * 10:8 function number - * 7:2 register number - * - * Notes: - * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). - * - * The register selects a DWORD (32 bit) register offset. Hence it - * doesn't get shifted by 2 bits as we want to "drop" the bottom two - * bits. - */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) -{ - unsigned long addr; - - DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," - " pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); - - if (bus == 0) { - int device; - - device = device_fn >> 3; - /* type 0 configuration cycle: */ -#if NOT_NOW - if (device > 20) { - DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", - device)); - return -1; - } -#endif - *type1 = 0; - addr = (device_fn << 8) | (where); - } else { - /* type 1 configuration cycle: */ - *type1 = 1; - addr = (bus << 16) | (device_fn << 8) | (where); - } - *pci_addr = addr; - DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); - return 0; -} - - -static unsigned int conf_read(unsigned long addr, unsigned char type1) -{ - unsigned long flags; - unsigned int stat0, value, temp; - unsigned int pyxis_cfg = 0; /* to keep gcc quiet */ - - save_and_cli(flags); /* avoid getting hit by machine check */ - - DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); - - /* reset status register to avoid losing errors: */ - stat0 = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = stat0; mb(); - temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0)); - /* if Type1 access, must set PYXIS CFG */ - if (type1) { - pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - DBG(("conf_read: TYPE1 access\n")); - } - - mb(); - draina(); - PYXIS_mcheck_expected = 1; - PYXIS_mcheck_taken = 0; - mb(); - /* access configuration space: */ - value = *(vuip)addr; - mb(); - mb(); /* magic */ - if (PYXIS_mcheck_taken) { - PYXIS_mcheck_taken = 0; - value = 0xffffffffU; - mb(); - } - PYXIS_mcheck_expected = 0; - mb(); - - /* if Type1 access, must reset IOC CFG so normal IO space ops work */ - if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - DBG(("conf_read(): finished\n")); - - restore_flags(flags); - return value; -} - - -static void conf_write(unsigned long addr, unsigned int value, - unsigned char type1) -{ - unsigned long flags; - unsigned int stat0, temp; - unsigned int pyxis_cfg = 0; /* to keep gcc quiet */ - - save_and_cli(flags); /* avoid getting hit by machine check */ - - /* reset status register to avoid losing errors: */ - stat0 = *(vuip)PYXIS_ERR; - *(vuip)PYXIS_ERR = stat0; mb(); - temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0)); - /* if Type1 access, must set PYXIS CFG */ - if (type1) { - pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - DBG(("conf_read: TYPE1 access\n")); - } - - draina(); - PYXIS_mcheck_expected = 1; - mb(); - /* access configuration space: */ - *(vuip)addr = value; - mb(); - mb(); /* magic */ - temp = *(vuip)PYXIS_ERR; /* do a PYXIS read to force the write */ - PYXIS_mcheck_expected = 0; - mb(); - - /* if Type1 access, must reset IOC CFG so normal IO space ops work */ - if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - - DBG(("conf_write(): finished\n")); - restore_flags(flags); -} - - -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - *value = 0xff; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= (pci_addr << 5) + 0x00; - - *value = conf_read(addr, type1) >> ((where & 3) * 8); - - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - *value = 0xffff; - - if (where & 0x1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - - addr |= (pci_addr << 5) + 0x08; - - *value = conf_read(addr, type1) >> ((where & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - *value = 0xffffffff; - if (where & 0x3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - addr |= (pci_addr << 5) + 0x18; - *value = conf_read(addr, type1); - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - addr |= (pci_addr << 5) + 0x00; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - addr |= (pci_addr << 5) + 0x08; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) -{ - unsigned long addr = PYXIS_CONF; - unsigned long pci_addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - addr |= (pci_addr << 5) + 0x18; - conf_write(addr, value << ((where & 3) * 8), type1); - return PCIBIOS_SUCCESSFUL; -} - - -unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end) -{ - unsigned int pyxis_err ; - -#if 0 -printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK); -printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR); - -printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ); -printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK); -printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE); -printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO); -printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG); -printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT); -#endif - - /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. - */ - pyxis_err = *(vuip)PYXIS_ERR_MASK; - pyxis_err &= ~4; - *(vuip)PYXIS_ERR_MASK = pyxis_err; mb(); - pyxis_err = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ - - pyxis_err = *(vuip)PYXIS_ERR ; - pyxis_err |= 0x180; /* master/target abort */ - *(vuip)PYXIS_ERR = pyxis_err; mb(); - pyxis_err = *(vuip)PYXIS_ERR; /* re-read to force write */ - -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 0 for enabled and mapped to 0 */ - if (((*(vuip)PYXIS_W0_BASE & 3) == 1) && - (*(vuip)PYXIS_T0_BASE == 0) && - ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U)) - { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 0 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W0_BASE, - *(vuip)PYXIS_W0_MASK, - *(vuip)PYXIS_T0_BASE); -#endif - } - else /* check window 1 for enabled and mapped to 0 */ - if (((*(vuip)PYXIS_W1_BASE & 3) == 1) && - (*(vuip)PYXIS_T1_BASE == 0) && - ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U)) -{ - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 1 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W1_BASE, - *(vuip)PYXIS_W1_MASK, - *(vuip)PYXIS_T1_BASE); -#endif - } - else /* check window 2 for enabled and mapped to 0 */ - if (((*(vuip)PYXIS_W2_BASE & 3) == 1) && - (*(vuip)PYXIS_T2_BASE == 0) && - ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U)) - { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 2 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W2_BASE, - *(vuip)PYXIS_W2_MASK, - *(vuip)PYXIS_T2_BASE); -#endif - } - else /* check window 3 for enabled and mapped to 0 */ - if (((*(vuip)PYXIS_W3_BASE & 3) == 1) && - (*(vuip)PYXIS_T3_BASE == 0) && - ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U)) - { - PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U; - PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U; - PYXIS_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("pyxis_init: using Window 3 settings\n"); - printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vuip)PYXIS_W3_BASE, - *(vuip)PYXIS_W3_MASK, - *(vuip)PYXIS_T3_BASE); -#endif - } - else /* we must use our defaults which were pre-initialized... */ -#endif /* SRM_SETUP */ - { -#if defined(CONFIG_ALPHA_RUFFIAN) -#if 1 - printk("pyxis_init: skipping window register rewrites... " - " trust DeskStation firmware!\n"); -#endif -#else /* RUFFIAN */ - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, we may - * want to use them to do scatter/gather DMA. Window 0 - * goes at 1 GB and is 1 GB large. - */ - - *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE & 0xfff00000U); - *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE - 1) & 0xfff00000U; - *(vuip)PYXIS_T0_BASE = 0; - - *(vuip)PYXIS_W1_BASE = 0x0 ; - *(vuip)PYXIS_W2_BASE = 0x0 ; - *(vuip)PYXIS_W3_BASE = 0x0 ; - mb(); -#endif /* RUFFIAN */ - } - - /* - * check ASN in HWRPB for validity, report if bad - */ - if (hwrpb->max_asn != MAX_ASN) { - printk("PYXIS_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); - hwrpb->max_asn = MAX_ASN; - } - - /* - * Next, clear the PYXIS_CFG register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... - */ - { - unsigned int pyxis_cfg, temp; - pyxis_cfg = *(vuip)PYXIS_CFG; mb(); - if (pyxis_cfg != 0) { -#if 1 - printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg); -#endif - *(vuip)PYXIS_CFG = 0; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } - } - - { - unsigned int pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; - unsigned int pyxis_hae_io = *(vuip)PYXIS_HAE_IO; -#if 0 - printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem); - printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io); -#endif -#ifdef CONFIG_ALPHA_SRM_SETUP - /* - * sigh... For the SRM setup, unless we know apriori what the HAE - * contents will be, we need to setup the arbitrary region bases - * so we can test against the range of addresses and tailor the - * region chosen for the SPARSE memory access. - * - * see include/asm-alpha/pyxis.h for the SPARSE mem read/write - */ - pyxis_sm_base_r1 = (pyxis_hae_mem ) & 0xe0000000UL;/* region 1 */ - pyxis_sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL;/* region 2 */ - pyxis_sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL;/* region 3 */ - - /* - Set the HAE cache, so that setup_arch() code - will use the SRM setting always. Our readb/writeb - code in pyxis.h expects never to have to change - the contents of the HAE. - */ - hae.cache = pyxis_hae_mem; -#else /* SRM_SETUP */ - *(vuip)PYXIS_HAE_MEM = 0U; mb(); - pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ - *(vuip)PYXIS_HAE_IO = 0; mb(); - pyxis_hae_io = *(vuip)PYXIS_HAE_IO; /* re-read to force write */ -#endif /* SRM_SETUP */ - } - - /* - * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for - * enabling byte/word PCI bus space(s) access. - */ - { - unsigned int ctrl1; - ctrl1 = *(vuip) PYXIS_CTRL1; - if (!(ctrl1 & 1)) { -#if 1 - printk("PYXIS_init: enabling byte/word PCI space\n"); -#endif - *(vuip) PYXIS_CTRL1 = ctrl1 | 1; mb(); - ctrl1 = *(vuip)PYXIS_CTRL1; /* re-read to force write */ - } - } - - return mem_start; -} - -int pyxis_pci_clr_err(void) -{ - PYXIS_jd = *(vuip)PYXIS_ERR; - DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd)); - *(vuip)PYXIS_ERR = 0x0180; mb(); - PYXIS_jd = *(vuip)PYXIS_ERR; /* re-read to force write */ - return 0; -} - -void pyxis_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) -{ - struct el_common *mchk_header; - struct el_PYXIS_sysdata_mcheck *mchk_sysdata; - - mchk_header = (struct el_common *)la_ptr; - - mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *) - (la_ptr + mchk_header->sys_offset); - -#if 0 - DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr, - mchk_sysdata->epic_pear)); -#endif -#ifdef DEBUG_MCHECK_DUMP - { - unsigned long *ptr; - int i; - - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); - } - } -#endif /* DEBUG_MCHECK_DUMP */ - - /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. - */ - mb(); - mb(); /* magic */ - if (PYXIS_mcheck_expected) { - DBG(("PYXIS machine check expected\n")); - PYXIS_mcheck_expected = 0; - PYXIS_mcheck_taken = 1; - mb(); - mb(); /* magic */ - draina(); - pyxis_pci_clr_err(); - wrmces(0x7); - mb(); - } -#if 1 - else { - printk("PYXIS machine check NOT expected\n") ; - DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x" - " sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - PYXIS_mcheck_expected = 0; - PYXIS_mcheck_taken = 1; - mb(); - mb(); /* magic */ - draina(); - pyxis_pci_clr_err(); - wrmces(0x7); - mb(); - } -#endif -} - -#if defined(CONFIG_ALPHA_RUFFIAN) -/* Note: This is only used by MILO, AFAIK... */ -/* - * The DeskStation Ruffian motherboard firmware does not place - * the memory size in the PALimpure area. Therefore, we use - * the Bank Configuration Registers in PYXIS to obtain the size. - */ -unsigned long pyxis_get_bank_size(unsigned long offset) -{ - unsigned long bank_addr, bank, ret = 0; - - /* Valid offsets are: 0x800, 0x840 and 0x880 - since Ruffian only uses three banks. */ - bank_addr = (unsigned long)PYXIS_MCR + offset; - bank = *(vulp)bank_addr; - - /* Check BANK_ENABLE */ - if (bank & 0x01) { - static unsigned long size[] = { - 0x40000000UL, /* 0x00, 1G */ - 0x20000000UL, /* 0x02, 512M */ - 0x10000000UL, /* 0x04, 256M */ - 0x08000000UL, /* 0x06, 128M */ - 0x04000000UL, /* 0x08, 64M */ - 0x02000000UL, /* 0x0a, 32M */ - 0x01000000UL, /* 0x0c, 16M */ - 0x00800000UL, /* 0x0e, 8M */ - 0x80000000UL, /* 0x10, 2G */ - }; - - bank = (bank & 0x1e) >> 1; - if (bank < sizeof(size)/sizeof(*size)) - ret = size[bank]; - } - - return ret; -} -#endif /* CONFIG_ALPHA_RUFFIAN */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index bcab8667f..419fb47de 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -5,10 +5,9 @@ */ /* - * bootup setup stuff.. + * Bootup setup stuff. */ -#include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -23,6 +22,10 @@ #include <linux/config.h> /* CONFIG_ALPHA_LCA etc */ #include <linux/ioport.h> #include <linux/mc146818rtc.h> +#include <linux/console.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/string.h> #ifdef CONFIG_RTC #include <linux/timex.h> @@ -35,8 +38,8 @@ #include <asm/dma.h> #include <asm/io.h> -extern void setup_smp(void); -extern char *smp_info(void); + +#include "proto.h" #if 1 # define DBG_SRM(args) printk args @@ -44,19 +47,23 @@ extern char *smp_info(void); # define DBG_SRM(args) #endif -struct hae hae = { - 0, - (unsigned long*) HAE_ADDRESS -}; - -#ifdef CONFIG_ALPHA_SRM_SETUP +struct hwrpb_struct *hwrpb; unsigned long srm_hae; -#endif -struct hwrpb_struct *hwrpb; +#ifdef CONFIG_ALPHA_GENERIC +struct alpha_machine_vector alpha_mv; +int alpha_using_srm, alpha_use_srm_setup; +#endif unsigned char aux_device_present = 0xaa; +#define N(a) (sizeof(a)/sizeof(a[0])) + +static unsigned long find_end_memory(void); +static struct alpha_machine_vector *get_sysvec(long, long, long); +static struct alpha_machine_vector *get_sysvec_byname(const char *); +static void get_sysnames(long, long, char **, char **); + /* * This is setup by the secondary bootstrap loader. Because * the zero page is zeroed out as soon as the vm system is @@ -67,234 +74,526 @@ unsigned char aux_device_present = 0xaa; #define COMMAND_LINE ((char*)(PARAM + 0x0000)) #define COMMAND_LINE_SIZE 256 -static char command_line[COMMAND_LINE_SIZE] = { 0, }; - char saved_command_line[COMMAND_LINE_SIZE]; +static char command_line[COMMAND_LINE_SIZE]; +char saved_command_line[COMMAND_LINE_SIZE]; + /* * The format of "screen_info" is strange, and due to early * i386-setup code. This is just enough to make the console * code think we're on a VGA color display. */ + struct screen_info screen_info = { -#if defined(CONFIG_ALPHA_BOOK1) - /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */ - 0, 37, /* orig-x, orig-y */ - { 0, 0 }, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 100, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 37, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ -#else - 0, 25, /* orig-x, orig-y */ - { 0, 0 }, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ -#endif + orig_x: 0, + orig_y: 25, + orig_video_cols: 80, + orig_video_lines: 25, + orig_video_isVGA: 1, + orig_video_points: 16 }; + /* * Initialize Programmable Interval Timers with standard values. Some * drivers depend on them being initialized (e.g., joystick driver). */ -static void init_pit (void) + +/* It is (normally) only counter 1 that presents config problems, so + provide this support function to do the rest of the job. */ + +void inline +init_pit_rest(void) { #if 0 - /* - * Leave refresh timer alone---nobody should depend on - * a particular value anyway. - */ - outb(0x54, 0x43); /* counter 1: refresh timer */ - outb(0x18, 0x41); + /* Leave refresh timer alone---nobody should depend on a + particular value anyway. */ + outb(0x54, 0x43); /* counter 1: refresh timer */ + outb(0x18, 0x41); #endif -#ifdef CONFIG_RTC /* setup interval timer if /dev/rtc is being used */ - outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb(LATCH & 0xff, 0x40); /* LSB */ - outb(LATCH >> 8, 0x40); /* MSB */ - request_region(0x40, 0x20, "timer"); /* reserve pit */ -#else /* RTC */ -#if !defined(CONFIG_ALPHA_RUFFIAN) - /* Ruffian depends on the system timer established in MILO!! */ - outb(0x36, 0x43); /* counter 0: system timer */ - outb(0x00, 0x40); - outb(0x00, 0x40); -#endif /* RUFFIAN */ - request_region(0x70, 0x10, "timer"); /* reserve rtc */ -#endif /* RTC */ - - outb(0xb6, 0x43); /* counter 2: speaker */ - outb(0x31, 0x42); - outb(0x13, 0x42); + outb(0xb6, 0x43); /* counter 2: speaker */ + outb(0x31, 0x42); + outb(0x13, 0x42); + + if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) { + printk("Setting RTC_FREQ to 1024 Hz\n"); + CMOS_WRITE(0x26, RTC_FREQ_SELECT); + } } -static unsigned long find_end_memory(void) +#ifdef CONFIG_RTC +static inline void +rtc_init_pit (void) { - int i; - unsigned long high = 0; - struct memclust_struct * cluster; - struct memdesc_struct * memdesc; + /* Setup interval timer if /dev/rtc is being used */ + outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb(LATCH & 0xff, 0x40); /* LSB */ + outb(LATCH >> 8, 0x40); /* MSB */ + request_region(0x40, 0x20, "timer"); /* reserve pit */ - memdesc = (struct memdesc_struct *) - (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); - cluster = memdesc->cluster; - for (i = memdesc->numclusters ; i > 0; i--, cluster++) { - unsigned long tmp; - tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT; - if (tmp > high) - high = tmp; - } - /* round it up to an even number of pages.. */ - high = (high + PAGE_SIZE) & (PAGE_MASK*2); - return PAGE_OFFSET + high; + init_pit_rest(); } +#endif -void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void +generic_init_pit (void) { - extern int _end; + outb(0x36, 0x43); /* counter 0: system timer */ + outb(0x00, 0x40); + outb(0x00, 0x40); + request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */ - init_pit(); + init_pit_rest(); +} - if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) { - printk("setup_arch: setting RTC_FREQ to 1024/sec\n"); - CMOS_WRITE(0x26, RTC_FREQ_SELECT); - } +/* This probably isn't Right, but it is what the old code did. */ +#if defined(CONFIG_RTC) +# define init_pit rtc_init_pit +#else +# define init_pit alpha_mv.init_pit +#endif - hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr); -#if !defined(CONFIG_ALPHA_TSUNAMI) -#ifdef CONFIG_ALPHA_SRM_SETUP - srm_hae = *hae.reg; /* save SRM setting for restoration */ - DBG_SRM(("setup_arch: old HAE base: 0x%016lx\n", srm_hae)); -#endif /* SRM_SETUP */ - set_hae(hae.cache); /* sync HAE register w/hae_cache */ -#endif /* !TSUNAMI */ +/* + * Declare all of the machine vectors. + */ + +extern struct alpha_machine_vector alcor_mv; +extern struct alpha_machine_vector alphabook1_mv; +extern struct alpha_machine_vector avanti_mv; +extern struct alpha_machine_vector cabriolet_mv; +extern struct alpha_machine_vector dp264_mv; +extern struct alpha_machine_vector eb164_mv; +extern struct alpha_machine_vector eb64p_mv; +extern struct alpha_machine_vector eb66_mv; +extern struct alpha_machine_vector eb66p_mv; +extern struct alpha_machine_vector jensen_mv; +extern struct alpha_machine_vector lx164_mv; +extern struct alpha_machine_vector miata_mv; +extern struct alpha_machine_vector mikasa_mv; +extern struct alpha_machine_vector mikasa_primo_mv; +extern struct alpha_machine_vector noname_mv; +extern struct alpha_machine_vector noritake_mv; +extern struct alpha_machine_vector noritake_primo_mv; +extern struct alpha_machine_vector p2k_mv; +extern struct alpha_machine_vector pc164_mv; +extern struct alpha_machine_vector rawhide_mv; +extern struct alpha_machine_vector ruffian_mv; +extern struct alpha_machine_vector sable_mv; +extern struct alpha_machine_vector sable_gamma_mv; +extern struct alpha_machine_vector sx164_mv; +extern struct alpha_machine_vector takara_mv; +extern struct alpha_machine_vector xl_mv; +extern struct alpha_machine_vector xlt_mv; + + +void __init +setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p) +{ + extern char _end[]; - wrmces(0x7); /* reset enable correctable error reports */ + struct alpha_machine_vector *vec = NULL; + struct percpu_struct *cpu; + char *type_name, *var_name, *p; - ROOT_DEV = to_kdev_t(0x0802); /* sda2 */ - command_line[COMMAND_LINE_SIZE - 1] = '\0'; + hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr); - /* Hack for Jensen... since we're restricted to 8 or 16 - * chars for boot flags depending on the boot mode, - * we need some shorthand. This should do for - * installation. Later we'll add other abbreviations - * as well... + /* + * Locate the command line. */ + + /* Hack for Jensen... since we're restricted to 8 or 16 chars for + boot flags depending on the boot mode, we need some shorthand. + This should do for installation. Later we'll add other + abbreviations as well... */ if (strcmp(COMMAND_LINE, "INSTALL") == 0) { strcpy(command_line, "root=/dev/fd0 load_ramdisk=1"); - strcpy(saved_command_line, command_line); } else { - strcpy(command_line, COMMAND_LINE); - strcpy(saved_command_line, COMMAND_LINE); + strncpy(command_line, COMMAND_LINE, sizeof command_line); + command_line[sizeof(command_line)-1] = 0; } - printk("Command line: %s\n", command_line); - + strcpy(saved_command_line, command_line); *cmdline_p = command_line; - *memory_start_p = (unsigned long) &_end; + + /* + * Process command-line arguments. + */ + + for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) { +#ifndef alpha_use_srm_setup + /* Allow a command-line option to respect the + SRM's configuration. */ + if (strncmp(p, "srm_setup=", 10) == 0) { + alpha_use_srm_setup = (p[10] != '0'); + continue; + } +#endif + + if (strncmp(p, "alpha_mv=", 9) == 0) { + vec = get_sysvec_byname(p+9); + continue; + } + } + + /* Replace the command line, not that we've killed it with strtok. */ + strcpy(command_line, saved_command_line); + + /* + * Indentify and reconfigure for the current system. + */ + + get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, + &type_name, &var_name); + if (*var_name == '0') + var_name = ""; + + if (!vec) { + cpu = (struct percpu_struct*) + ((char*)hwrpb + hwrpb->processor_offset); + vec = get_sysvec(hwrpb->sys_type, hwrpb->sys_variation, + cpu->type); + } + +#ifdef CONFIG_ALPHA_GENERIC + if (!vec) { + panic("Unsupported system type: %s%s%s (%ld %ld)\n", + type_name, (*var_name ? " variation " : ""), var_name, + hwrpb->sys_type, hwrpb->sys_variation); + } + alpha_mv = *vec; + + /* Assume that we've booted from SRM if we havn't booted from MILO. + Detect the later by looking for "MILO" in the system serial nr. */ + alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; +#else + /* Once we're sure we can reliably identify systems, we should + simply panic as we do above. */ + if (vec != &alpha_mv) { + printk("WARNING: Not configured for system type: %s%s%s " + "(%ld %ld)\nContinuing with trepidation...\n", + type_name, (*var_name ? " variation " : ""), var_name, + hwrpb->sys_type, hwrpb->sys_variation); + } +#endif + + /* + * Sync with the HAE + */ + + /* Save the SRM's current value for restoration. */ + srm_hae = *alpha_mv.hae_register; + __set_hae(alpha_mv.hae_cache); + + /* Reset enable correctable error reports. */ + wrmces(0x7); + + /* Find our memory. */ *memory_end_p = find_end_memory(); + *memory_start_p = (unsigned long) _end; + + /* Initialize the machine. Usually has to do with setting up + DMA windows and the like. */ + if (alpha_mv.init_arch) + alpha_mv.init_arch(memory_start_p, memory_end_p); -#if defined(CONFIG_ALPHA_LCA) - *memory_start_p = lca_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_APECS) - *memory_start_p = apecs_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_CIA) - *memory_start_p = cia_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_PYXIS) - *memory_start_p = pyxis_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_T2) - *memory_start_p = t2_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_TSUNAMI) - *memory_start_p = tsunami_init(*memory_start_p, *memory_end_p); -#elif defined(CONFIG_ALPHA_MCPCIA) - *memory_start_p = mcpcia_init(*memory_start_p, *memory_end_p); + /* Initialize the timers. */ + init_pit(); + + /* Default root filesystem to sda2. */ + ROOT_DEV = to_kdev_t(0x0802); + + /* + * Give us a default console. TGA users will see nothing until + * chr_dev_init is called, rather late in the boot sequence. + */ + +#ifdef CONFIG_VT +#if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +#elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif #endif + /* Delayed so that we've initialized the machine first. */ + printk("Booting on %s%s%s using machine vector %s\n", + type_name, (*var_name ? " variation " : ""), + var_name, alpha_mv.vector_name); + printk("Command line: %s\n", command_line); + + /* + * Check ASN in HWRPB for validity, report if bad. + * FIXME: how was this failing? Should we trust it instead, + * and copy the value into alpha_mv.max_asn? + */ + + if (hwrpb->max_asn != MAX_ASN) { + printk("Max ASN from HWRPB is bad (0x%lx)\n", hwrpb->max_asn); + } + + /* + * Identify the flock of penguins. + */ + #ifdef __SMP__ setup_smp(); #endif } +static unsigned long __init +find_end_memory(void) +{ + int i; + unsigned long high = 0; + struct memclust_struct * cluster; + struct memdesc_struct * memdesc; -#define N(a) (sizeof(a)/sizeof(a[0])) + memdesc = (struct memdesc_struct *) + (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); + cluster = memdesc->cluster; -/* A change was made to the HWRPB via an ECO and the following code tracks - * a part of the ECO. The HWRPB version must be 5 or higher or the ECO - * was not implemented in the console firmware. If its at rev 5 or greater - * we can get the platform ascii string name from the HWRPB. Thats what this - * function does. It checks the rev level and if the string is in the HWRPB - * it returns the addtess of the string ... a pointer to the platform name. - * - * Returns: - * - Pointer to a ascii string if its in the HWRPB - * - Pointer to a blank string if the data is not in the HWRPB. - */ -static char * -platform_string(void) -{ - struct dsr_struct *dsr; - static char unk_system_string[] = "N/A"; + for (i = memdesc->numclusters ; i > 0; i--, cluster++) { + unsigned long tmp; + tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT; + if (tmp > high) + high = tmp; + } - /* Go to the console for the string pointer. - * If the rpb_vers is not 5 or greater the rpb - * is old and does not have this data in it. - */ - if (hwrpb->revision < 5) - return (unk_system_string); - else { - /* The Dynamic System Recognition struct - * has the system platform name starting - * after the character count of the string. - */ - dsr = ((struct dsr_struct *) - ((char *)hwrpb + hwrpb->dsr_offset)); - return ((char *)dsr + (dsr->sysname_off + - sizeof(long))); - } + /* Round it up to an even number of pages. */ + high = (high + PAGE_SIZE) & (PAGE_MASK*2); + return PAGE_OFFSET + high; } -static void -get_sysnames(long type, long variation, - char **type_name, char **variation_name) + +static char sys_unknown[] = "Unknown"; +static char systype_names[][16] = { + "0", + "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", + "Pelican", "Morgan", "Sable", "Medulla", "Noname", + "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", + "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", + "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", + "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", + "Tsunami", "Wildfire", "CUSCO" +}; + +static char unofficial_names[][8] = {"100", "Ruffian"}; + +static char eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164"}; +static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3}; + +static char alcor_names[][16] = {"Alcor", "Maverick", "Bret"}; +static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; + +static char eb64p_names[][16] = {"EB64+", "Cabriolet", "AlphaPCI64"}; +static int eb64p_indices[] = {0,0,1,2}; + +static char eb66_names[][8] = {"EB66", "EB66+"}; +static int eb66_indices[] = {0,0,1}; + +static char rawhide_names[][16] = { + "Dodge", "Wrangler", "Durango", "Tincup", "DaVinci" +}; +static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; + + +static struct alpha_machine_vector * __init +get_sysvec(long type, long variation, long cpu) { - static char *sys_unknown = "Unknown"; - static char *systype_names[] = { - "0", - "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", - "Pelican", "Morgan", "Sable", "Medulla", "Noname", - "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", - "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", - "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", - "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", - "Tsunami", "Wildfire", "CUSCO" +#ifdef CONFIG_ALPHA_GENERIC + static struct alpha_machine_vector *systype_vecs[] __initlocaldata = + { + NULL, /* 0 */ + NULL, /* ADU */ + NULL, /* Cobra */ + NULL, /* Ruby */ + NULL, /* Flamingo */ + NULL, /* Mannequin */ + &jensen_mv, + NULL, /* Pelican */ + NULL, /* Morgan */ + NULL, /* Sable -- see below. */ + NULL, /* Medulla */ + &noname_mv, + NULL, /* Turbolaser */ + &avanti_mv, + NULL, /* Mustang */ + &alcor_mv, /* Alcor, Bret, Maverick. */ + NULL, /* Tradewind */ + NULL, /* Mikasa -- see below. */ + NULL, /* EB64 */ + NULL, /* EB66 -- see variation. */ + NULL, /* EB64+ -- see variation. */ + &alphabook1_mv, + &rawhide_mv, + NULL, /* K2 */ + NULL, /* Lynx */ + &xl_mv, + NULL, /* EB164 -- see variation. */ + NULL, /* Noritake -- see below. */ + NULL, /* Cortex */ + NULL, /* 29 */ + &miata_mv, + NULL, /* XXM */ + &takara_mv, + NULL, /* Yukon */ + &dp264_mv, + NULL, /* Wildfire */ + NULL, /* CUSCO */ + }; + + static struct alpha_machine_vector *unofficial_vecs[] __initlocaldata = + { + NULL, /* 100 */ + &ruffian_mv, + }; + + static struct alpha_machine_vector *alcor_vecs[] __initlocaldata = + { + &alcor_mv, &xlt_mv, &xlt_mv }; - static char *unofficial_names[] = {"100", "Ruffian"}; + static struct alpha_machine_vector *eb164_vecs[] __initlocaldata = + { + &eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv + }; + + static struct alpha_machine_vector *eb64p_vecs[] __initlocaldata = + { + &eb64p_mv, + &cabriolet_mv, + NULL /* AlphaPCI64 */ + }; - static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"}; - static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3}; + static struct alpha_machine_vector *eb66_vecs[] __initlocaldata = + { + &eb66_mv, + &eb66p_mv + }; - static char * alcor_names[] = {"Alcor", "Maverick", "Bret"}; - static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; + /* ??? Do we need to distinguish between Rawhides? */ - static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"}; - static int eb64p_indices[] = {0,0,1.2}; + struct alpha_machine_vector *vec; - static char * eb66_names[] = {"EB66", "EB66+"}; - static int eb66_indices[] = {0,0,1}; + /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */ + if (type < 0) + type = -type; - static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango", - "Tincup", "DaVinci"}; - static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4}; + /* Search the system tables first... */ + vec = NULL; + if (type < N(systype_vecs)) { + vec = systype_vecs[type]; + } else if ((type > ST_UNOFFICIAL_BIAS) && + (type - ST_UNOFFICIAL_BIAS) < N(unofficial_vecs)) { + vec = unofficial_vecs[type - ST_UNOFFICIAL_BIAS]; + } + + /* If we've not found one, try for a variation. */ + + if (!vec) { + /* Member ID is a bit-field. */ + long member = (variation >> 10) & 0x3f; + + switch (type) { + case ST_DEC_ALCOR: + if (member < N(alcor_indices)) + vec = alcor_vecs[alcor_indices[member]]; + break; + case ST_DEC_EB164: + if (member < N(eb164_indices)) + vec = eb164_vecs[eb164_indices[member]]; + break; + case ST_DEC_EB64P: + if (member < N(eb64p_indices)) + vec = eb64p_vecs[eb64p_indices[member]]; + break; + case ST_DEC_EB66: + if (member < N(eb66_indices)) + vec = eb66_vecs[eb66_indices[member]]; + break; + case ST_DEC_1000: + if (cpu == EV5_CPU) + vec = &mikasa_primo_mv; + else + vec = &mikasa_mv; + break; + case ST_DEC_NORITAKE: + if (cpu == EV5_CPU) + vec = &noritake_primo_mv; + else + vec = &noritake_mv; + break; + case ST_DEC_2100_A500: + if (cpu == EV5_CPU) + vec = &sable_gamma_mv; + else + vec = &sable_mv; + break; + } + } + return vec; +#else + /* TODO: verify that the system is of the type for which we + were configured. For now, cop out and return success. */ + return &alpha_mv; +#endif /* GENERIC */ +} +static struct alpha_machine_vector * __init +get_sysvec_byname(const char *name) +{ +#ifdef CONFIG_ALPHA_GENERIC + static struct alpha_machine_vector *all_vecs[] __initlocaldata = + { + &alcor_mv, + &alphabook1_mv, + &avanti_mv, + &cabriolet_mv, + &dp264_mv, + &eb164_mv, + &eb64p_mv, + &eb66_mv, + &eb66p_mv, + &jensen_mv, + &lx164_mv, + &miata_mv, + &mikasa_mv, + &mikasa_primo_mv, + &noname_mv, + &noritake_mv, + &noritake_primo_mv, + &p2k_mv, + &pc164_mv, + &rawhide_mv, + &ruffian_mv, + &sable_mv, + &sable_gamma_mv, + &sx164_mv, + &takara_mv, + &xl_mv, + &xlt_mv + }; + + int i, n = sizeof(all_vecs)/sizeof(*all_vecs); + for (i = 0; i < n; ++i) { + struct alpha_machine_vector *mv = all_vecs[i]; + if (strcasecmp(mv->vector_name, name) == 0) + return mv; + } + return NULL; +#else + if (strcasecmp(alpha_mv.vector_name, name) == 0) + return &alpha_mv; + return NULL; +#endif +} + +static void +get_sysnames(long type, long variation, + char **type_name, char **variation_name) +{ long member; /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */ @@ -343,9 +642,47 @@ get_sysnames(long type, long variation, break; case ST_DEC_RAWHIDE: if (member < N(rawhide_indices)) - *variation_name = rawhide_names[rawhide_indices[member]]; + *variation_name = rawhide_names[rawhide_indices[member]]; break; - } /* end family switch */ + } +} + +/* + * A change was made to the HWRPB via an ECO and the following code + * tracks a part of the ECO. In HWRPB versions less than 5, the ECO + * was not implemented in the console firmware. If it's revision 5 or + * greater we can get the name of the platform as an ASCII string from + * the HWRPB. That's what this function does. It checks the revision + * level and if the string is in the HWRPB it returns the address of + * the string--a pointer to the name of the platform. + * + * Returns: + * - Pointer to a ASCII string if it's in the HWRPB + * - Pointer to a blank string if the data is not in the HWRPB. + */ + +static char * +platform_string(void) +{ + struct dsr_struct *dsr; + static char unk_system_string[] = "N/A"; + + /* Go to the console for the string pointer. + * If the rpb_vers is not 5 or greater the rpb + * is old and does not have this data in it. + */ + if (hwrpb->revision < 5) + return (unk_system_string); + else { + /* The Dynamic System Recognition struct + * has the system platform name starting + * after the character count of the string. + */ + dsr = ((struct dsr_struct *) + ((char *)hwrpb + hwrpb->dsr_offset)); + return ((char *)dsr + (dsr->sysname_off + + sizeof(long))); + } } /* @@ -353,20 +690,21 @@ get_sysnames(long type, long variation, */ int get_cpuinfo(char *buffer) { - static char *cpu_names[] = { - "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56", "PCA57" - }; - extern struct unaligned_stat { unsigned long count, va, pc; } unaligned[2]; + static char cpu_names[][8] = { + "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56", "PCA57" + }; + struct percpu_struct *cpu; unsigned int cpu_index; char *cpu_name; char *systype_name; char *sysvariation_name; + int len; cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); @@ -377,30 +715,25 @@ int get_cpuinfo(char *buffer) get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, &systype_name, &sysvariation_name); - return sprintf(buffer, - "cpu\t\t\t: Alpha\n" - "cpu model\t\t: %s\n" - "cpu variation\t\t: %ld\n" - "cpu revision\t\t: %ld\n" - "cpu serial number\t: %s\n" - "system type\t\t: %s\n" - "system variation\t: %s\n" - "system revision\t\t: %ld\n" - "system serial number\t: %s\n" - "cycle frequency [Hz]\t: %lu\n" - "timer frequency [Hz]\t: %lu.%02lu\n" - "page size [bytes]\t: %ld\n" - "phys. address bits\t: %ld\n" - "max. addr. space #\t: %ld\n" - "BogoMIPS\t\t: %lu.%02lu\n" - "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "platform string\t\t: %s\n" -#ifdef __SMP__ - "%s" -#endif - , - + len = sprintf(buffer, + "cpu\t\t\t: Alpha\n" + "cpu model\t\t: %s\n" + "cpu variation\t\t: %ld\n" + "cpu revision\t\t: %ld\n" + "cpu serial number\t: %s\n" + "system type\t\t: %s\n" + "system variation\t: %s\n" + "system revision\t\t: %ld\n" + "system serial number\t: %s\n" + "cycle frequency [Hz]\t: %lu\n" + "timer frequency [Hz]\t: %lu.%02lu\n" + "page size [bytes]\t: %ld\n" + "phys. address bits\t: %ld\n" + "max. addr. space #\t: %ld\n" + "BogoMIPS\t\t: %lu.%02lu\n" + "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" + "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" + "platform string\t\t: %s\n", cpu_name, cpu->variation, cpu->revision, (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, @@ -414,9 +747,11 @@ int get_cpuinfo(char *buffer) loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va, - platform_string() + platform_string()); + #ifdef __SMP__ - , smp_info() + return len + smp_info(buffer+len); +#else + return len; #endif - ); } diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 1943b26f7..22f8742e1 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -203,6 +203,12 @@ do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, } } +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + /* * Do a signal return; undo the signal stack. */ @@ -225,67 +231,65 @@ struct rt_sigframe #define INSN_LDI_R0 0x201f0000 #define INSN_CALLSYS 0x00000083 - -static void +static long restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, struct switch_stack *sw) { unsigned long usp; - int i; + long i, err = 0; - __get_user(regs->pc, &sc->sc_pc); + err |= __get_user(regs->pc, &sc->sc_pc); sw->r26 = (unsigned long) ret_from_sys_call; - __get_user(regs->r0, sc->sc_regs+0); - __get_user(regs->r1, sc->sc_regs+1); - __get_user(regs->r2, sc->sc_regs+2); - __get_user(regs->r3, sc->sc_regs+3); - __get_user(regs->r4, sc->sc_regs+4); - __get_user(regs->r5, sc->sc_regs+5); - __get_user(regs->r6, sc->sc_regs+6); - __get_user(regs->r7, sc->sc_regs+7); - __get_user(regs->r8, sc->sc_regs+8); - __get_user(sw->r9, sc->sc_regs+9); - __get_user(sw->r10, sc->sc_regs+10); - __get_user(sw->r11, sc->sc_regs+11); - __get_user(sw->r12, sc->sc_regs+12); - __get_user(sw->r13, sc->sc_regs+13); - __get_user(sw->r14, sc->sc_regs+14); - __get_user(sw->r15, sc->sc_regs+15); - __get_user(regs->r16, sc->sc_regs+16); - __get_user(regs->r17, sc->sc_regs+17); - __get_user(regs->r18, sc->sc_regs+18); - __get_user(regs->r19, sc->sc_regs+19); - __get_user(regs->r20, sc->sc_regs+20); - __get_user(regs->r21, sc->sc_regs+21); - __get_user(regs->r22, sc->sc_regs+22); - __get_user(regs->r23, sc->sc_regs+23); - __get_user(regs->r24, sc->sc_regs+24); - __get_user(regs->r25, sc->sc_regs+25); - __get_user(regs->r26, sc->sc_regs+26); - __get_user(regs->r27, sc->sc_regs+27); - __get_user(regs->r28, sc->sc_regs+28); - __get_user(regs->gp, sc->sc_regs+29); - __get_user(usp, sc->sc_regs+30); + err |= __get_user(regs->r0, sc->sc_regs+0); + err |= __get_user(regs->r1, sc->sc_regs+1); + err |= __get_user(regs->r2, sc->sc_regs+2); + err |= __get_user(regs->r3, sc->sc_regs+3); + err |= __get_user(regs->r4, sc->sc_regs+4); + err |= __get_user(regs->r5, sc->sc_regs+5); + err |= __get_user(regs->r6, sc->sc_regs+6); + err |= __get_user(regs->r7, sc->sc_regs+7); + err |= __get_user(regs->r8, sc->sc_regs+8); + err |= __get_user(sw->r9, sc->sc_regs+9); + err |= __get_user(sw->r10, sc->sc_regs+10); + err |= __get_user(sw->r11, sc->sc_regs+11); + err |= __get_user(sw->r12, sc->sc_regs+12); + err |= __get_user(sw->r13, sc->sc_regs+13); + err |= __get_user(sw->r14, sc->sc_regs+14); + err |= __get_user(sw->r15, sc->sc_regs+15); + err |= __get_user(regs->r16, sc->sc_regs+16); + err |= __get_user(regs->r17, sc->sc_regs+17); + err |= __get_user(regs->r18, sc->sc_regs+18); + err |= __get_user(regs->r19, sc->sc_regs+19); + err |= __get_user(regs->r20, sc->sc_regs+20); + err |= __get_user(regs->r21, sc->sc_regs+21); + err |= __get_user(regs->r22, sc->sc_regs+22); + err |= __get_user(regs->r23, sc->sc_regs+23); + err |= __get_user(regs->r24, sc->sc_regs+24); + err |= __get_user(regs->r25, sc->sc_regs+25); + err |= __get_user(regs->r26, sc->sc_regs+26); + err |= __get_user(regs->r27, sc->sc_regs+27); + err |= __get_user(regs->r28, sc->sc_regs+28); + err |= __get_user(regs->gp, sc->sc_regs+29); + err |= __get_user(usp, sc->sc_regs+30); wrusp(usp); for (i = 0; i < 31; i++) - __get_user(sw->fp[i], sc->sc_fpregs+i); - __get_user(sw->fp[31], &sc->sc_fpcr); + err |= __get_user(sw->fp[i], sc->sc_fpregs+i); + err |= __get_user(sw->fp[31], &sc->sc_fpcr); + + return err; } asmlinkage void do_sigreturn(struct sigframe *frame, struct pt_regs *regs, struct switch_stack *sw) { - unsigned long ps; sigset_t set; /* Verify that it's a good sigcontext before using it */ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto give_sigsegv; - if (__get_user(ps, &frame->sc.sc_ps) || ps != 8) - goto give_sigsegv; if (__get_user(set.sig[0], &frame->sc.sc_mask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, @@ -298,7 +302,8 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs, recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - restore_sigcontext(&frame->sc, regs, sw); + if (restore_sigcontext(&frame->sc, regs, sw)) + goto give_sigsegv; /* Send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) @@ -306,22 +311,19 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs, return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } asmlinkage void do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, struct switch_stack *sw) { - unsigned long ps; sigset_t set; + stack_t st; /* Verify that it's a good sigcontext before using it */ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto give_sigsegv; - if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8) - goto give_sigsegv; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto give_sigsegv; @@ -331,7 +333,14 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - restore_sigcontext(&frame->uc.uc_mcontext, regs, sw); + if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw)) + goto give_sigsegv; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto give_sigsegv; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, rdusp()); /* Send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) @@ -339,8 +348,7 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + force_sig(SIGSEGV, current); } @@ -348,99 +356,113 @@ give_sigsegv: * Set up a signal frame. */ -static void +static inline void * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & -32ul); +} + +static long setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, struct switch_stack *sw, unsigned long mask, unsigned long sp) { - long i; - - __put_user(0, &sc->sc_onstack); - __put_user(mask, &sc->sc_mask); - __put_user(regs->pc, &sc->sc_pc); - __put_user(8, &sc->sc_ps); - - __put_user(regs->r0 , sc->sc_regs+0); - __put_user(regs->r1 , sc->sc_regs+1); - __put_user(regs->r2 , sc->sc_regs+2); - __put_user(regs->r3 , sc->sc_regs+3); - __put_user(regs->r4 , sc->sc_regs+4); - __put_user(regs->r5 , sc->sc_regs+5); - __put_user(regs->r6 , sc->sc_regs+6); - __put_user(regs->r7 , sc->sc_regs+7); - __put_user(regs->r8 , sc->sc_regs+8); - __put_user(sw->r9 , sc->sc_regs+9); - __put_user(sw->r10 , sc->sc_regs+10); - __put_user(sw->r11 , sc->sc_regs+11); - __put_user(sw->r12 , sc->sc_regs+12); - __put_user(sw->r13 , sc->sc_regs+13); - __put_user(sw->r14 , sc->sc_regs+14); - __put_user(sw->r15 , sc->sc_regs+15); - __put_user(regs->r16, sc->sc_regs+16); - __put_user(regs->r17, sc->sc_regs+17); - __put_user(regs->r18, sc->sc_regs+18); - __put_user(regs->r19, sc->sc_regs+19); - __put_user(regs->r20, sc->sc_regs+20); - __put_user(regs->r21, sc->sc_regs+21); - __put_user(regs->r22, sc->sc_regs+22); - __put_user(regs->r23, sc->sc_regs+23); - __put_user(regs->r24, sc->sc_regs+24); - __put_user(regs->r25, sc->sc_regs+25); - __put_user(regs->r26, sc->sc_regs+26); - __put_user(regs->r27, sc->sc_regs+27); - __put_user(regs->r28, sc->sc_regs+28); - __put_user(regs->gp , sc->sc_regs+29); - __put_user(sp, sc->sc_regs+30); - __put_user(0, sc->sc_regs+31); + long i, err = 0; + + err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); + err |= __put_user(mask, &sc->sc_mask); + err |= __put_user(regs->pc, &sc->sc_pc); + err |= __put_user(8, &sc->sc_ps); + + err |= __put_user(regs->r0 , sc->sc_regs+0); + err |= __put_user(regs->r1 , sc->sc_regs+1); + err |= __put_user(regs->r2 , sc->sc_regs+2); + err |= __put_user(regs->r3 , sc->sc_regs+3); + err |= __put_user(regs->r4 , sc->sc_regs+4); + err |= __put_user(regs->r5 , sc->sc_regs+5); + err |= __put_user(regs->r6 , sc->sc_regs+6); + err |= __put_user(regs->r7 , sc->sc_regs+7); + err |= __put_user(regs->r8 , sc->sc_regs+8); + err |= __put_user(sw->r9 , sc->sc_regs+9); + err |= __put_user(sw->r10 , sc->sc_regs+10); + err |= __put_user(sw->r11 , sc->sc_regs+11); + err |= __put_user(sw->r12 , sc->sc_regs+12); + err |= __put_user(sw->r13 , sc->sc_regs+13); + err |= __put_user(sw->r14 , sc->sc_regs+14); + err |= __put_user(sw->r15 , sc->sc_regs+15); + err |= __put_user(regs->r16, sc->sc_regs+16); + err |= __put_user(regs->r17, sc->sc_regs+17); + err |= __put_user(regs->r18, sc->sc_regs+18); + err |= __put_user(regs->r19, sc->sc_regs+19); + err |= __put_user(regs->r20, sc->sc_regs+20); + err |= __put_user(regs->r21, sc->sc_regs+21); + err |= __put_user(regs->r22, sc->sc_regs+22); + err |= __put_user(regs->r23, sc->sc_regs+23); + err |= __put_user(regs->r24, sc->sc_regs+24); + err |= __put_user(regs->r25, sc->sc_regs+25); + err |= __put_user(regs->r26, sc->sc_regs+26); + err |= __put_user(regs->r27, sc->sc_regs+27); + err |= __put_user(regs->r28, sc->sc_regs+28); + err |= __put_user(regs->gp , sc->sc_regs+29); + err |= __put_user(sp, sc->sc_regs+30); + err |= __put_user(0, sc->sc_regs+31); for (i = 0; i < 31; i++) - __put_user(sw->fp[i], sc->sc_fpregs+i); - __put_user(0, sc->sc_fpregs+31); - __put_user(sw->fp[31], &sc->sc_fpcr); + err |= __put_user(sw->fp[i], sc->sc_fpregs+i); + err |= __put_user(0, sc->sc_fpregs+31); + err |= __put_user(sw->fp[31], &sc->sc_fpcr); + + err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); + err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); + err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2); - __put_user(regs->trap_a0, &sc->sc_traparg_a0); - __put_user(regs->trap_a1, &sc->sc_traparg_a1); - __put_user(regs->trap_a2, &sc->sc_traparg_a2); + return err; } static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { - unsigned long oldsp; + unsigned long oldsp, r26, err = 0; struct sigframe *frame; oldsp = rdusp(); - frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32); - - /* XXX: Check here if we would need to switch stacks.. */ + frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); + err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); if (_NSIG_WORDS > 1) { - __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); } /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { - regs->r26 = (unsigned long) ka->ka_restorer; + r26 = (unsigned long) ka->ka_restorer; } else { - __put_user(INSN_MOV_R30_R16, frame->retcode+0); - __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); - __put_user(INSN_CALLSYS, frame->retcode+2); + err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); + err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); + err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); - regs->r26 = (unsigned long) frame->retcode; + r26 = (unsigned long) frame->retcode; } + /* Check that everything was written properly. */ + if (err) + goto give_sigsegv; + /* "Return" to the handler */ + regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = 0; /* a1: exception code */ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ wrusp((unsigned long) frame); - + #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); @@ -449,47 +471,54 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { - unsigned long oldsp; + unsigned long oldsp, r26, err = 0; struct rt_sigframe *frame; oldsp = rdusp(); - frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32); - - /* XXX: Check here if we would need to switch stacks.. */ + frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - __copy_to_user(&frame->info, info, sizeof(siginfo_t)); - - /* Zero all bits of the ucontext besides the sigcontext. */ - __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t)); - /* Copy in the bits we actually use. */ - __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); - setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp); - __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, + set->sig[0], oldsp); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { - regs->r26 = (unsigned long) ka->ka_restorer; + r26 = (unsigned long) ka->ka_restorer; } else { - __put_user(INSN_MOV_R30_R16, frame->retcode+0); - __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1); - __put_user(INSN_CALLSYS, frame->retcode+2); + err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); + err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, + frame->retcode+1); + err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); - regs->r26 = (unsigned long) frame->retcode; + r26 = (unsigned long) frame->retcode; } + if (err) + goto give_sigsegv; + /* "Return" to the handler */ + regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ @@ -504,8 +533,9 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c index bcc4ed212..3d7cd05f8 100644 --- a/arch/alpha/kernel/smc37c669.c +++ b/arch/alpha/kernel/smc37c669.c @@ -6,6 +6,7 @@ #include <linux/malloc.h> #include <linux/mm.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/hwrpb.h> #include <asm/io.h> @@ -1131,7 +1132,7 @@ struct DDB smc_ddb = { 0, /* is a flash update driver */ 0, /* is a block device */ 0, /* not seekable */ - 0, /* is an ethernet device */ + 0, /* is an Ethernet device */ 0, /* is a filesystem driver */ }; #endif diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index fed91a1c1..53175a0f1 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -1,4 +1,3 @@ -#include <linux/config.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> @@ -9,12 +8,12 @@ #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/hwrpb.h> #include <asm/ptrace.h> #include <asm/atomic.h> -#include <asm/delay.h> #include <asm/irq.h> #include <asm/bitops.h> #include <asm/pgtable.h> @@ -25,6 +24,8 @@ #define __KERNEL_SYSCALLS__ #include <asm/unistd.h> +#include "proto.h" + struct ipi_msg_flush_tb_struct ipi_msg_flush_tb; struct cpuinfo_alpha cpu_data[NR_CPUS]; @@ -336,10 +337,8 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) #ifdef NOT_YET clear_profile_irq(mid_xlate[cpu]); -#ifdef CONFIG_PROFILE if(!user_mode(regs)) - sparc_do_profile(regs->pc); -#endif + alpha_do_profile(regs->pc); #endif if (!--prof_counter[cpu]) { @@ -349,7 +348,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) if (--current->counter < 0) { current->counter = 0; - need_resched = 1; + current->need_resched = 1; } spin_lock(&ticker_lock); @@ -397,9 +396,8 @@ lier); return -EINVAL; } -/* Only broken Intel needs this, thus it should not even be referenced - * globally... - */ +/* Only broken Intel needs this, thus it should not even be referenced globally. +*/ __initfunc(void initialize_secondary(void)) { printk("initialize_secondary: entry\n"); @@ -463,7 +461,7 @@ printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", #endif return; } - udelay(1000); + mdelay(1); } #if 0 printk("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid); @@ -490,7 +488,7 @@ send_cpu_msg(char *str, int cpuid) printk("Processor %x not ready\n", cpuid); return; } - udelay(1000); + mdelay(1); } cp1 = (char *) &cpu->ipc_buffer[1]; @@ -506,7 +504,7 @@ send_cpu_msg(char *str, int cpuid) printk("Processor %x not ready\n", cpuid); return; } - udelay(1000); + mdelay(1); } } @@ -673,7 +671,7 @@ wrapper_local_flush_tlb_page(unsigned int this_cpu) static int unknown_ipi(unsigned int this_cpu) { - printk("unknown_ipi() on cpu %d: ", this_cpu); + printk("unknown_ipi() on CPU %d: ", this_cpu); return 1; } @@ -739,15 +737,11 @@ send_ipi_message(long to_whom, enum ipi_message_type operation) } } -static char smp_buf[256]; - -char *smp_info(void) +int smp_info(char *buffer) { - sprintf(smp_buf, "CPUs probed %d active %d map 0x%x AKP %d\n", - smp_num_probed, smp_num_cpus, cpu_present_map, - klock_info.akp); - - return smp_buf; + return sprintf(buffer, "CPUs probed %d active %d map 0x%x AKP %d\n", + smp_num_probed, smp_num_cpus, cpu_present_map, + klock_info.akp); } /* wrapper for call from panic() */ @@ -762,7 +756,7 @@ smp_message_pass(int target, int msg, unsigned long data, int wait) send_ipi_message(CPU_STOP, cpu_present_map ^ (1 << me)); return; barf: - printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me); + printk("Yeeee, trying to send SMP msg(%d) on CPU %d\n", msg, me); panic("Bogon SMP message pass."); } diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c new file mode 100644 index 000000000..9b9dd34cf --- /dev/null +++ b/arch/alpha/kernel/sys_alcor.c @@ -0,0 +1,263 @@ +/* + * linux/arch/alpha/kernel/sys_alcor.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the ALCOR and XLT (XL-300/366/433). + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/core_cia.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +alcor_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + /* On Alcor, at least, lines 20..30 are not connected and can + generate spurrious interrupts if we turn them on while IRQ + probing. So explicitly mask them out. */ + mask |= 0x7ff000000000UL; + + /* Note inverted sense of mask bits: */ + *(vuip)GRU_INT_MASK = ~(mask >> 16); + mb(); + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +alcor_ack_irq(unsigned long irq) +{ + if (irq < 16) { + /* Ack the interrupt making it the lowest priority */ + /* First the slave .. */ + if (irq > 7) { + outb(0xE0 | (irq - 8), 0xa0); + irq = 2; + } + /* .. then the master */ + outb(0xE0 | irq, 0x20); + + /* On ALCOR/XLT, need to dismiss interrupt via GRU. */ + *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); + *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); + } +} + +static void +alcor_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary register of the GRU */ + pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 31) { + isa_device_interrupt(vector, regs); + } else { + handle_irq(16 + i, 16 + i, regs); + } + } + restore_flags(flags); +} + +static void +alcor_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = srm_device_interrupt; + + *(vuip)GRU_INT_MASK = ~(alpha_irq_mask >> 16); mb(); /* invert */ + *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */ + *(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */ + *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */ + + enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} + + +/* + * PCI Fixup configuration. + * + * Summary @ GRU_INT_REQ: + * Bit Meaning + * 0 Interrupt Line A from slot 2 + * 1 Interrupt Line B from slot 2 + * 2 Interrupt Line C from slot 2 + * 3 Interrupt Line D from slot 2 + * 4 Interrupt Line A from slot 1 + * 5 Interrupt line B from slot 1 + * 6 Interrupt Line C from slot 1 + * 7 Interrupt Line D from slot 1 + * 8 Interrupt Line A from slot 0 + * 9 Interrupt Line B from slot 0 + *10 Interrupt Line C from slot 0 + *11 Interrupt Line D from slot 0 + *12 Interrupt Line A from slot 4 + *13 Interrupt Line B from slot 4 + *14 Interrupt Line C from slot 4 + *15 Interrupt Line D from slot 4 + *16 Interrupt Line D from slot 3 + *17 Interrupt Line D from slot 3 + *18 Interrupt Line D from slot 3 + *19 Interrupt Line D from slot 3 + *20-30 Reserved + *31 EISA interrupt + * + * The device to slot mapping looks like: + * + * Slot Device + * 6 built-in TULIP (XLT only) + * 7 PCI on board slot 0 + * 8 PCI on board slot 3 + * 9 PCI on board slot 4 + * 10 PCEB (PCI-EISA bridge) + * 11 PCI on board slot 2 + * 12 PCI on board slot 1 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +static int __init +alcor_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[7][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + /* note: IDSEL 17 is XLT only */ + {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ + {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ + {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 20, slot 4 */ + { -1, -1, -1, -1, -1}, /* IdSel 21, PCEB */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + }; + const long min_idsel = 6, max_idsel = 12, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static void __init +alcor_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(alcor_map_irq, common_swizzle); +} + + +static void +alcor_kill_arch (int mode, char *reboot_cmd) +{ + /* Who said DEC engineer's have no sense of humor? ;-) */ + if (alpha_using_srm) { + *(vuip) GRU_RESET = 0x0000dead; + mb(); + } + + generic_kill_arch(mode, reboot_cmd); +} + + +/* + * The System Vectors + */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_ALCOR) +struct alpha_machine_vector alcor_mv __initmv = { + vector_name: "Alcor", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: ALCOR_PROBE_MASK, + update_irq_hw: alcor_update_irq_hw, + ack_irq: alcor_ack_irq, + device_interrupt: alcor_device_interrupt, + + init_arch: cia_init_arch, + init_irq: alcor_init_irq, + init_pit: generic_init_pit, + pci_fixup: alcor_pci_fixup, + kill_arch: alcor_kill_arch, + + sys: { cia: { + gru_int_req_bits: ALCOR_GRU_INT_REQ_BITS + }} +}; +ALIAS_MV(alcor) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XLT) +struct alpha_machine_vector xlt_mv __initmv = { + vector_name: "XLT", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: ALCOR_PROBE_MASK, + update_irq_hw: alcor_update_irq_hw, + ack_irq: alcor_ack_irq, + device_interrupt: alcor_device_interrupt, + + init_arch: cia_init_arch, + init_irq: alcor_init_irq, + init_pit: generic_init_pit, + pci_fixup: alcor_pci_fixup, + kill_arch: alcor_kill_arch, + + sys: { cia: { + gru_int_req_bits: XLT_GRU_INT_REQ_BITS + }} +}; +ALIAS_MV(xlt) +#endif diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c new file mode 100644 index 000000000..273d53c0b --- /dev/null +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -0,0 +1,395 @@ +/* + * linux/arch/alpha/kernel/sys_cabriolet.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164, + * PC164 and LX164. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_apecs.h> +#include <asm/core_cia.h> +#include <asm/core_lca.h> +#include <asm/core_pyxis.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +cabriolet_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) + outl(alpha_irq_mask >> 16, 0x804); + else if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + + +/* Under SRM console, we must use the CSERVE PALcode routine to manage + the interrupt mask for us. Otherwise, the kernel/HW get out of + sync with what the PALcode thinks it needs to deliver/ignore. */ + +static void +cabriolet_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmaskp) +{ + if (irq >= 16) { + if (unmaskp) + cserve_ena(irq - 16); + else + cserve_dis(irq - 16); + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +static void +cabriolet_device_interrupt(unsigned long v, struct pt_regs *r) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary registers */ + pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16); + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 4) { + isa_device_interrupt(v, r); + } else { + handle_irq(16 + i, 16 + i, r); + } + } + restore_flags(flags); +} + +static void +cabriolet_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) { + alpha_mv.update_irq_hw = cabriolet_srm_update_irq_hw; + alpha_mv.device_interrupt = srm_device_interrupt; + } + else { + outl(alpha_irq_mask >> 16, 0x804); + } + + enable_irq(16 + 4); /* enable SIO cascade */ + enable_irq(2); /* enable cascade */ +} + + +/* + * The EB66+ is very similar to the EB66 except that it does not have + * the on-board NCR and Tulip chips. In the code below, I have used + * slot number to refer to the id select line and *not* the slot + * number used in the EB66+ documentation. However, in the table, + * I've given the slot number, the id select line and the Jxx number + * that's printed on the board. The interrupt pins from the PCI slots + * are wired into 3 interrupt summary registers at 0x804, 0x805 and + * 0x806 ISA. + * + * In the table, -1 means don't assign an IRQ number. This is usually + * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. + */ + +static inline int __init +eb66p_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ + {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */ + {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */ + }; + const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static inline void __init +eb66p_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + common_pci_fixup(eb66p_map_irq, common_swizzle); + enable_ide(0x398); +} + + +/* + * The AlphaPC64 is very similar to the EB66+ except that its slots + * are numbered differently. In the code below, I have used slot + * number to refer to the id select line and *not* the slot number + * used in the AlphaPC64 documentation. However, in the table, I've + * given the slot number, the id select line and the Jxx number that's + * printed on the board. The interrupt pins from the PCI slots are + * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806 + * ISA. + * + * In the table, -1 means don't assign an IRQ number. This is usually + * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. + */ + +static inline int __init +cabriolet_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ + { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ + { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */ + }; + const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static inline void __init +cabriolet_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + common_pci_fixup(cabriolet_map_irq, common_swizzle); + enable_ide(0x398); +} + +static inline void __init +eb164_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(cabriolet_map_irq, common_swizzle); + enable_ide(0x398); +} + + +/* + * The PC164 and LX164 have 19 PCI interrupts, four from each of the four + * PCI slots, the SIO, PCI/IDE, and USB. + * + * Each of the interrupts can be individually masked. This is + * accomplished by setting the appropriate bit in the mask register. + * A bit is set by writing a "1" to the desired position in the mask + * register and cleared by writing a "0". There are 3 mask registers + * located at ISA address 804h, 805h and 806h. + * + * An I/O read at ISA address 804h, 805h, 806h will return the + * state of the 11 PCI interrupts and not the state of the MASKED + * interrupts. + * + * Note: A write to I/O 804h, 805h, and 806h the mask register will be + * updated. + * + * + * ISA DATA<7:0> + * ISA +--------------------------------------------------------------+ + * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +==============================================================+ + * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 | + * +--------------------------------------------------------------+ + * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 | + * +--------------------------------------------------------------+ + * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 | + * +--------------------------------------------------------------+ + * * Rsrv = reserved bits + * Note: The mask register is write-only. + * + * IdSel + * 5 32 bit PCI option slot 2 + * 6 64 bit PCI option slot 0 + * 7 64 bit PCI option slot 1 + * 8 Saturn I/O + * 9 32 bit PCI option slot 3 + * 10 USB + * 11 IDE + * + */ + +static inline int __init +alphapc164_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[7][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ + { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ + { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */ + { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */ + { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */ + }; + const long min_idsel = 5, max_idsel = 11, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static inline void __init +alphapc164_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(alphapc164_map_irq, common_swizzle); + SMC93x_Init(); +} + +/* + * The System Vector + */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET) +struct alpha_machine_vector cabriolet_mv __initmv = { + vector_name: "Cabriolet", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + DO_APECS_BUS, + machine_check: apecs_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 35, + irq_probe_mask: _PROBE_MASK(35), + update_irq_hw: cabriolet_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: cabriolet_device_interrupt, + + init_arch: apecs_init_arch, + init_irq: cabriolet_init_irq, + init_pit: generic_init_pit, + pci_fixup: cabriolet_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(cabriolet) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164) +struct alpha_machine_vector eb164_mv __initmv = { + vector_name: "EB164", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 35, + irq_probe_mask: _PROBE_MASK(35), + update_irq_hw: cabriolet_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: cabriolet_device_interrupt, + + init_arch: cia_init_arch, + init_irq: cabriolet_init_irq, + init_pit: generic_init_pit, + pci_fixup: eb164_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(eb164) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P) +struct alpha_machine_vector eb66p_mv __initmv = { + vector_name: "EB66+", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_LCA_IO, + DO_LCA_BUS, + machine_check: lca_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 35, + irq_probe_mask: _PROBE_MASK(35), + update_irq_hw: cabriolet_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: cabriolet_device_interrupt, + + init_arch: lca_init_arch, + init_irq: cabriolet_init_irq, + init_pit: generic_init_pit, + pci_fixup: eb66p_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(eb66p) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164) +struct alpha_machine_vector lx164_mv __initmv = { + vector_name: "LX164", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_PYXIS_IO, + DO_PYXIS_BUS, + machine_check: pyxis_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 35, + irq_probe_mask: _PROBE_MASK(35), + update_irq_hw: cabriolet_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: cabriolet_device_interrupt, + + init_arch: pyxis_init_arch, + init_irq: cabriolet_init_irq, + init_pit: generic_init_pit, + pci_fixup: alphapc164_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(lx164) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) +struct alpha_machine_vector pc164_mv __initmv = { + vector_name: "PC164", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 35, + irq_probe_mask: _PROBE_MASK(35), + update_irq_hw: cabriolet_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: cabriolet_device_interrupt, + + init_arch: cia_init_arch, + init_irq: cabriolet_init_irq, + init_pit: generic_init_pit, + pci_fixup: alphapc164_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(pc164) +#endif + diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c new file mode 100644 index 000000000..e110891be --- /dev/null +++ b/arch/alpha/kernel/sys_dp264.c @@ -0,0 +1,231 @@ +/* + * linux/arch/alpha/kernel/sys_dp264.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the DP264 (EV6+TSUNAMI). + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_tsunami.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +/* + * HACK ALERT! only CPU#0 is used currently + */ + +static void +dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + /* Make CERTAIN none of the bogus ints get enabled */ + *(vulp)TSUNAMI_CSR_DIM0 = + ~(mask) & ~0x0000000000000000UL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)TSUNAMI_CSR_DIM0; + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + __save_and_cli(flags); + + /* Read the interrupt summary register of TSUNAMI */ + pld = (*(vulp)TSUNAMI_CSR_DIR0); + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 55) { + isa_device_interrupt(vector, regs); + } else { /* if not timer int */ + handle_irq(16 + i, 16 + i, regs); + } +#if 0 + *(vulp)TSUNAMI_CSR_DIR0 = 1UL << i; mb(); + tmp = *(vulp)TSUNAMI_CSR_DIR0; +#endif + } + __restore_flags(flags); +} + +static void +dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + /* + * The DP264 SRM console reports PCI interrupts with a vector + * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) + * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have + * it line up with the actual bit numbers from the DIM registers, + * which is how we manage the interrupts/mask. Sigh... + */ + if (irq >= 32) + ack = irq = irq - 16; + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void __init +dp264_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = dp264_srm_device_interrupt; + + /* Note invert on MASK bits. */ + *(vulp)TSUNAMI_CSR_DIM0 = ~(alpha_irq_mask) & ~0UL; mb(); + *(vulp)TSUNAMI_CSR_DIM0; + + enable_irq(55); /* Enable CYPRESS interrupt controller (ISA). */ + enable_irq(2); +} + + +/* + * PCI Fixup configuration. + * + * Summary @ TSUNAMI_CSR_DIM0: + * Bit Meaning + * 0-17 Unused + *18 Interrupt SCSI B (Adaptec 7895 builtin) + *19 Interrupt SCSI A (Adaptec 7895 builtin) + *20 Interrupt Line D from slot 2 PCI0 + *21 Interrupt Line C from slot 2 PCI0 + *22 Interrupt Line B from slot 2 PCI0 + *23 Interrupt Line A from slot 2 PCI0 + *24 Interrupt Line D from slot 1 PCI0 + *25 Interrupt Line C from slot 1 PCI0 + *26 Interrupt Line B from slot 1 PCI0 + *27 Interrupt Line A from slot 1 PCI0 + *28 Interrupt Line D from slot 0 PCI0 + *29 Interrupt Line C from slot 0 PCI0 + *30 Interrupt Line B from slot 0 PCI0 + *31 Interrupt Line A from slot 0 PCI0 + * + *32 Interrupt Line D from slot 3 PCI1 + *33 Interrupt Line C from slot 3 PCI1 + *34 Interrupt Line B from slot 3 PCI1 + *35 Interrupt Line A from slot 3 PCI1 + *36 Interrupt Line D from slot 2 PCI1 + *37 Interrupt Line C from slot 2 PCI1 + *38 Interrupt Line B from slot 2 PCI1 + *39 Interrupt Line A from slot 2 PCI1 + *40 Interrupt Line D from slot 1 PCI1 + *41 Interrupt Line C from slot 1 PCI1 + *42 Interrupt Line B from slot 1 PCI1 + *43 Interrupt Line A from slot 1 PCI1 + *44 Interrupt Line D from slot 0 PCI1 + *45 Interrupt Line C from slot 0 PCI1 + *46 Interrupt Line B from slot 0 PCI1 + *47 Interrupt Line A from slot 0 PCI1 + *48-52 Unused + *53 PCI0 NMI (from Cypress) + *54 PCI0 SMI INT (from Cypress) + *55 PCI0 ISA Interrupt (from Cypress) + *56-60 Unused + *61 PCI1 Bus Error + *62 PCI0 Bus Error + *63 Reserved + * + * IdSel + * 5 Cypress Bridge I/O + * 6 SCSI Adaptec builtin + * 7 64 bit PCI option slot 0 + * 8 64 bit PCI option slot 1 + * 9 64 bit PCI option slot 2 + * + */ + +static int __init +dp264_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { -1, -1, -1, -1, -1}, /* IdSel 5 ISA Bridge */ + { 16+ 2, 16+ 2, 16+ 2, 16+ 2, 16+ 2}, /* IdSel 6 SCSI builtin*/ + { 16+15, 16+15, 16+14, 16+13, 16+12}, /* IdSel 7 slot 0 */ + { 16+11, 16+11, 16+10, 16+ 9, 16+ 8}, /* IdSel 8 slot 1 */ + { 16+ 7, 16+ 7, 16+ 6, 16+ 5, 16+ 4} /* IdSel 9 slot 2 */ + }; + const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static void __init +dp264_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(dp264_map_irq, common_swizzle); + SMC669_Init(); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector dp264_mv __initmv = { + vector_name: "DP264", + DO_EV6_MMU, + DO_DEFAULT_RTC, + DO_TSUNAMI_IO, + DO_TSUNAMI_BUS, + machine_check: tsunami_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 64, + irq_probe_mask: _PROBE_MASK(64), + update_irq_hw: dp264_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: dp264_device_interrupt, + + init_arch: tsunami_init_arch, + init_irq: dp264_init_irq, + init_pit: generic_init_pit, + pci_fixup: dp264_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(dp264) diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c new file mode 100644 index 000000000..bffd119f3 --- /dev/null +++ b/arch/alpha/kernel/sys_eb64p.c @@ -0,0 +1,206 @@ +/* + * linux/arch/alpha/kernel/sys_eb64p.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the EB64+ and EB66. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_apecs.h> +#include <asm/core_lca.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +eb64p_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) + if (irq >= 24) + outb(mask >> 24, 0x27); + else + outb(mask >> 16, 0x26); + else if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +static void +eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary registers */ + pld = inb(0x26) | (inb(0x27) << 8); + /* + * Now, for every possible bit set, work through + * them and call the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + + if (i == 5) { + isa_device_interrupt(vector, regs); + } else { + handle_irq(16 + i, 16 + i, regs); + } + } + restore_flags(flags); +} + +static void __init +eb64p_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + outb(alpha_irq_mask >> 16, 0x26); + outb(alpha_irq_mask >> 24, 0x27); + enable_irq(16 + 5); /* enable SIO cascade */ + enable_irq(2); /* enable cascade */ +} + +/* + * PCI Fixup configuration. + * + * There are two 8 bit external summary registers as follows: + * + * Summary @ 0x26: + * Bit Meaning + * 0 Interrupt Line A from slot 0 + * 1 Interrupt Line A from slot 1 + * 2 Interrupt Line B from slot 0 + * 3 Interrupt Line B from slot 1 + * 4 Interrupt Line C from slot 0 + * 5 Interrupt line from the two ISA PICs + * 6 Tulip (slot + * 7 NCR SCSI + * + * Summary @ 0x27 + * Bit Meaning + * 0 Interrupt Line C from slot 1 + * 1 Interrupt Line D from slot 0 + * 2 Interrupt Line D from slot 1 + * 3 RAZ + * 4 RAZ + * 5 RAZ + * 6 RAZ + * 7 RAZ + * + * The device to slot mapping looks like: + * + * Slot Device + * 5 NCR SCSI controller + * 6 PCI on board slot 0 + * 7 PCI on board slot 1 + * 8 Intel SIO PCI-ISA bridge chip + * 9 Tulip - DECchip 21040 Ethernet controller + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +static int __init +eb64p_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ + {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ + {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ + { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ + {16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 9, TULIP */ + }; + const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static void __init +eb64p_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + common_pci_fixup(eb64p_map_irq, common_swizzle); +} + + +/* + * The System Vector + */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB64P) +struct alpha_machine_vector eb64p_mv __initmv = { + vector_name: "EB64+", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + DO_APECS_BUS, + machine_check: apecs_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 32, + irq_probe_mask: _PROBE_MASK(32), + update_irq_hw: eb64p_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: eb64p_device_interrupt, + + init_arch: apecs_init_arch, + init_irq: eb64p_init_irq, + init_pit: generic_init_pit, + pci_fixup: eb64p_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(eb64p) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66) +struct alpha_machine_vector eb66_mv __initmv = { + vector_name: "EB66", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_LCA_IO, + DO_LCA_BUS, + machine_check: lca_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 32, + irq_probe_mask: _PROBE_MASK(32), + update_irq_hw: eb64p_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: eb64p_device_interrupt, + + init_arch: lca_init_arch, + init_irq: eb64p_init_irq, + init_pit: generic_init_pit, + pci_fixup: eb64p_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(eb66) +#endif diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c new file mode 100644 index 000000000..8406661d7 --- /dev/null +++ b/arch/alpha/kernel/sys_jensen.c @@ -0,0 +1,146 @@ +/* + * linux/arch/alpha/kernel/sys_jensen.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the Jensen. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/jensen.h> +#undef __EXTERN_INLINE + +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/pgtable.h> + +#include "proto.h" +#include "irq.h" +#include "machvec.h" + + +static void +jensen_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +/* + * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and + * 0x9X0 for the local motherboard interrupts.. + * + * 0x660 - NMI + * + * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) + * 0x810 - IRQ1 line printer (duh..) + * 0x860 - IRQ6 floppy disk + * 0x8E0 - IRQ14 SCSI controller + * + * 0x900 - COM1 + * 0x920 - COM2 + * 0x980 - keyboard + * 0x990 - mouse + * + * PCI-based systems are more sane: they don't have the local + * interrupts at all, and have only normal PCI interrupts from + * devices. Happily it's easy enough to do a sane mapping from the + * Jensen.. Note that this means that we may have to do a hardware + * "ack" to a different interrupt than we report to the rest of the + * world. + */ + +static void +handle_nmi(struct pt_regs * regs) +{ + printk("Whee.. NMI received. Probable hardware error\n"); + printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); +} + +static void +jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + switch (vector) { + case 0x660: handle_nmi(regs); return; + + /* local device interrupts: */ + case 0x900: irq = 4, ack = -1; break; /* com1 -> irq 4 */ + case 0x920: irq = 3, ack = -1; break; /* com2 -> irq 3 */ + case 0x980: irq = 1, ack = -1; break; /* kbd -> irq 1 */ + case 0x990: irq = 9, ack = -1; break; /* mouse -> irq 9 */ + default: + if (vector > 0x900) { + printk("Unknown local interrupt %lx\n", vector); + } + + /* irq1 is supposed to be the keyboard, silly Jensen + (is this really needed??) */ + if (irq == 1) + irq = 7; + break; + } + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void +jensen_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + enable_irq(2); /* enable cascade */ +} + +static void +jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs) +{ + printk(KERN_CRIT "Machine check\n"); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector jensen_mv __initmv = { + vector_name: "Jensen", + DO_EV4_MMU, + IO_LITE(JENSEN,jensen,jensen), + BUS(jensen), + machine_check: jensen_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: _PROBE_MASK(16), + update_irq_hw: jensen_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: jensen_device_interrupt, + + init_arch: NULL, + init_irq: jensen_init_irq, + init_pit: generic_init_pit, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(jensen) diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c new file mode 100644 index 000000000..71ec1b2cc --- /dev/null +++ b/arch/alpha/kernel/sys_miata.c @@ -0,0 +1,307 @@ +/* + * linux/arch/alpha/kernel/sys_miata.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the MIATA (EV56+PYXIS). + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_pyxis.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +miata_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x4000000000000e3bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +miata_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld, tmp; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* + * For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) + * then all the PCI slots/INTXs (12-31). + */ + /* Maybe HALT should only be used for SRM console boots? */ + pld &= 0x00000000fffff1c4UL; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) { + isa_device_interrupt(vector, regs); + } else if (i == 6) { + continue; + } else { + /* if not timer int */ + handle_irq(16 + i, 16 + i, regs); + } + *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); + tmp = *(vulp)PYXIS_INT_REQ; + } + restore_flags(flags); +} + +static void +miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + /* + * I really hate to do this, but the MIATA SRM console ignores the + * low 8 bits in the interrupt summary register, and reports the + * vector 0x80 *lower* than I expected from the bit numbering in + * the documentation. + * This was done because the low 8 summary bits really aren't used + * for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't + * used for this purpose, as PIC interrupts are delivered as the + * vectors 0x800-0x8f0). + * But I really don't want to change the fixup code for allocation + * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which look + * nice and clean now. + * So, here's this grotty hack... :-( + */ + if (irq >= 16) + ack = irq = irq + 8; + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void __init +miata_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = miata_srm_device_interrupt; + + /* Note invert on MASK bits. */ + *(vulp)PYXIS_INT_MASK = ~((long)alpha_irq_mask >> 16); mb(); +#if 0 + /* These break on MiataGL so we'll try not to do it at all. */ + *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ + *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ +#endif + /* Clear upper timer. */ + *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb(); + + enable_irq(16 + 2); /* enable HALT switch - SRM only? */ + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} + + +/* + * PCI Fixup configuration. + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 Fan Fault + * 1 NMI + * 2 Halt/Reset switch + * 3 none + * 4 CID0 (Riser ID) + * 5 CID1 (Riser ID) + * 6 Interval timer + * 7 PCI-ISA Bridge + * 8 Ethernet + * 9 EIDE (deprecated, ISA 14/15 used) + *10 none + *11 USB + *12 Interrupt Line A from slot 4 + *13 Interrupt Line B from slot 4 + *14 Interrupt Line C from slot 4 + *15 Interrupt Line D from slot 4 + *16 Interrupt Line A from slot 5 + *17 Interrupt line B from slot 5 + *18 Interrupt Line C from slot 5 + *19 Interrupt Line D from slot 5 + *20 Interrupt Line A from slot 1 + *21 Interrupt Line B from slot 1 + *22 Interrupt Line C from slot 1 + *23 Interrupt Line D from slot 1 + *24 Interrupt Line A from slot 2 + *25 Interrupt Line B from slot 2 + *26 Interrupt Line C from slot 2 + *27 Interrupt Line D from slot 2 + *27 Interrupt Line A from slot 3 + *29 Interrupt Line B from slot 3 + *30 Interrupt Line C from slot 3 + *31 Interrupt Line D from slot 3 + * + * The device to slot mapping looks like: + * + * Slot Device + * 3 DC21142 Ethernet + * 4 EIDE CMD646 + * 5 none + * 6 USB + * 7 PCI-ISA bridge + * 8 PCI-PCI Bridge (SBU Riser) + * 9 none + * 10 none + * 11 PCI on board slot 4 (SBU Riser) + * 12 PCI on board slot 5 (SBU Riser) + * + * These are behind the bridge, so I'm not sure what to do... + * + * 13 PCI on board slot 1 (SBU Riser) + * 14 PCI on board slot 2 (SBU Riser) + * 15 PCI on board slot 3 (SBU Riser) + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +static int __init +miata_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[18][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ + { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ + { -1, -1, -1, -1, -1}, /* IdSel 16, none */ + { -1, -1, -1, -1, -1}, /* IdSel 17, none */ + /* {16+11, 16+11, 16+11, 16+11, 16+11},*//* IdSel 17, USB ?? */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCI-ISA */ + { -1, -1, -1, -1, -1}, /* IdSel 19, PCI-PCI */ + { -1, -1, -1, -1, -1}, /* IdSel 20, none */ + { -1, -1, -1, -1, -1}, /* IdSel 21, none */ + {16+12, 16+12, 16+13, 16+14, 16+15}, /* IdSel 22, slot 4 */ + {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 23, slot 5 */ + /* The following are actually on bus 1, which is + across the builtin PCI-PCI bridge. */ + {16+20, 16+20, 16+21, 16+22, 16+23}, /* IdSel 24, slot 1 */ + {16+24, 16+24, 16+25, 16+26, 16+27}, /* IdSel 25, slot 2 */ + {16+28, 16+28, 16+29, 16+30, 16+31}, /* IdSel 26, slot 3 */ + { -1, -1, -1, -1, -1}, /* IdSel 27, none */ + { -1, -1, -1, -1, -1}, /* IdSel 28, none */ + { -1, -1, -1, -1, -1}, /* IdSel 29, none */ + { -1, -1, -1, -1, -1}, /* IdSel 30, none */ + { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ + }; + const long min_idsel = 3, max_idsel = 20, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static int __init +miata_swizzle(struct pci_dev *dev, int *pinp) +{ + int slot, pin = *pinp; + + /* Check first for the built-in bridge. */ + if ((PCI_SLOT(dev->bus->self->devfn) == 8) || + (PCI_SLOT(dev->bus->self->devfn) == 20)) { + slot = PCI_SLOT(dev->devfn) + 5; + } + else + { + /* Must be a card-based bridge. */ + do { + if ((PCI_SLOT(dev->bus->self->devfn) == 8) || + (PCI_SLOT(dev->bus->self->devfn) == 20)) { + slot = PCI_SLOT(dev->devfn) + 5; + break; + } + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + + /* Move up the chain of bridges. */ + dev = dev->bus->self; + /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + } while (dev->bus->self); + } + *pinp = pin; + return slot; +} + +static void __init +miata_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(miata_map_irq, miata_swizzle); + SMC669_Init(); /* it might be a GL (fails harmlessly if not) */ + es1888_init(); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector miata_mv __initmv = { + vector_name: "Miata", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_PYXIS_IO, + DO_PYXIS_BUS, + machine_check: pyxis_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: _PROBE_MASK(48), + update_irq_hw: miata_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: miata_device_interrupt, + + init_arch: pyxis_init_arch, + init_irq: miata_init_irq, + init_pit: generic_init_pit, + pci_fixup: miata_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(miata) diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c new file mode 100644 index 000000000..92af5d372 --- /dev/null +++ b/arch/alpha/kernel/sys_mikasa.c @@ -0,0 +1,297 @@ +/* + * linux/arch/alpha/kernel/sys_mikasa.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the MIKASA (AlphaServer 1000). + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_apecs.h> +#include <asm/core_cia.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + +static void +mikasa_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) + outw(~(mask >> 16), 0x536); /* note invert */ + else if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +static void +mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary registers */ + pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | + (((unsigned long) inb(0xa0)) << 8) | + ((unsigned long) inb(0x20)); + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i < 16) { + isa_device_interrupt(vector, regs); + } else { + handle_irq(i, i, regs); + } + } + restore_flags(flags); +} + +static void __init +mikasa_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = srm_device_interrupt; + + outw(~(alpha_irq_mask >> 16), 0x536); /* note invert */ + enable_irq(2); /* enable cascade */ +} + + +/* + * PCI Fixup configuration. + * + * Summary @ 0x536: + * Bit Meaning + * 0 Interrupt Line A from slot 0 + * 1 Interrupt Line B from slot 0 + * 2 Interrupt Line C from slot 0 + * 3 Interrupt Line D from slot 0 + * 4 Interrupt Line A from slot 1 + * 5 Interrupt line B from slot 1 + * 6 Interrupt Line C from slot 1 + * 7 Interrupt Line D from slot 1 + * 8 Interrupt Line A from slot 2 + * 9 Interrupt Line B from slot 2 + *10 Interrupt Line C from slot 2 + *11 Interrupt Line D from slot 2 + *12 NCR 810 SCSI + *13 Power Supply Fail + *14 Temperature Warn + *15 Reserved + * + * The device to slot mapping looks like: + * + * Slot Device + * 6 NCR SCSI controller + * 7 Intel PCI-EISA bridge chip + * 11 PCI on board slot 0 + * 12 PCI on board slot 1 + * 13 PCI on board slot 2 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +static int __init +mikasa_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[8][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ + { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */ + }; + const long min_idsel = 6, max_idsel = 13, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static void __init +mikasa_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE,APECS_AND_LCA_DEFAULT_MEM_BASE); + common_pci_fixup(mikasa_map_irq, common_swizzle); +} + +static void __init +mikasa_primo_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(mikasa_map_irq, common_swizzle); +} + +static void +mikasa_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ +#define MCHK_NO_DEVSEL 0x205L +#define MCHK_NO_TABT 0x204L + + struct el_common *mchk_header; + struct el_apecs_procdata *mchk_procdata; + struct el_apecs_mikasa_sysdata_mcheck *mchk_sysdata; + unsigned long *ptr; + int i; + + mchk_header = (struct el_common *)la_ptr; + + mchk_procdata = (struct el_apecs_procdata *) + (la_ptr + mchk_header->proc_offset + - sizeof(mchk_procdata->paltemp)); + + mchk_sysdata = (struct el_apecs_mikasa_sysdata_mcheck *) + (la_ptr + mchk_header->sys_offset); + +#ifdef DEBUG + printk("mikasa_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr); + printk(" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset); + printk("mikasa_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + apecs_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear); + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + } +#endif + + /* + * Check if machine check is due to a badaddr() and if so, + * ignore the machine check. + */ + + if (apecs_mcheck_expected + && ((unsigned int)mchk_header->code == MCHK_NO_DEVSEL + || (unsigned int)mchk_header->code == MCHK_NO_TABT)) { + apecs_mcheck_expected = 0; + apecs_mcheck_taken = 1; + mb(); + mb(); /* magic */ + apecs_pci_clr_err(); + wrmces(0x7); + mb(); + draina(); + } + else if (vector == 0x620 || vector == 0x630) { + /* Disable correctable from now on. */ + wrmces(0x1f); + mb(); + draina(); + printk("mikasa_machine_check: HW correctable (0x%lx)\n", + vector); + } + else { + printk(KERN_CRIT "APECS machine check:\n"); + printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr); + printk(KERN_CRIT + " pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset); + printk(KERN_CRIT " expected %d DCSR 0x%lx PEAR 0x%lx\n", + apecs_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear); + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(KERN_CRIT " +%lx %lx %lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); + } +#if 0 + /* doesn't work with MILO */ + show_regs(regs); +#endif + } +} + + +/* + * The System Vector + */ + +#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) +struct alpha_machine_vector mikasa_mv __initmv = { + vector_name: "Mikasa", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + DO_APECS_BUS, + machine_check: mikasa_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 32, + irq_probe_mask: _PROBE_MASK(32), + update_irq_hw: mikasa_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: mikasa_device_interrupt, + + init_arch: apecs_init_arch, + init_irq: mikasa_init_irq, + init_pit: generic_init_pit, + pci_fixup: mikasa_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(mikasa) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO) +struct alpha_machine_vector mikasa_primo_mv __initmv = { + vector_name: "Mikasa-Primo", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: mikasa_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 32, + irq_probe_mask: _PROBE_MASK(32), + update_irq_hw: mikasa_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: mikasa_device_interrupt, + + init_arch: cia_init_arch, + init_irq: mikasa_init_irq, + init_pit: generic_init_pit, + pci_fixup: mikasa_primo_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(mikasa_primo) +#endif diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c new file mode 100644 index 000000000..c8901ae2f --- /dev/null +++ b/arch/alpha/kernel/sys_noritake.c @@ -0,0 +1,301 @@ +/* + * linux/arch/alpha/kernel/sys_noritake.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the NORITAKE (AlphaServer 1000A), + * CORELLE (AlphaServer 800), and ALCOR Primo (AlphaStation 600A). + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_apecs.h> +#include <asm/core_cia.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +noritake_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq <= 15) + if (irq <= 7) + outb(mask, 0x21); /* ISA PIC1 */ + else + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else if (irq <= 31) + outw(~(mask >> 16), 0x54a); + else + outw(~(mask >> 32), 0x54c); +} + +static void +noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary registers of NORITAKE */ + pld = ((unsigned long) inw(0x54c) << 32) | + ((unsigned long) inw(0x54a) << 16) | + ((unsigned long) inb(0xa0) << 8) | + ((unsigned long) inb(0x20)); + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i < 16) { + isa_device_interrupt(vector, regs); + } else { + handle_irq(i, i, regs); + } + } + restore_flags(flags); +} + +static void +noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + /* + * I really hate to do this, too, but the NORITAKE SRM console also + * reports PCI vectors *lower* than I expected from the bit numbers + * in the documentation. + * But I really don't want to change the fixup code for allocation + * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which + * look nice and clean now. + * So, here's this additional grotty hack... :-( + */ + if (irq >= 16) + ack = irq = irq + 1; + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void __init +noritake_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = noritake_srm_device_interrupt; + + outw(~(alpha_irq_mask >> 16), 0x54a); /* note invert */ + outw(~(alpha_irq_mask >> 32), 0x54c); /* note invert */ + enable_irq(2); /* enable cascade */ +} + + +/* + * PCI Fixup configuration. + * + * Summary @ 0x542, summary register #1: + * Bit Meaning + * 0 All valid ints from summary regs 2 & 3 + * 1 QLOGIC ISP1020A SCSI + * 2 Interrupt Line A from slot 0 + * 3 Interrupt Line B from slot 0 + * 4 Interrupt Line A from slot 1 + * 5 Interrupt line B from slot 1 + * 6 Interrupt Line A from slot 2 + * 7 Interrupt Line B from slot 2 + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line B from slot 3 + *10 Interrupt Line A from slot 4 + *11 Interrupt Line B from slot 4 + *12 Interrupt Line A from slot 5 + *13 Interrupt Line B from slot 5 + *14 Interrupt Line A from slot 6 + *15 Interrupt Line B from slot 6 + * + * Summary @ 0x544, summary register #2: + * Bit Meaning + * 0 OR of all unmasked ints in SR #2 + * 1 OR of secondary bus ints + * 2 Interrupt Line C from slot 0 + * 3 Interrupt Line D from slot 0 + * 4 Interrupt Line C from slot 1 + * 5 Interrupt line D from slot 1 + * 6 Interrupt Line C from slot 2 + * 7 Interrupt Line D from slot 2 + * 8 Interrupt Line C from slot 3 + * 9 Interrupt Line D from slot 3 + *10 Interrupt Line C from slot 4 + *11 Interrupt Line D from slot 4 + *12 Interrupt Line C from slot 5 + *13 Interrupt Line D from slot 5 + *14 Interrupt Line C from slot 6 + *15 Interrupt Line D from slot 6 + * + * The device to slot mapping looks like: + * + * Slot Device + * 7 Intel PCI-EISA bridge chip + * 8 DEC PCI-PCI bridge chip + * 11 PCI on board slot 0 + * 12 PCI on board slot 1 + * 13 PCI on board slot 2 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ + +static int __init +noritake_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[15][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + /* note: IDSELs 16, 17, and 25 are CORELLE only */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ + { -1, -1, -1, -1, -1}, /* IdSel 17, S3 Trio64 */ + { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ + { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ + { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ + { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ + { 16+2, 16+2, 16+3, 32+2, 32+3}, /* IdSel 22, slot 0 */ + { 16+4, 16+4, 16+5, 32+4, 32+5}, /* IdSel 23, slot 1 */ + { 16+6, 16+6, 16+7, 32+6, 32+7}, /* IdSel 24, slot 2 */ + { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 25, slot 3 */ + /* The following 5 are actually on PCI bus 1, which is + across the built-in bridge of the NORITAKE only. */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* IdSel 16, QLOGIC */ + { 16+8, 16+8, 16+9, 32+8, 32+9}, /* IdSel 17, slot 3 */ + {16+10, 16+10, 16+11, 32+10, 32+11}, /* IdSel 18, slot 4 */ + {16+12, 16+12, 16+13, 32+12, 32+13}, /* IdSel 19, slot 5 */ + {16+14, 16+14, 16+15, 32+14, 32+15}, /* IdSel 20, slot 6 */ + }; + const long min_idsel = 5, max_idsel = 19, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static int __init +noritake_swizzle(struct pci_dev *dev, int *pinp) +{ + int slot, pin = *pinp; + + /* Check first for the built-in bridge */ + if (PCI_SLOT(dev->bus->self->devfn) == 8) { + slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */ + } + else + { + /* Must be a card-based bridge. */ + do { + if (PCI_SLOT(dev->bus->self->devfn) == 8) { + slot = PCI_SLOT(dev->devfn) + 15; + break; + } + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ; + + /* Move up the chain of bridges. */ + dev = dev->bus->self; + /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + } while (dev->bus->self); + } + *pinp = pin; + return slot; +} + +static void __init +noritake_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE,APECS_AND_LCA_DEFAULT_MEM_BASE); + common_pci_fixup(noritake_map_irq, noritake_swizzle); +} + +static void __init +noritake_primo_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(noritake_map_irq, noritake_swizzle); +} + + +/* + * The System Vectors + */ + +#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) +struct alpha_machine_vector noritake_mv __initmv = { + vector_name: "Noritake", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + DO_APECS_BUS, + machine_check: apecs_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: _PROBE_MASK(48), + update_irq_hw: noritake_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: noritake_device_interrupt, + + init_arch: apecs_init_arch, + init_irq: noritake_init_irq, + init_pit: generic_init_pit, + pci_fixup: noritake_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(noritake) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO) +struct alpha_machine_vector noritake_primo_mv __initmv = { + vector_name: "Noritake-Primo", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: _PROBE_MASK(48), + update_irq_hw: noritake_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: noritake_device_interrupt, + + init_arch: cia_init_arch, + init_irq: noritake_init_irq, + init_pit: generic_init_pit, + pci_fixup: noritake_primo_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(noritake_primo) +#endif diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c new file mode 100644 index 000000000..0885a232a --- /dev/null +++ b/arch/alpha/kernel/sys_rawhide.c @@ -0,0 +1,195 @@ +/* + * linux/arch/alpha/kernel/sys_rawhide.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the RAWHIDE. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/pci.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_mcpcia.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 40) { + /* PCI bus 1 with builtin NCR810 SCSI */ + *(vuip)MCPCIA_INT_MASK0(1) = + (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; + mb(); + /* ... and read it back to make sure it got written. */ + *(vuip)MCPCIA_INT_MASK0(1); + } + else if (irq >= 16) { + /* PCI bus 0 with EISA bridge */ + *(vuip)MCPCIA_INT_MASK0(0) = + (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; + mb(); + /* ... and read it back to make sure it got written. */ + *(vuip)MCPCIA_INT_MASK0(0); + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + /* + * The RAWHIDE SRM console reports PCI interrupts with a vector + * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) + * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have + * it line up with the actual bit numbers from the REQ registers, + * which is how we manage the interrupts/mask. Sigh... + * + * also, PCI #1 interrupts are offset some more... :-( + */ + if (irq == 52) + ack = irq = 56; /* SCSI on PCI 1 is special */ + else { + if (irq >= 24) /* adjust all PCI interrupts down 8 */ + ack = irq = irq - 8; + if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */ + ack = irq = irq - 8; + } + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void __init +rawhide_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + /* HACK ALERT! only PCI busses 0 and 1 are used currently, + and routing is only to CPU #1*/ + + *(vuip)MCPCIA_INT_MASK0(0) = + (~((alpha_irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb(); + /* ... and read it back to make sure it got written. */ + *(vuip)MCPCIA_INT_MASK0(0); + + *(vuip)MCPCIA_INT_MASK0(1) = + (~((alpha_irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb(); + /* ... and read it back to make sure it got written. */ + *(vuip)MCPCIA_INT_MASK0(1); + + enable_irq(2); +} + +/* + * PCI Fixup configuration. + * + * Summary @ MCPCIA_PCI0_INT_REQ: + * Bit Meaning + * 0 Interrupt Line A from slot 2 PCI0 + * 1 Interrupt Line B from slot 2 PCI0 + * 2 Interrupt Line C from slot 2 PCI0 + * 3 Interrupt Line D from slot 2 PCI0 + * 4 Interrupt Line A from slot 3 PCI0 + * 5 Interrupt Line B from slot 3 PCI0 + * 6 Interrupt Line C from slot 3 PCI0 + * 7 Interrupt Line D from slot 3 PCI0 + * 8 Interrupt Line A from slot 4 PCI0 + * 9 Interrupt Line B from slot 4 PCI0 + * 10 Interrupt Line C from slot 4 PCI0 + * 11 Interrupt Line D from slot 4 PCI0 + * 12 Interrupt Line A from slot 5 PCI0 + * 13 Interrupt Line B from slot 5 PCI0 + * 14 Interrupt Line C from slot 5 PCI0 + * 15 Interrupt Line D from slot 5 PCI0 + * 16 EISA interrupt (PCI 0) or SCSI interrupt (PCI 1) + * 17-23 NA + * + * IdSel + * 1 EISA bridge (PCI bus 0 only) + * 2 PCI option slot 2 + * 3 PCI option slot 3 + * 4 PCI option slot 4 + * 5 PCI option slot 5 + * + */ + +static int __init +rawhide_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 */ + { 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */ + { 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */ + { 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */ + { 16+12, 16+12, 16+13, 16+14, 16+15} /* IdSel 5 slot 5 */ + }; + const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP; + if (irq >= 0) + irq += 24 * bus2hose[dev->bus->number]->pci_hose_index; + return irq; +} + +static void __init +rawhide_pci_fixup(void) +{ + mcpcia_pci_fixup(); + common_pci_fixup(rawhide_map_irq, common_swizzle); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector rawhide_mv __initmv = { + vector_name: "Rawhide", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_MCPCIA_IO, + DO_MCPCIA_BUS, + machine_check: mcpcia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 64, + irq_probe_mask: _PROBE_MASK(64), + update_irq_hw: rawhide_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: rawhide_srm_device_interrupt, + + init_arch: mcpcia_init_arch, + init_irq: rawhide_init_irq, + init_pit: generic_init_pit, + pci_fixup: rawhide_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(rawhide) diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c new file mode 100644 index 000000000..9d32bcb15 --- /dev/null +++ b/arch/alpha/kernel/sys_ruffian.c @@ -0,0 +1,267 @@ +/* + * linux/arch/alpha/kernel/sys_ruffian.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the RUFFIAN. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_pyxis.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + /* Note inverted sense of mask bits: */ + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & 0x00000000ffffffbfUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +ruffian_ack_irq(unsigned long irq) +{ + if (irq < 16) { + /* Ack PYXIS ISA interrupt. */ + *(vulp)PYXIS_INT_REQ = 1L << 7; mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_REQ; + if (irq > 7) { + outb(0x20, 0xa0); + } + outb(0x20, 0x20); + } else { + /* Ack PYXIS PCI interrupt. */ + *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_REQ; + } +} + +static void +ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142 (8) + * then all the PCI slots/INTXs (12-31) + * flash(5) :DWH: + */ + pld &= 0x00000000ffffff9fUL; /* was ffff7f */ + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) { + /* Copy this bit from isa_device_interrupt cause + we need to hook into int 0 for the timer. I + refuse to soil device_interrupt with ifdefs. */ + + /* Generate a PCI interrupt acknowledge cycle. + The PIC will respond with the interrupt + vector of the highest priority interrupt + that is pending. The PALcode sets up the + interrupts vectors such that irq level L + generates vector L. */ + + unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; + if (j == 7 && !(inb(0x20) & 0x80)) { + /* It's only a passive release... */ + } else if (j == 0) { + timer_interrupt(regs); + ruffian_ack_irq(0); + } else { + handle_irq(j, j, regs); + } + } else { + /* if not timer int */ + handle_irq(16 + i, 16 + i, regs); + } + + *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); + *(vulp)PYXIS_INT_REQ; /* read to force the write */ + } + restore_flags(flags); +} + +static void __init +ruffian_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + /* Invert 6&7 for i82371 */ + *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); + *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ + *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); + *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); + + outb(0x11,0xA0); + outb(0x08,0xA1); + outb(0x02,0xA1); + outb(0x01,0xA1); + outb(0xFF,0xA1); + + outb(0x11,0x20); + outb(0x00,0x21); + outb(0x04,0x21); + outb(0x01,0x21); + outb(0xFF,0x21); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) PYXIS_IACK_SC; + + /* Finish writing the 82C59A PIC Operation Control Words */ + outb(0x20,0xA0); + outb(0x20,0x20); + + /* Turn on the interrupt controller, the timer interrupt */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(0); /* enable timer */ + enable_irq(2); /* enable 2nd PIC cascade */ +} + + +/* + * For RUFFIAN, we do not want to make any modifications to the PCI + * setup. So just scan the busses. + */ + +static void __init +ruffian_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); +} + + +/* + * The DeskStation Ruffian motherboard firmware does not place + * the memory size in the PALimpure area. Therefore, we use + * the Bank Configuration Registers in PYXIS to obtain the size. + */ +static unsigned long __init +ruffian_get_bank_size(unsigned long offset) +{ + unsigned long bank_addr, bank, ret = 0; + + /* Valid offsets are: 0x800, 0x840 and 0x880 + since Ruffian only uses three banks. */ + bank_addr = (unsigned long)PYXIS_MCR + offset; + bank = *(vulp)bank_addr; + + /* Check BANK_ENABLE */ + if (bank & 0x01) { + static unsigned long size[] __initdata = { + 0x40000000UL, /* 0x00, 1G */ + 0x20000000UL, /* 0x02, 512M */ + 0x10000000UL, /* 0x04, 256M */ + 0x08000000UL, /* 0x06, 128M */ + 0x04000000UL, /* 0x08, 64M */ + 0x02000000UL, /* 0x0a, 32M */ + 0x01000000UL, /* 0x0c, 16M */ + 0x00800000UL, /* 0x0e, 8M */ + 0x80000000UL, /* 0x10, 2G */ + }; + + bank = (bank & 0x1e) >> 1; + if (bank < sizeof(size)/sizeof(*size)) + ret = size[bank]; + } + + return ret; +} + +static void __init +ruffian_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + /* FIXME: What do we do with ruffian_get_bank_size above? */ + + pyxis_enable_errors(); + if (!pyxis_srm_window_setup()) { + printk("ruffian_init_arch: Skipping window register rewrites." + "\n... Trust DeskStation firmware!\n"); + } + pyxis_finish_init_arch(); +} + + +static void +ruffian_init_pit (void) +{ + /* Ruffian depends on the system timer established in MILO! */ + request_region(0x70, 0x10, "timer"); + init_pit_rest(); +} + + +/* + * The System Vector + */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_RUFFIAN) +struct alpha_machine_vector ruffian_mv __initmv = { + vector_name: "Ruffian", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_PYXIS_IO, + DO_PYXIS_BUS, + machine_check: pyxis_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 48, + irq_probe_mask: RUFFIAN_PROBE_MASK, + update_irq_hw: ruffian_update_irq_hw, + ack_irq: ruffian_ack_irq, + device_interrupt: ruffian_device_interrupt, + + init_arch: ruffian_init_arch, + init_irq: ruffian_init_irq, + init_pit: ruffian_init_pit, + pci_fixup: ruffian_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(ruffian) +#endif diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c new file mode 100644 index 000000000..42a1f9c48 --- /dev/null +++ b/arch/alpha/kernel/sys_sable.c @@ -0,0 +1,297 @@ +/* + * linux/arch/alpha/kernel/sys_sable.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the Sable and Sable-Gamma systems. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_t2.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +/* + * For SABLE, which is really baroque, we manage 40 IRQ's, but the + * hardware really only supports 24, not via normal ISA PIC, + * but cascaded custom 8259's, etc. + * 0-7 (char at 536) + * 8-15 (char at 53a) + * 16-23 (char at 53c) + */ + +/* Note that the vector reported by the SRM PALcode corresponds to the + interrupt mask bits, but we have to manage via more normal IRQs. */ + +static struct +{ + char irq_to_mask[40]; + char mask_to_irq[40]; + unsigned long shadow_mask; +} sable_irq_swizzle = { + { + -1, 6, -1, 8, 15, 12, 7, 9, /* pseudo PIC 0-7 */ + -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */ + 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */ + }, + { + 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */ + 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */ + 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */ + }, + 0 +}; + + +static void +sable_update_irq_hw(unsigned long irq, unsigned long unused_mask, int unmask_p) +{ + unsigned long bit, mask; + + /* The "irq" argument is really the irq, but we need it to + be the mask bit number. Convert it now. */ + + irq = sable_irq_swizzle.irq_to_mask[irq]; + bit = 1UL << irq; + mask = sable_irq_swizzle.shadow_mask | bit; + if (unmask_p) + mask &= ~bit; + sable_irq_swizzle.shadow_mask = mask; + + /* The "irq" argument is now really the mask bit number. */ + if (irq <= 7) + outb(mask, 0x537); + else if (irq <= 15) + outb(mask >> 8, 0x53b); + else + outb(mask >> 16, 0x53d); +} + +static void +sable_ack_irq(unsigned long irq) +{ + /* Note that the "irq" here is really the mask bit number */ + switch (irq) { + case 0 ... 7: + outb(0xE0 | (irq - 0), 0x536); + outb(0xE0 | 1, 0x534); /* slave 0 */ + break; + case 8 ... 15: + outb(0xE0 | (irq - 8), 0x53a); + outb(0xE0 | 3, 0x534); /* slave 1 */ + break; + case 16 ... 24: + outb(0xE0 | (irq - 16), 0x53c); + outb(0xE0 | 4, 0x534); /* slave 2 */ + break; + } +} + +static void +sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + /* Note that the vector reported by the SRM PALcode corresponds + to the interrupt mask bits, but we have to manage via more + normal IRQs. */ + + int irq, ack; + unsigned long flags; + + __save_and_cli(flags); + ack = irq = (vector - 0x800) >> 4; + + irq = sable_irq_swizzle.mask_to_irq[(ack)]; +#if 0 + if (irq == 5 || irq == 9 || irq == 10 || irq == 11 || + irq == 14 || irq == 15) + printk("srm_device_interrupt: vector=0x%lx ack=0x%x" + " irq=0x%x\n", vector, ack, irq); +#endif + + handle_irq(irq, ack, regs); + __restore_flags(flags); +} + +static void __init +sable_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + outb(alpha_irq_mask , 0x537); /* slave 0 */ + outb(alpha_irq_mask >> 8, 0x53b); /* slave 1 */ + outb(alpha_irq_mask >> 16, 0x53d); /* slave 2 */ + outb(0x44, 0x535); /* enable cascades in master */ +} + + +/* + * PCI Fixup configuration for ALPHA SABLE (2100) - 2100A is different ?? + * + * Summary Registers (536/53a/53c): + * Bit Meaning + *----------------- + * 0 PCI slot 0 + * 1 NCR810 (builtin) + * 2 TULIP (builtin) + * 3 mouse + * 4 PCI slot 1 + * 5 PCI slot 2 + * 6 keyboard + * 7 floppy + * 8 COM2 + * 9 parallel port + *10 EISA irq 3 + *11 EISA irq 4 + *12 EISA irq 5 + *13 EISA irq 6 + *14 EISA irq 7 + *15 COM1 + *16 EISA irq 9 + *17 EISA irq 10 + *18 EISA irq 11 + *19 EISA irq 12 + *20 EISA irq 13 + *21 EISA irq 14 + *22 NC + *23 IIC + * + * The device to slot mapping looks like: + * + * Slot Device + * 0 TULIP + * 1 SCSI + * 2 PCI-EISA bridge + * 3 none + * 4 none + * 5 none + * 6 PCI on board slot 0 + * 7 PCI on board slot 1 + * 8 PCI on board slot 2 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ +/* + * NOTE: the IRQ assignments below are arbitrary, but need to be consistent + * with the values in the irq swizzling tables above. + */ + +static int __init +sable_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[9][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ + { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 2, SIO */ + { -1, -1, -1, -1, -1}, /* IdSel 3, none */ + { -1, -1, -1, -1, -1}, /* IdSel 4, none */ + { -1, -1, -1, -1, -1}, /* IdSel 5, none */ + { 32+2, 32+2, 32+2, 32+2, 32+2}, /* IdSel 6, slot 0 */ + { 32+3, 32+3, 32+3, 32+3, 32+3}, /* IdSel 7, slot 1 */ + { 32+4, 32+4, 32+4, 32+4, 32+4}, /* IdSel 8, slot 2 */ + }; + const long min_idsel = 0, max_idsel = 8, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +void __init +sable_pci_fixup(void) +{ + layout_all_busses(EISA_DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(sable_map_irq, common_swizzle); +} + + +/* + * The System Vectors + * + * In order that T2_HAE_ADDRESS should be a constant, we play + * these games with GAMMA_BIAS. + */ + +#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_GAMMA) +#undef GAMMA_BIAS +#define GAMMA_BIAS 0 +struct alpha_machine_vector sable_mv __initmv = { + vector_name: "Sable", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_T2_IO, + DO_T2_BUS, + machine_check: t2_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 40, + irq_probe_mask: _PROBE_MASK(40), + update_irq_hw: sable_update_irq_hw, + ack_irq: sable_ack_irq, + device_interrupt: sable_srm_device_interrupt, + + init_arch: t2_init_arch, + init_irq: sable_init_irq, + init_pit: generic_init_pit, + pci_fixup: sable_pci_fixup, + kill_arch: generic_kill_arch, + + sys: { t2: { + gamma_bias: 0 + } } +}; +ALIAS_MV(sable) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_GAMMA) +#undef GAMMA_BIAS +#define GAMMA_BIAS _GAMMA_BIAS +struct alpha_machine_vector sable_gamma_mv __initmv = { + vector_name: "Sable-Gamma", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_T2_IO, + DO_T2_BUS, + machine_check: t2_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 40, + irq_probe_mask: _PROBE_MASK(40), + update_irq_hw: sable_update_irq_hw, + ack_irq: sable_ack_irq, + device_interrupt: sable_srm_device_interrupt, + + init_arch: t2_init_arch, + init_irq: sable_init_irq, + init_pit: generic_init_pit, + pci_fixup: sable_pci_fixup, + kill_arch: generic_kill_arch, + + sys: { t2: { + gamma_bias: _GAMMA_BIAS + } } +}; +ALIAS_MV(sable_gamma) +#endif diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c new file mode 100644 index 000000000..dfd6adaa7 --- /dev/null +++ b/arch/alpha/kernel/sys_sio.c @@ -0,0 +1,470 @@ +/* + * linux/arch/alpha/kernel/sys_sio.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code for all boards that route the PCI interrupts through the SIO + * PCI/ISA bridge. This includes Noname (AXPpci33), Multia (UDB), + * Kenetics's Platform 2000, Avanti (AlphaStation), XL, and AlphaBook1. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/compiler.h> +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_apecs.h> +#include <asm/core_lca.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + +static void +sio_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 8) + outb(mask >> 8, 0xA1); + else + outb(mask, 0x21); +} + +static void __init +sio_init_irq(void) +{ + STANDARD_INIT_IRQ_PROLOG; + + if (alpha_using_srm) + alpha_mv.device_interrupt = srm_device_interrupt; + + enable_irq(2); /* enable cascade */ +} + +static inline void __init +xl_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + /* + * Set up the PCI->physical memory translation windows. For + * the XL we *must* use both windows, in order to maximize the + * amount of physical memory that can be used to DMA from the + * ISA bus, and still allow PCI bus devices access to all of + * host memory. + * + * See <asm/apecs.h> for window bases and sizes. + * + * This restriction due to the true XL motherboards' 82379AB SIO + * PCI<->ISA bridge chip which passes only 27 bits of address... + */ + + *(vuip)APECS_IOC_PB1R = 1<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U); + *(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB1R = 0; + + *(vuip)APECS_IOC_PB2R = 1<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U); + *(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U; + *(vuip)APECS_IOC_TB2R = 0; + + /* + * Finally, clear the HAXR2 register, which gets used for PCI + * Config Space accesses. That is the way we want to use it, + * and we do not want to depend on what ARC or SRM might have + * left behind... + */ + + *(vuip)APECS_IOC_HAXR2 = 0; mb(); +} + +static inline void __init +alphabook1_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + /* The AlphaBook1 has LCD video fixed at 800x600, + 37 rows and 100 cols. */ + screen_info.orig_y = 37; + screen_info.orig_video_cols = 100; + screen_info.orig_video_lines = 37; + + lca_init_arch(mem_start, mem_end); +} + + +/* + * sio_route_tab selects irq routing in PCI/ISA bridge so that: + * PIRQ0 -> irq 15 + * PIRQ1 -> irq 9 + * PIRQ2 -> irq 10 + * PIRQ3 -> irq 11 + * + * This probably ought to be configurable via MILO. For + * example, sound boards seem to like using IRQ 9. + */ +static unsigned long sio_route_tab __initdata = 0; + +static void __init +sio_pci_fixup(int (*map_irq)(struct pci_dev *dev, int sel, int pin), + unsigned long new_route_tab) +{ + unsigned int route_tab; + + /* Examine or update the PCI routing table. */ + pcibios_read_config_dword(0, PCI_DEVFN(7, 0), 0x60, &route_tab); + + sio_route_tab = route_tab; + if (PCI_MODIFY) { + sio_route_tab = new_route_tab; + pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, + new_route_tab); + } + + /* Update all the IRQs. */ + common_pci_fixup(map_irq, common_swizzle); +} + +static unsigned int __init +sio_collect_irq_levels(void) +{ + unsigned int level_bits = 0; + struct pci_dev *dev; + + /* Iterate through the devices, collecting IRQ levels. */ + for (dev = pci_devices; dev; dev = dev->next) { + if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) + continue; + + if (dev->irq) + level_bits |= (1 << dev->irq); + } + return level_bits; +} + +static void __init +sio_fixup_irq_levels(unsigned int level_bits) +{ + unsigned int old_level_bits; + + /* + * Now, make all PCI interrupts level sensitive. Notice: + * these registers must be accessed byte-wise. inw()/outw() + * don't work. + * + * Make sure to turn off any level bits set for IRQs 9,10,11,15, + * so that the only bits getting set are for devices actually found. + * Note that we do preserve the remainder of the bits, which we hope + * will be set correctly by ARC/SRM. + * + * Note: we at least preserve any level-set bits on AlphaBook1 + */ + old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8); + + level_bits |= (old_level_bits & 0x71ff); + + outb((level_bits >> 0) & 0xff, 0x4d0); + outb((level_bits >> 8) & 0xff, 0x4d1); +} + +static inline int __init +noname_map_irq(struct pci_dev *dev, int slot, int pin) +{ + /* + * The Noname board has 5 PCI slots with each of the 4 + * interrupt pins routed to different pins on the PCI/ISA + * bridge (PIRQ0-PIRQ3). The table below is based on + * information available at: + * + * http://ftp.digital.com/pub/DEC/axppci/ref_interrupts.txt + * + * I have no information on the Avanti interrupt routing, but + * the routing seems to be identical to the Noname except + * that the Avanti has an additional slot whose routing I'm + * unsure of. + * + * pirq_tab[0] is a fake entry to deal with old PCI boards + * that have the interrupt pin number hardwired to 0 (meaning + * that they use the default INTA line, if they are interrupt + * driven at all). + */ + static char irq_tab[][5] __initlocaldata = { + /*INT A B C D */ + { 3, 3, 3, 3, 3}, /* idsel 6 (53c810) */ + {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ + { 2, 2, -1, -1, -1}, /* idsel 8 (Hack: slot closest ISA) */ + {-1, -1, -1, -1, -1}, /* idsel 9 (unused) */ + {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ + { 0, 0, 2, 1, 0}, /* idsel 11 KN25_PCI_SLOT0 */ + { 1, 1, 0, 2, 1}, /* idsel 12 KN25_PCI_SLOT1 */ + { 2, 2, 1, 0, 2}, /* idsel 13 KN25_PCI_SLOT2 */ + { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */ + }; + const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP, tmp; + tmp = __kernel_extbl(sio_route_tab, irq); + return irq >= 0 ? tmp : -1; +} + +static inline void __init +noname_pci_fixup(void) +{ + /* + * For UDB, the only available PCI slot must not map to IRQ 9, + * since that's the builtin MSS sound chip. That PCI slot + * will map to PIRQ1 (for INTA at least), so we give it IRQ 15 + * instead. + * + * Unfortunately we have to do this for NONAME as well, since + * they are co-indicated when the platform type "Noname" is + * selected... :-( + */ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + sio_pci_fixup(noname_map_irq, 0x0b0a0f09); + sio_fixup_irq_levels(sio_collect_irq_levels()); + enable_ide(0x26e); +} + +static inline void __init +avanti_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + sio_pci_fixup(noname_map_irq, 0x0b0a090f); + sio_fixup_irq_levels(sio_collect_irq_levels()); + enable_ide(0x26e); +} + +static inline void __init +xl_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, XL_DEFAULT_MEM_BASE); + sio_pci_fixup(noname_map_irq, 0x0b0a090f); + sio_fixup_irq_levels(sio_collect_irq_levels()); + enable_ide(0x26e); +} + +static inline int __init +p2k_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[][5] __initlocaldata = { + /*INT A B C D */ + { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ + {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ + { 1, 1, 2, 3, 0}, /* idsel 8 (slot A) */ + { 2, 2, 3, 0, 1}, /* idsel 9 (slot B) */ + {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ + {-1, -1, -1, -1, -1}, /* idsel 11 (unused) */ + { 3, 3, -1, -1, -1}, /* idsel 12 (CMD0646) */ + }; + const long min_idsel = 6, max_idsel = 12, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP, tmp; + tmp = __kernel_extbl(sio_route_tab, irq); + return irq >= 0 ? tmp : -1; +} + +static inline void __init +p2k_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + sio_pci_fixup(p2k_map_irq, 0x0b0a090f); + sio_fixup_irq_levels(sio_collect_irq_levels()); + enable_ide(0x26e); +} + +static inline void __init +alphabook1_pci_fixup(void) +{ + struct pci_dev *dev; + unsigned char orig, config; + + layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); + + /* For the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15. */ + sio_pci_fixup(noname_map_irq, 0x0e0f0a0a); + + /* + * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) + * is sensitive to PCI bus bursts, so we must DISABLE + * burst mode for the NCR 8xx SCSI... :-( + * + * Note that the NCR810 SCSI driver must preserve the + * setting of the bit in order for this to work. At the + * moment (2.0.29), ncr53c8xx.c does NOT do this, but + * 53c7,8xx.c DOES. + */ + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->vendor == PCI_VENDOR_ID_NCR && + (dev->device == PCI_DEVICE_ID_NCR_53C810 || + dev->device == PCI_DEVICE_ID_NCR_53C815 || + dev->device == PCI_DEVICE_ID_NCR_53C820 || + dev->device == PCI_DEVICE_ID_NCR_53C825)) { + unsigned int io_port; + unsigned char ctest4; + + pcibios_read_config_dword(dev->bus->number, + dev->devfn, + PCI_BASE_ADDRESS_0, + &io_port); + io_port &= PCI_BASE_ADDRESS_IO_MASK; + ctest4 = inb(io_port+0x21); + if (!(ctest4 & 0x80)) { + printk("AlphaBook1 NCR init: setting" + " burst disable\n"); + outb(ctest4 | 0x80, io_port+0x21); + } + } + } + + /* Do not set *ANY* level triggers for AlphaBook1. */ + sio_fixup_irq_levels(0); + + /* Make sure that register PR1 indicates 1Mb mem */ + outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */ + outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */ + outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */ + if ((config & 0xc0) != 0xc0) { + printk("AlphaBook1 VGA init: setting 1Mb memory\n"); + config |= 0xc0; + outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */ + } + outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */ +} + + +/* + * The System Vectors + */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_BOOK1) +struct alpha_machine_vector alphabook1_mv __initmv = { + vector_name: "AlphaBook1", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_LCA_IO, + DO_LCA_BUS, + machine_check: lca_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: _PROBE_MASK(16), + update_irq_hw: sio_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: isa_device_interrupt, + + init_arch: alphabook1_init_arch, + init_irq: sio_init_irq, + init_pit: generic_init_pit, + pci_fixup: alphabook1_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(alphabook1) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_AVANTI) +struct alpha_machine_vector avanti_mv __initmv = { + vector_name: "Avanti", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + DO_APECS_BUS, + machine_check: apecs_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: _PROBE_MASK(16), + update_irq_hw: sio_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: isa_device_interrupt, + + init_arch: apecs_init_arch, + init_irq: sio_init_irq, + init_pit: generic_init_pit, + pci_fixup: avanti_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(avanti) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_NONAME) +struct alpha_machine_vector noname_mv __initmv = { + vector_name: "Noname", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_LCA_IO, + DO_LCA_BUS, + machine_check: lca_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: _PROBE_MASK(16), + update_irq_hw: sio_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: srm_device_interrupt, + + init_arch: lca_init_arch, + init_irq: sio_init_irq, + init_pit: generic_init_pit, + pci_fixup: noname_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(noname) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_P2K) +struct alpha_machine_vector p2k_mv __initmv = { + vector_name: "Platform2000", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_LCA_IO, + DO_LCA_BUS, + machine_check: lca_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: P2K_PROBE_MASK, + update_irq_hw: sio_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: srm_device_interrupt, + + init_arch: lca_init_arch, + init_irq: sio_init_irq, + init_pit: generic_init_pit, + pci_fixup: p2k_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(p2k) +#endif + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XL) +struct alpha_machine_vector xl_mv __initmv = { + vector_name: "XL", + DO_EV4_MMU, + DO_DEFAULT_RTC, + DO_APECS_IO, + BUS(apecs_xl), + machine_check: apecs_machine_check, + max_dma_address: ALPHA_XL_MAX_DMA_ADDRESS, + + nr_irqs: 16, + irq_probe_mask: _PROBE_MASK(16), + update_irq_hw: sio_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: isa_device_interrupt, + + init_arch: xl_init_arch, + init_irq: sio_init_irq, + init_pit: generic_init_pit, + pci_fixup: xl_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(xl) +#endif diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c new file mode 100644 index 000000000..1219b9626 --- /dev/null +++ b/arch/alpha/kernel/sys_sx164.c @@ -0,0 +1,217 @@ +/* + * linux/arch/alpha/kernel/sys_sx164.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the SX164 (PCA56+PYXIS). + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_pyxis.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +sx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + /* Make CERTAIN none of the bogus ints get enabled */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x000000000000003bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +sx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + if (unmask_p) + cserve_ena(irq - 16); + else + cserve_dis(irq - 16); + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +sx164_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld, tmp; + unsigned int i; + unsigned long flags; + + save_and_cli(flags); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* + * For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7) + * then all the PCI slots/INTXs (8-23) + */ + /* Maybe HALT should only be used for SRM console boots? */ + pld &= 0x0000000000ffffc0UL; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) { + isa_device_interrupt(vector, regs); + } else if (i == 6) { + continue; + } else { + /* if not timer int */ + handle_irq(16 + i, 16 + i, regs); + } + *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); + tmp = *(vulp)PYXIS_INT_REQ; + } + restore_flags(flags); +} + +static void +sx164_init_irq(void) +{ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + + if (alpha_using_srm) { + alpha_mv.update_irq_hw = sx164_srm_update_irq_hw; + alpha_mv.device_interrupt = srm_device_interrupt; + } + else { + /* Note invert on MASK bits. */ + *(vulp)PYXIS_INT_MASK = ~((long)alpha_irq_mask >> 16); + mb(); + *(vulp)PYXIS_INT_MASK; + } + + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} + +/* + * PCI Fixup configuration. + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 RSVD + * 1 NMI + * 2 Halt/Reset switch + * 3 MBZ + * 4 RAZ + * 5 RAZ + * 6 Interval timer (RTC) + * 7 PCI-ISA Bridge + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line A from slot 2 + *10 Interrupt Line A from slot 1 + *11 Interrupt Line A from slot 0 + *12 Interrupt Line B from slot 3 + *13 Interrupt Line B from slot 2 + *14 Interrupt Line B from slot 1 + *15 Interrupt line B from slot 0 + *16 Interrupt Line C from slot 3 + *17 Interrupt Line C from slot 2 + *18 Interrupt Line C from slot 1 + *19 Interrupt Line C from slot 0 + *20 Interrupt Line D from slot 3 + *21 Interrupt Line D from slot 2 + *22 Interrupt Line D from slot 1 + *23 Interrupt Line D from slot 0 + * + * IdSel + * 5 32 bit PCI option slot 2 + * 6 64 bit PCI option slot 0 + * 7 64 bit PCI option slot 1 + * 8 Cypress I/O + * 9 32 bit PCI option slot 3 + * + */ + +static int __init +sx164_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[5][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */ + { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */ + { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */ + { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */ + { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */ + }; + const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +void __init +sx164_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(sx164_map_irq, common_swizzle); + SMC669_Init(); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector sx164_mv __initmv = { + vector_name: "SX164", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_PYXIS_IO, + DO_PYXIS_BUS, + machine_check: pyxis_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 40, + irq_probe_mask: _PROBE_MASK(40), + update_irq_hw: sx164_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: sx164_device_interrupt, + + init_arch: pyxis_init_arch, + init_irq: sx164_init_irq, + init_pit: generic_init_pit, + pci_fixup: sx164_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(sx164) diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c new file mode 100644 index 000000000..326fd6409 --- /dev/null +++ b/arch/alpha/kernel/sys_takara.c @@ -0,0 +1,165 @@ +/* + * linux/arch/alpha/kernel/sys_takara.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the TAKARA. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/core_cia.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +/* + * WARNING WARNING WARNING + * + * This port is missing an update_irq_hw implementation. + */ + +static void +takara_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long flags; + unsigned intstatus; + + save_and_cli(flags); + + /* + * The PALcode will have passed us vectors 0x800 or 0x810, + * which are fairly arbitrary values and serve only to tell + * us whether an interrupt has come in on IRQ0 or IRQ1. If + * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's + * probably ISA, but PCI interrupts can come through IRQ0 + * as well if the interrupt controller isn't in accelerated + * mode. + * + * OTOH, the accelerator thing doesn't seem to be working + * overly well, so what we'll do instead is try directly + * examining the Master Interrupt Register to see if it's a + * PCI interrupt, and if _not_ then we'll pass it on to the + * ISA handler. + */ + + intstatus = inw(0x500) & 15; + if (intstatus) { + /* + * This is a PCI interrupt. Check each bit and + * despatch an interrupt if it's set. + */ + + if (intstatus & 8) handle_irq(16+3, 16+3, regs); + if (intstatus & 4) handle_irq(16+2, 16+2, regs); + if (intstatus & 2) handle_irq(16+1, 16+1, regs); + if (intstatus & 1) handle_irq(16+0, 16+0, regs); + } else + isa_device_interrupt (vector, regs); + + restore_flags(flags); +} + +static void __init +takara_init_irq(void) +{ + unsigned int ctlreg; + + STANDARD_INIT_IRQ_PROLOG; + + ctlreg = inl(0x500); + ctlreg &= ~0x8000; /* return to non-accelerated mode */ + outw(ctlreg >> 16, 0x502); + outw(ctlreg & 0xFFFF, 0x500); + ctlreg = 0x05107c00; /* enable the PCI interrupt register */ + outw(ctlreg >> 16, 0x502); + outw(ctlreg & 0xFFFF, 0x500); + enable_irq(2); +} + + +/* + * The Takara has PCI devices 1, 2, and 3 configured to slots 20, + * 19, and 18 respectively, in the default configuration. They can + * also be jumpered to slots 8, 7, and 6 respectively, which is fun + * because the SIO ISA bridge can also be slot 7. However, the SIO + * doesn't explicitly generate PCI-type interrupts, so we can + * assign it whatever the hell IRQ we like and it doesn't matter. + */ + +static int __init +takara_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[15][5] __initlocaldata = { + { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 6 == device 3 */ + { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 7 == device 2 */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 8 == device 1 */ + { -1, -1, -1, -1, -1}, /* slot 9 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 10 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 11 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 12 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 13 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 14 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 15 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 16 == nothing */ + { -1, -1, -1, -1, -1}, /* slot 17 == nothing */ + { 16+3, 16+3, 16+3, 16+3, 16+3}, /* slot 18 == device 3 */ + { 16+2, 16+2, 16+2, 16+2, 16+2}, /* slot 19 == device 2 */ + { 16+1, 16+1, 16+1, 16+1, 16+1}, /* slot 20 == device 1 */ + }; + const long min_idsel = 6, max_idsel = 20, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; +} + +static void __init +takara_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(takara_map_irq, common_swizzle); + enable_ide(0x26e); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector takara_mv __initmv = { + vector_name: "Takara", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_CIA_IO, + DO_CIA_BUS, + machine_check: cia_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 20, + irq_probe_mask: _PROBE_MASK(20), + update_irq_hw: NULL, + ack_irq: generic_ack_irq, + device_interrupt: takara_device_interrupt, + + init_arch: cia_init_arch, + init_irq: takara_init_irq, + init_pit: generic_init_pit, + pci_fixup: takara_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(takara) diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 0456eb171..b1c1a9410 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -57,7 +57,7 @@ static struct { __u32 last_time; /* ticks/cycle * 2^48 */ unsigned long scaled_ticks_per_cycle; - /* last time the cmos clock got updated */ + /* last time the CMOS clock got updated */ time_t last_rtc_update; } state; diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 42790d3aa..c2fc4c8e6 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -13,15 +13,17 @@ #include <linux/sched.h> #include <linux/tty.h> #include <linux/delay.h> +#include <linux/smp_lock.h> #include <asm/gentrap.h> #include <asm/uaccess.h> #include <asm/unaligned.h> #include <asm/sysinfo.h> -#include <asm/smp_lock.h> +#include "proto.h" -static void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) +static void +dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) { printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", regs->pc, regs->r26, regs->ps); @@ -51,7 +53,8 @@ static void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15) printk("gp = %016lx sp = %p\n", regs->gp, regs+1); } -static void dik_show_code(unsigned int *pc) +static void +dik_show_code(unsigned int *pc) { long i; @@ -65,7 +68,8 @@ static void dik_show_code(unsigned int *pc) printk("\n"); } -static void dik_show_trace(unsigned long *sp) +static void +dik_show_trace(unsigned long *sp) { long i = 0; printk("Trace:"); @@ -86,8 +90,8 @@ static void dik_show_trace(unsigned long *sp) printk("\n"); } -void die_if_kernel(char * str, struct pt_regs *regs, long err, - unsigned long *r9_15) +void +die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15) { if (regs->ps & 8) return; @@ -106,21 +110,20 @@ void die_if_kernel(char * str, struct pt_regs *regs, long err, } #ifndef CONFIG_MATHEMU -static long dummy_alpha_fp_emul_imprecise(struct pt_regs *r, unsigned long wm) -{ - return 0; -} - +static long dummy_emul() { return 0; } long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask) - = dummy_alpha_fp_emul_imprecise; + = (void *)dummy_emul; +long (*alpha_fp_emul) (unsigned long pc) + = (void *)dummy_emul; #else long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask); +long alpha_fp_emul (unsigned long pc); #endif -asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask, - unsigned long a2, unsigned long a3, - unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage void +do_entArith(unsigned long summary, unsigned long write_mask, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { if ((summary & 1)) { /* @@ -133,8 +136,10 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask, } lock_kernel(); +#if 0 printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", current->comm, regs.pc, summary, write_mask); +#endif die_if_kernel("Arithmetic fault", ®s, 0, 0); force_sig(SIGFPE, current); unlock_kernel(); @@ -202,7 +207,6 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, case 4: /* opDEC */ #ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION { - extern long alpha_fp_emul (unsigned long pc); unsigned int opcode; /* get opcode of faulting instruction: */ @@ -255,9 +259,10 @@ struct unaligned_stat { #define una_reg(r) (regs.regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)]) -asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg, - unsigned long a3, unsigned long a4, unsigned long a5, - struct allregs regs) +asmlinkage void +do_entUna(void * va, unsigned long opcode, unsigned long reg, + unsigned long a3, unsigned long a4, unsigned long a5, + struct allregs regs) { long error, tmp1, tmp2, tmp3, tmp4; unsigned long pc = regs.pc - 4; @@ -497,7 +502,8 @@ got_exception: * needs to be remapped to preserve non-finite values * (infinities, not-a-numbers, denormals). */ -static inline unsigned long s_mem_to_reg (unsigned long s_mem) +static inline unsigned long +s_mem_to_reg (unsigned long s_mem) { unsigned long frac = (s_mem >> 0) & 0x7fffff; unsigned long sign = (s_mem >> 31) & 0x1; @@ -524,7 +530,8 @@ static inline unsigned long s_mem_to_reg (unsigned long s_mem) * Convert an s-floating point value in register format to the * corresponding value in memory format. */ -static inline unsigned long s_reg_to_mem (unsigned long s_reg) +static inline unsigned long +s_reg_to_mem (unsigned long s_reg) { return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34); } @@ -571,12 +578,10 @@ static int unauser_reg_offsets[32] = { #undef R -asmlinkage void do_entUnaUser(void * va, unsigned long opcode, - unsigned long reg, struct pt_regs *regs) +asmlinkage void +do_entUnaUser(void * va, unsigned long opcode, + unsigned long reg, struct pt_regs *regs) { - extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); - extern unsigned long alpha_read_fp_reg (unsigned long reg); - static int cnt = 0; static long last_time = 0; @@ -868,10 +873,10 @@ give_sigbus: /* * Unimplemented system calls. */ -asmlinkage long alpha_ni_syscall(unsigned long a0, unsigned long a1, - unsigned long a2, unsigned long a3, - unsigned long a4, unsigned long a5, - struct pt_regs regs) +asmlinkage long +alpha_ni_syscall(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { /* We only get here for OSF system calls, minus #112; the rest go to sys_ni_syscall. */ @@ -879,17 +884,11 @@ asmlinkage long alpha_ni_syscall(unsigned long a0, unsigned long a1, return -ENOSYS; } -extern asmlinkage void entMM(void); -extern asmlinkage void entIF(void); -extern asmlinkage void entArith(void); -extern asmlinkage void entUna(void); -extern asmlinkage void entSys(void); - -register unsigned long gptr __asm__("$29"); - -void trap_init(void) +void +trap_init(void) { /* Tell PAL-code what global pointer we want in the kernel. */ + register unsigned long gptr __asm__("$29"); wrkgp(gptr); wrent(entArith, 1); diff --git a/arch/alpha/kernel/tsunami.c b/arch/alpha/kernel/tsunami.c deleted file mode 100644 index 3d0fdde89..000000000 --- a/arch/alpha/kernel/tsunami.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Code common to all TSUNAMI chips. - * - * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). - * - */ -#include <linux/kernel.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/sched.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/hwrpb.h> -#include <asm/ptrace.h> -#include <asm/mmu_context.h> - -/* - * NOTE: Herein lie back-to-back mb instructions. They are magic. - * One plausible explanation is that the i/o controller does not properly - * handle the system transaction. Another involves timing. Ho hum. - */ - -extern struct hwrpb_struct *hwrpb; -extern asmlinkage void wrmces(unsigned long mces); - -/* - * BIOS32-style PCI interface: - */ - -#ifdef CONFIG_ALPHA_TSUNAMI - -#ifdef DEBUG -# define DBG(args) printk args -#else -# define DBG(args) -#endif - -#define DEBUG_MCHECK -#ifdef DEBUG_MCHECK -# define DBG_MCK(args) printk args -#define DEBUG_MCHECK_DUMP -#else -# define DBG_MCK(args) -#endif - -#define vuip volatile unsigned int * -#define vulp volatile unsigned long * - -static volatile unsigned int TSUNAMI_mcheck_expected[NR_CPUS]; -static volatile unsigned int TSUNAMI_mcheck_taken[NR_CPUS]; -static unsigned int TSUNAMI_jd[NR_CPUS]; - -#ifdef CONFIG_ALPHA_SRM_SETUP -unsigned int TSUNAMI_DMA_WIN_BASE = TSUNAMI_DMA_WIN_BASE_DEFAULT; -unsigned int TSUNAMI_DMA_WIN_SIZE = TSUNAMI_DMA_WIN_SIZE_DEFAULT; -#endif /* SRM_SETUP */ - -/* - * Given a bus, device, and function number, compute resulting - * configuration space address - * accordingly. It is therefore not safe to have concurrent - * invocations to configuration space access routines, but there - * really shouldn't be any need for this. - * - * Note that all config space accesses use Type 1 address format. - * - * Note also that type 1 is determined by non-zero bus number. - * - * Type 1: - * - * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 - * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 31:24 reserved - * 23:16 bus number (8 bits = 128 possible buses) - * 15:11 Device number (5 bits) - * 10:8 function number - * 7:2 register number - * - * Notes: - * The function number selects which function of a multi-function device - * (e.g., scsi and ethernet). - * - * The register selects a DWORD (32 bit) register offset. Hence it - * doesn't get shifted by 2 bits as we want to "drop" the bottom two - * bits. - */ -static int mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr, - unsigned char *type1) -{ - unsigned long addr; - - DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); - - if (bus == 0) { - *type1 = 0; - } else { - /* type 1 configuration cycle: */ - *type1 = 1; - } - addr = (bus << 16) | (device_fn << 8) | (where); - *pci_addr = addr; - DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); - return 0; -} - -int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) -{ - unsigned long addr; - unsigned char type1; - unsigned char result; - - *value = 0xff; - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "ldbu %0,%1" - : "=r" (result) - : "m" (*(unsigned char *)(addr+TSUNAMI_PCI0_CONF))); - - *value = result; - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) -{ - unsigned long addr; - unsigned char type1; - unsigned short result; - - *value = 0xffff; - - if (where & 0x1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "ldwu %0,%1" - : "=r" (result) - : "m" (*(unsigned short *)(addr+TSUNAMI_PCI0_CONF))); - - *value = result; - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int *value) -{ - unsigned long addr; - unsigned char type1; - unsigned int result; - - *value = 0xffffffff; - if (where & 0x3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "ldl %0,%1" - : "=r" (result) - : "m" (*(unsigned int *)(addr+TSUNAMI_PCI0_CONF))); - - *value = result; - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) -{ - unsigned long addr; - unsigned char type1; - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "stb %1,%0\n\t" - "mb" - : : "m" (*(unsigned char *)(addr+TSUNAMI_PCI0_CONF)), - "r" (value)); - - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) -{ - unsigned long addr; - unsigned char type1; - - if (where & 0x1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "stw %1,%0\n\t" - "mb" - : : "m" (*(unsigned short *)(addr+TSUNAMI_PCI0_CONF)), - "r" (value)); - - return PCIBIOS_SUCCESSFUL; -} - - -int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned int value) -{ - unsigned long addr; - unsigned char type1; - - if (where & 0x3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) { - return PCIBIOS_SUCCESSFUL; - } - - __asm__ __volatile__ ( - "stl %1,%0\n\t" - "mb" - : : "m" (*(unsigned int *)(addr+TSUNAMI_PCI0_CONF)), - "r" (value)); - - return PCIBIOS_SUCCESSFUL; -} - - -unsigned long tsunami_init(unsigned long mem_start, unsigned long mem_end) -{ - unsigned long tsunami_err; - unsigned int i; - -#if 0 -printk("tsunami_init: CChip registers:\n"); -printk("tsunami_init: CSR_CSC 0x%lx\n", *(vulp)TSUNAMI_CSR_CSC); -printk("tsunami_init: CSR_MTR 0x%lx\n", *(vulp)TSUNAMI_CSR_MTR); -printk("tsunami_init: CSR_MISC 0x%lx\n", *(vulp)TSUNAMI_CSR_MISC); -printk("tsunami_init: CSR_DIM0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM0); -printk("tsunami_init: CSR_DIM1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM1); -printk("tsunami_init: CSR_DIR0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR0); -printk("tsunami_init: CSR_DIR1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR1); -printk("tsunami_init: CSR_DRIR 0x%lx\n", *(vulp)TSUNAMI_CSR_DRIR); - -printk("tsunami_init: DChip registers:\n"); -printk("tsunami_init: CSR_DSC 0x%lx\n", *(vulp)TSUNAMI_CSR_DSC); -printk("tsunami_init: CSR_STR 0x%lx\n", *(vulp)TSUNAMI_CSR_STR); -printk("tsunami_init: CSR_DREV 0x%lx\n", *(vulp)TSUNAMI_CSR_DREV); - -printk("tsunami_init: PChip registers:\n"); -printk("tsunami_init: PCHIP0_WSBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA0); -printk("tsunami_init: PCHIP0_WSBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA1); -printk("tsunami_init: PCHIP0_WSBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA2); -printk("tsunami_init: PCHIP0_WSBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA3); -printk("tsunami_init: PCHIP0_WSM0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM0); -printk("tsunami_init: PCHIP0_WSM1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM1); -printk("tsunami_init: PCHIP0_WSM2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM2); -printk("tsunami_init: PCHIP0_WSM3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM3); -printk("tsunami_init: PCHIP0_TBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA0); -printk("tsunami_init: PCHIP0_TBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA1); -printk("tsunami_init: PCHIP0_TBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA2); -printk("tsunami_init: PCHIP0_TBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA3); - -printk("tsunami_init: PCHIP0_PCTL 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PCTL); -printk("tsunami_init: PCHIP0_PLAT 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PLAT); -printk("tsunami_init: PCHIP0_PERROR 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERROR); -printk("tsunami_init: PCHIP0_PERRMASK 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERRMASK); - -#endif - - for (i = 0; i < NR_CPUS; i++) { - TSUNAMI_mcheck_expected[i] = 0; - TSUNAMI_mcheck_taken[i] = 0; - } -#ifdef NOT_YET - /* - * Set up error reporting. Make sure CPU_PE is OFF in the mask. - */ - tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK; - tsunami_err &= ~20; - *(vulp)TSUNAMI_PCHIP0_PERRMASK = tsunami_err; - mb(); - tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK; - - tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ; - tsunami_err |= 0x40; /* master/target abort */ - *(vulp)TSUNAMI_PCHIP0_PERROR = tsunami_err ; - mb() ; - tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ; -#endif /* NOT_YET */ - -#ifdef CONFIG_ALPHA_SRM_SETUP - /* check window 0 for enabled and mapped to 0 */ - if (((*(vulp)TSUNAMI_PCHIP0_WSBA0 & 3) == 1) && - (*(vulp)TSUNAMI_PCHIP0_TBA0 == 0) && - ((*(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U) > 0x0ff00000U)) - { - TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA0 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("tsunami_init: using Window 0 settings\n"); - printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vulp)TSUNAMI_PCHIP0_WSBA0, - *(vulp)TSUNAMI_PCHIP0_WSM0, - *(vulp)TSUNAMI_PCHIP0_TBA0); -#endif - } - else /* check window 1 for enabled and mapped to 0 */ - if (((*(vulp)TSUNAMI_PCHIP0_WSBA1 & 3) == 1) && - (*(vulp)TSUNAMI_PCHIP0_TBA1 == 0) && - ((*(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U) > 0x0ff00000U)) -{ - TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA1 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("tsunami_init: using Window 1 settings\n"); - printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vulp)TSUNAMI_PCHIP0_WSBA1, - *(vulp)TSUNAMI_PCHIP0_WSM1, - *(vulp)TSUNAMI_PCHIP0_TBA1); -#endif - } - else /* check window 2 for enabled and mapped to 0 */ - if (((*(vulp)TSUNAMI_PCHIP0_WSBA2 & 3) == 1) && - (*(vulp)TSUNAMI_PCHIP0_TSB2 == 0) && - ((*(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U) > 0x0ff00000U)) - { - TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA2 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("tsunami_init: using Window 2 settings\n"); - printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vulp)TSUNAMI_PCHIP0_WSBA2, - *(vulp)TSUNAMI_PCHIP0_WSM2, - *(vulp)TSUNAMI_PCHIP0_TSB2); -#endif - } - else /* check window 3 for enabled and mapped to 0 */ - if (((*(vulp)TSUNAMI_PCHIP0_WSBA3 & 3) == 1) && - (*(vulp)TSUNAMI_PCHIP0_TBA3 == 0) && - ((*(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U) > 0x0ff00000U)) - { - TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA3 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U; - TSUNAMI_DMA_WIN_SIZE += 0x00100000U; -#if 1 - printk("tsunami_init: using Window 3 settings\n"); - printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n", - *(vulp)TSUNAMI_PCHIP0_WSBA3, - *(vulp)TSUNAMI_PCHIP0_WSM3, - *(vulp)TSUNAMI_PCHIP0_TBA3); -#endif - } - else /* we must use our defaults which were pre-initialized... */ -#endif /* SRM_SETUP */ - { - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, we may - * want to use them to do scatter/gather DMA. Window 0 - * goes at 1 GB and is 1 GB large. - */ - - *(vulp)TSUNAMI_PCHIP0_WSBA0 = 1L | (TSUNAMI_DMA_WIN_BASE & 0xfff00000U); - *(vulp)TSUNAMI_PCHIP0_WSM0 = (TSUNAMI_DMA_WIN_SIZE - 1) & 0xfff00000UL; - *(vulp)TSUNAMI_PCHIP0_TBA0 = 0UL; - - *(vulp)TSUNAMI_PCHIP0_WSBA1 = 0UL; - *(vulp)TSUNAMI_PCHIP0_WSBA2 = 0UL; - *(vulp)TSUNAMI_PCHIP0_WSBA3 = 0UL; - mb(); - } - - /* - * check ASN in HWRPB for validity, report if bad - */ - if (hwrpb->max_asn != MAX_ASN) { - printk("TSUNAMI_init: max ASN from HWRPB is bad (0x%lx)\n", - hwrpb->max_asn); - hwrpb->max_asn = MAX_ASN; - } - - return mem_start; -} - -int tsunami_pci_clr_err(void) -{ - unsigned int cpu = smp_processor_id(); - - TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR); - DBG(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n", TSUNAMI_jd[cpu])); - *((vulp)TSUNAMI_PCHIP0_PERROR) = 0x040; mb(); - TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR); - return 0; -} - -void tsunami_machine_check(unsigned long vector, unsigned long la_ptr, - struct pt_regs * regs) -{ -#if 1 - printk("TSUNAMI machine check ignored\n") ; -#else - struct el_common *mchk_header; - struct el_TSUNAMI_sysdata_mcheck *mchk_sysdata; - unsigned int cpu = smp_processor_id(); - - mchk_header = (struct el_common *)la_ptr; - - mchk_sysdata = - (struct el_TSUNAMI_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); - -#if 0 - DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - DBG_MCK(("tsunami_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - TSUNAMI_mcheck_expected[cpu], mchk_sysdata->epic_dcsr, - mchk_sysdata->epic_pear)); -#endif -#ifdef DEBUG_MCHECK_DUMP - { - unsigned long *ptr; - int i; - - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); - } - } -#endif /* DEBUG_MCHECK_DUMP */ - /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. - */ - mb(); - mb(); /* magic */ - if (TSUNAMI_mcheck_expected[cpu]) { - DBG(("TSUNAMI machine check expected\n")); - TSUNAMI_mcheck_expected[cpu] = 0; - TSUNAMI_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - tsunami_pci_clr_err(); - wrmces(0x7); - mb(); - } -#if 1 - else { - printk("TSUNAMI machine check NOT expected\n") ; - DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - TSUNAMI_mcheck_expected[cpu] = 0; - TSUNAMI_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - tsunami_pci_clr_err(); - wrmces(0x7); - mb(); - } -#endif -#endif -} - -#endif /* CONFIG_ALPHA_TSUNAMI */ diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 7c1e37bac..4dd7d591d 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -7,7 +7,7 @@ OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ - csum_ipv6_magic.o + csum_ipv6_magic.o strcasecmp.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/alpha/lib/io.c b/arch/alpha/lib/io.c index 405a3afa8..50cc1fe05 100644 --- a/arch/alpha/lib/io.c +++ b/arch/alpha/lib/io.c @@ -3,26 +3,9 @@ * files.. */ #include <linux/kernel.h> - +#include <linux/types.h> #include <asm/io.h> -/* - * Jensen has a separate "local" and "bus" IO space for - * byte-wide IO. - */ -#ifdef __is_local - -unsigned int _bus_inb(unsigned long addr) -{ - return __bus_inb(addr); -} - -void _bus_outb(unsigned char b, unsigned long addr) -{ - __bus_outb(b, addr); -} -#endif - unsigned int _inb(unsigned long addr) { return __inb(addr); @@ -70,6 +53,10 @@ unsigned long _readl(unsigned long addr) return __readl(addr); } +unsigned long _readq(unsigned long addr) +{ + return __readq(addr); +} void _writeb(unsigned char b, unsigned long addr) { @@ -86,6 +73,11 @@ void _writel(unsigned int b, unsigned long addr) __writel(b, addr); } +void _writeq(unsigned long b, unsigned long addr) +{ + __writeq(b, addr); +} + /* * Read COUNT 8-bit bytes from port PORT into memory starting at * SRC. @@ -363,12 +355,48 @@ void outsl (unsigned long port, const void *src, unsigned long count) * Copy data from IO memory space to "real" memory space. * This needs to be optimized. */ -void _memcpy_fromio(void * to, unsigned long from, unsigned long count) +void _memcpy_fromio(void * to, unsigned long from, long count) { - while (count) { + /* Optimize co-aligned transfers. Everything else gets handled + a byte at a time. */ + + if (count >= 8 && ((long)to & 7) == (from & 7)) { + count -= 8; + do { + *(u64 *)to = readq(from); + count -= 8; + to += 8; + from += 8; + } while (count >= 0); + count += 8; + } + + if (count >= 4 && ((long)to & 3) == (from & 3)) { + count -= 4; + do { + *(u32 *)to = readl(from); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); + count += 4; + } + + if (count >= 2 && ((long)to & 1) == (from & 1)) { + count -= 2; + do { + *(u16 *)to = readw(from); + count -= 2; + to += 2; + from += 2; + } while (count >= 0); + count += 2; + } + + while (count > 0) { + *(u8 *) to = readb(from); count--; - *(char *) to = readb(from); - ((char *) to)++; + to++; from++; } } @@ -377,25 +405,105 @@ void _memcpy_fromio(void * to, unsigned long from, unsigned long count) * Copy data from "real" memory space to IO memory space. * This needs to be optimized. */ -void _memcpy_toio(unsigned long to, void * from, unsigned long count) +void _memcpy_toio(unsigned long to, void * from, long count) { - while (count) { + /* Optimize co-aligned transfers. Everything else gets handled + a byte at a time. */ + + if (count >= 8 && (to & 7) == ((long)from & 7)) { + count -= 8; + do { + writeq(*(u64 *)from, to); + count -= 8; + to += 8; + from += 8; + } while (count >= 0); + count += 8; + } + + if (count >= 4 && (to & 3) == ((long)from & 3)) { + count -= 4; + do { + writel(*(u32 *)from, to); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); + count += 4; + } + + if (count >= 2 && (to & 1) == ((long)from & 1)) { + count -= 2; + do { + writew(*(u16 *)from, to); + count -= 2; + to += 2; + from += 2; + } while (count >= 0); + count += 2; + } + + while (count > 0) { + writeb(*(u8 *) from, to); count--; - writeb(*(char *) from, to); - ((char *) from)++; to++; + from++; } } /* * "memset" on IO memory space. - * This needs to be optimized. */ -void _memset_io(unsigned long dst, int c, unsigned long count) +void _memset_c_io(unsigned long to, unsigned long c, long count) { - while (count) { + /* Handle any initial odd byte */ + if (count > 0 && (to & 1)) { + writeb(c, to); + to++; count--; - writeb(c, dst); - dst++; + } + + /* Handle any initial odd halfword */ + if (count >= 2 && (to & 2)) { + writew(c, to); + to += 2; + count -= 2; + } + + /* Handle any initial odd word */ + if (count >= 4 && (to & 4)) { + writel(c, to); + to += 4; + count -= 4; + } + + /* Handle all full-sized quadwords: we're aligned (or have a small count) */ + count -= 8; + if (count >= 0) { + do { + writeq(c, to); + to += 8; + count -= 8; + } while (count >= 0); + } + count += 8; + + /* The tail is word-aligned if we still have count >= 4 */ + if (count >= 4) { + writel(c, to); + to += 4; + count -= 4; + } + + /* The tail is half-word aligned if we have count >= 2 */ + if (count >= 2) { + writew(c, to); + to += 2; + count -= 2; + } + + /* And finally, one last byte.. */ + if (count) { + writeb(c, to); } } diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S index dc2075e1f..f39197dee 100644 --- a/arch/alpha/lib/memset.S +++ b/arch/alpha/lib/memset.S @@ -18,6 +18,7 @@ .set noreorder .text .globl __memset + .globl __memsetw .globl __constant_c_memset .ent __memset .align 5 @@ -25,8 +26,8 @@ __memset: .frame $30,0,$26,0 .prologue 0 - zapnot $17,1,$17 /* E0 */ - sll $17,8,$1 /* E1 (p-c latency, next cycle) */ + and $17,255,$1 /* E1 */ + insbl $17,1,$17 /* .. E0 */ bis $17,$1,$17 /* E0 (p-c latency, next cycle) */ sll $17,16,$1 /* E1 (p-c latency, next cycle) */ @@ -52,9 +53,9 @@ __constant_c_memset: insql $17,$16,$2 /* E0 */ subq $3,8,$3 /* .. E1 */ - addq $18,$3,$18 /* E0 $18 is new count ($3 is negative) */ + addq $18,$3,$18 /* E0 $18 is new count ($3 is negative) */ mskql $4,$16,$4 /* .. E1 (and possible load stall) */ - subq $16,$3,$16 /* E0 $16 is new aligned destination */ + subq $16,$3,$16 /* E0 $16 is new aligned destination */ bis $2,$4,$1 /* .. E1 */ bis $31,$31,$31 /* E0 */ @@ -103,6 +104,22 @@ end: ret $31,($26),1 /* E1 */ .end __memset + .align 5 + .ent __memsetw +__memsetw: + .prologue 0 + + inswl $17,0,$1 /* E0 */ + inswl $17,2,$2 /* E0 */ + inswl $17,4,$3 /* E0 */ + or $1,$2,$1 /* .. E1 */ + inswl $17,6,$4 /* E0 */ + or $1,$3,$1 /* .. E1 */ + or $1,$4,$17 /* E0 */ + br __constant_c_memset /* .. E1 */ + + .end __memsetw + #ifdef __ELF__ .weak memset; memset = __memset #else diff --git a/arch/alpha/lib/strcasecmp.c b/arch/alpha/lib/strcasecmp.c new file mode 100644 index 000000000..4e57a216f --- /dev/null +++ b/arch/alpha/lib/strcasecmp.c @@ -0,0 +1,26 @@ +/* + * linux/arch/alpha/lib/strcasecmp.c + */ + +#include <linux/string.h> + + +/* We handle nothing here except the C locale. Since this is used in + only one place, on strings known to contain only 7 bit ASCII, this + is ok. */ + +int strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } while (ca == cb && ca != '\0'); + + return ca - cb; +} diff --git a/arch/alpha/lib/strlen_user.S b/arch/alpha/lib/strlen_user.S index b84d9a4c3..cdf71158f 100644 --- a/arch/alpha/lib/strlen_user.S +++ b/arch/alpha/lib/strlen_user.S @@ -2,7 +2,7 @@ * arch/alpha/lib/strlen_user.S * * Return the length of the string including the NUL terminator - * (strlen+1) or zero if an error occured. + * (strlen+1) or zero if an error occurred. */ #include <alpha/regdef.h> diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c index 543044019..97f4bc326 100644 --- a/arch/alpha/math-emu/fp-emul.c +++ b/arch/alpha/math-emu/fp-emul.c @@ -61,22 +61,33 @@ extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); MODULE_DESCRIPTION("FP Software completion module"); extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); -static long (*save_emul)(struct pt_regs *, unsigned long); +extern long (*alpha_fp_emul) (unsigned long pc); + +static long (*save_emul_imprecise)(struct pt_regs *, unsigned long); +static long (*save_emul) (unsigned long pc); + long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); +long do_alpha_fp_emul(unsigned long); int init_module(void) { - save_emul = alpha_fp_emul_imprecise; + save_emul_imprecise = alpha_fp_emul_imprecise; + save_emul = alpha_fp_emul; alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; + alpha_fp_emul = do_alpha_fp_emul; return 0; } void cleanup_module(void) { - alpha_fp_emul_imprecise = save_emul; + alpha_fp_emul_imprecise = save_emul_imprecise; + alpha_fp_emul = save_emul; } -#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise +#undef alpha_fp_emul_imprecise +#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise +#undef alpha_fp_emul +#define alpha_fp_emul do_alpha_fp_emul #endif /* MODULE */ @@ -95,6 +106,8 @@ alpha_fp_emul (unsigned long pc) unsigned long va, vb, vc, res, fpcr; __u32 insn; + MOD_INC_USE_COUNT; + get_user(insn, (__u32*)pc); fc = (insn >> 0) & 0x1f; /* destination register */ func = (insn >> 5) & 0x7ff; @@ -104,8 +117,8 @@ alpha_fp_emul (unsigned long pc) va = alpha_read_fp_reg(fa); vb = alpha_read_fp_reg(fb); - fpcr = rdfpcr(); + /* * Try the operation in software. First, obtain the rounding * mode... @@ -212,8 +225,10 @@ alpha_fp_emul (unsigned long pc) default: printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n", func & 0x3f, pc); + MOD_DEC_USE_COUNT; return 0; } + /* * Take the appropriate action for each possible * floating-point result: @@ -236,8 +251,10 @@ alpha_fp_emul (unsigned long pc) wrfpcr(fpcr); /* Do we generate a signal? */ - if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) + if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) { + MOD_DEC_USE_COUNT; return 0; + } } /* @@ -246,6 +263,8 @@ alpha_fp_emul (unsigned long pc) * result: */ alpha_write_fp_reg(fc, vc); + + MOD_DEC_USE_COUNT; return 1; } diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 603b33149..f3a923064 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -4,23 +4,30 @@ * Copyright (C) 1995 Linus Torvalds */ -#include <linux/signal.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> +#include <linux/mm.h> + +#define __EXTERN_INLINE inline +#include <asm/mmu_context.h> +#include <asm/pgtable.h> +#undef __EXTERN_INLINE + +#include <linux/signal.h> +#include <linux/head.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/types.h> #include <linux/ptrace.h> #include <linux/mman.h> -#include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> -#include <asm/pgtable.h> -#include <asm/mmu_context.h> + +extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); + #ifdef __SMP__ unsigned long last_asn[NR_CPUS] = { /* gag */ @@ -61,21 +68,26 @@ unsigned long last_asn[NR_CPUS] = { /* gag */ unsigned long asn_cache = ASN_FIRST_VERSION; #endif /* __SMP__ */ -#ifndef BROKEN_ASN /* - * Select a new ASN and reload the context. This is - * not inlined as this expands to a pretty large - * function. + * Select a new ASN for a task. */ -void get_new_asn_and_reload(struct task_struct *tsk, struct mm_struct *mm) + +void +get_new_mmu_context(struct task_struct *p, struct mm_struct *mm) { - mm->context = 0; - get_new_mmu_context(tsk, mm); - reload_context(tsk); -} -#endif + unsigned long asn = asn_cache; -extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); + if ((asn & HARDWARE_ASN_MASK) < MAX_ASN) + ++asn; + else { + tbiap(); + imb(); + asn = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION; + } + asn_cache = asn; + mm->context = asn; /* full version + asn */ + p->tss.asn = asn & HARDWARE_ASN_MASK; /* just asn */ +} /* * This routine handles page faults. It determines the address, @@ -99,23 +111,24 @@ extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); */ /* Macro for exception fixup code to access integer registers. */ -#define dpf_reg(r) \ - (((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 : \ +#define dpf_reg(r) \ + (((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 : \ (r) <= 18 ? (r)+8 : (r)-10]) -asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, - long cause, struct pt_regs *regs) +asmlinkage void +do_page_fault(unsigned long address, unsigned long mmcsr, + long cause, struct pt_regs *regs) { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; unsigned fixup; /* As of EV6, a load into $31/$f31 is a prefetch, and never faults - (or is suppressed by the PALcode). Support that for older cpu's + (or is suppressed by the PALcode). Support that for older CPUs by ignoring such an instruction. */ if (cause == 0) { - /* No need for get_user.. we know the insn is there. */ - unsigned int insn = *(unsigned int *)regs->pc; + unsigned int insn; + __get_user(insn, (unsigned int *)regs->pc); if ((insn >> 21 & 0x1f) == 0x1f && /* ldq ldl ldt lds ldg ldf ldwu ldbu */ (1ul << (insn >> 26) & 0x30f00001400ul)) { @@ -124,8 +137,8 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, } } - lock_kernel(); down(&mm->mmap_sem); + lock_kernel(); vma = find_vma(mm, address); if (!vma) goto bad_area; diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 7562f6709..85b1e3e07 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -28,6 +28,86 @@ extern void show_net_buffers(void); struct thread_struct * original_pcb_ptr; +#ifndef __SMP__ +struct pgtable_cache_struct quicklists; +#endif + +void +__bad_pmd(pgd_t *pgd) +{ + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, BAD_PAGETABLE); +} + +void +__bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, (pte_t *) BAD_PAGETABLE); +} + +pmd_t * +get_pmd_slow(pgd_t *pgd, unsigned long offset) +{ + pmd_t *pmd; + + pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + if (pgd_none(*pgd)) { + if (pmd) { + clear_page((unsigned long)pmd); + pgd_set(pgd, pmd); + return pmd + offset; + } + pgd_set(pgd, BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long)pmd); + if (pgd_bad(*pgd)) { + __bad_pmd(pgd); + return NULL; + } + return (pmd_t *) pgd_page(*pgd) + offset; +} + +pte_t * +get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page((unsigned long)pte); + pmd_set(pmd, pte); + return pte + offset; + } + pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long)pte); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) + free_pgd_slow(get_pgd_fast()), freed++; + if(pmd_quicklist) + free_pmd_slow(get_pmd_fast()), freed++; + if(pte_quicklist) + free_pte_slow(get_pte_fast()), freed++; + } while(pgtable_cache_size > low); + } + return freed; +} + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -41,22 +121,25 @@ struct thread_struct * original_pcb_ptr; * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -pmd_t * __bad_pagetable(void) +pmd_t * +__bad_pagetable(void) { memset((void *) EMPTY_PGT, 0, PAGE_SIZE); return (pmd_t *) EMPTY_PGT; } -pte_t __bad_page(void) +pte_t +__bad_page(void) { memset((void *) EMPTY_PGE, 0, PAGE_SIZE); return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED)); } -void show_mem(void) +void +show_mem(void) { - int i,free = 0,total = 0,reserved = 0; - int shared = 0; + long i,free = 0,total = 0,reserved = 0; + long shared = 0, cached = 0; printk("\nMem-info:\n"); show_free_areas(); @@ -66,15 +149,19 @@ void show_mem(void) total++; if (PageReserved(mem_map+i)) reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; else if (!atomic_read(&mem_map[i].count)) free++; else shared += atomic_read(&mem_map[i].count) - 1; } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); + printk("%ld pages of RAM\n",total); + printk("%ld free pages\n",free); + printk("%ld reserved pages\n",reserved); + printk("%ld pages shared\n",shared); + printk("%ld pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); #ifdef CONFIG_NET show_net_buffers(); @@ -83,29 +170,20 @@ void show_mem(void) extern unsigned long free_area_init(unsigned long, unsigned long); -static struct thread_struct * load_PCB(struct thread_struct * pcb) +static struct thread_struct * +load_PCB(struct thread_struct * pcb) { - struct thread_struct *old_pcb; - - __asm__ __volatile__( - "stq $30,0(%1)\n\t" - "bis %1,%1,$16\n\t" -#ifdef CONFIG_ALPHA_DP264 - "zap $16,0xe0,$16\n\t" -#endif /* DP264 */ - "call_pal %2\n\t" - "bis $0,$0,%0" - : "=r" (old_pcb) - : "r" (pcb), "i" (PAL_swpctx) - : "$0", "$1", "$16", "$22", "$23", "$24", "$25"); - return old_pcb; + register unsigned long sp __asm__("$30"); + pcb->ksp = sp; + return __reload_tss(pcb); } /* * paging_init() sets up the page tables: in the alpha version this actually * unmaps the bootup page table (as we're now in KSEG, so we don't need it). */ -unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +unsigned long +paging_init(unsigned long start_mem, unsigned long end_mem) { int i; unsigned long newptbr; @@ -162,7 +240,8 @@ printk("OKSP 0x%lx OPTBR 0x%lx\n", * note that current should be pointing at the idle thread task struct * for this CPU. */ -void paging_init_secondary(void) +void +paging_init_secondary(void) { current->tss.ptbr = init_task.tss.ptbr; current->tss.pal_flags = 1; @@ -180,7 +259,8 @@ printk("paging_init_secondary: KSP 0x%lx PTBR 0x%lx\n", } #endif /* __SMP__ */ -void mem_init(unsigned long start_mem, unsigned long end_mem) +void +mem_init(unsigned long start_mem, unsigned long end_mem) { unsigned long tmp; @@ -211,22 +291,24 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) return; } -void free_initmem (void) +void +free_initmem (void) { - extern char __init_begin, __init_end; - unsigned long addr; - - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); - free_page(addr); - } - printk ("Freeing unused kernel memory: %ldk freed\n", + extern char __init_begin, __init_end; + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + atomic_set(&mem_map[MAP_NR(addr)].count, 1); + free_page(addr); + } + printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); } -void si_meminfo(struct sysinfo *val) +void +si_meminfo(struct sysinfo *val) { int i; |