diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-02-15 02:15:32 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-02-15 02:15:32 +0000 |
commit | 86464aed71025541805e7b1515541aee89879e33 (patch) | |
tree | e01a457a4912a8553bc65524aa3125d51f29f810 /arch/alpha | |
parent | 88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff) |
Merge with Linux 2.2.1.
Diffstat (limited to 'arch/alpha')
27 files changed, 1579 insertions, 697 deletions
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index bcdf3d5e2..d48c8e09f 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -19,6 +19,10 @@ old_gas := $(shell if $(AS) --version 2>&1 | grep 'version 2.7' > /dev/null; the # 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) +have_mcpu_pca56 := $(shell if $(CC) -mcpu=pca56 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) + +have_mcpu_ev6 := $(shell if $(CC) -mcpu=ev6 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) + # Turn on the proper cpu optimizations. ifeq ($(have_mcpu),y) # If GENERIC, make sure to turn off any instruction set extensions that @@ -31,17 +35,34 @@ ifeq ($(have_mcpu),y) ifeq ($(CONFIG_ALPHA_EV4),y) CFLAGS := $(CFLAGS) -mcpu=ev4 endif - # Leave out EV5, since it is too hard to figure out whether we - # should use EV56 insns or not. + ifeq ($(CONFIG_ALPHA_PYXIS),y) + CFLAGS := $(CFLAGS) -mcpu=ev56 + endif + ifeq ($(CONFIG_ALPHA_POLARIS),y) + ifeq ($(have_mcpu_pca56),y) + CFLAGS := $(CFLAGS) -mcpu=pca56 + else + CFLAGS := $(CFLAGS) -mcpu=ev56 + endif + endif ifeq ($(CONFIG_ALPHA_EV6),y) - CFLAGS := $(CFLAGS) -mcpu=ev6 + ifeq ($(have_mcpu_ev6),y) + CFLAGS := $(CFLAGS) -mcpu=ev6 + else + ifeq ($(have_mcpu_pca56),y) + CFLAGS := $(CFLAGS) -mcpu=pca56 + else + CFLAGS := $(CFLAGS) -mcpu=ev56 + endif + endif endif endif # For TSUNAMI, we must have the assembler not emulate our instructions. +# The same is true for POLARIS. # BWX is most important, but we don't really want any emulation ever. ifeq ($(old_gas),y) - ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI),) + ifneq ($(CONFIG_ALPHA_GENERIC)$(CONFIG_ALPHA_TSUNAMI)$(CONFIG_ALPHA_POLARIS),) # How do we do #error in make? CFLAGS := --error-please-upgrade-your-assembler endif @@ -52,6 +73,12 @@ else ifeq ($(CONFIG_ALPHA_PYXIS),y) CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWIO_ENABLED endif + ifeq ($(CONFIG_ALPHA_POLARIS),y) + CFLAGS := $(CFLAGS) -Wa,-m21164pc + endif + ifeq ($(CONFIG_ALPHA_TSUNAMI),y) + CFLAGS := $(CFLAGS) -Wa,-mev6 + endif endif HEAD := arch/alpha/kernel/head.o diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 48e924fd7..4e64ee826 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -13,7 +13,6 @@ mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - MODULES=y bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS bool 'Kernel module loader' CONFIG_KMOD fi @@ -44,6 +43,7 @@ choice 'Alpha system type' \ Platform2000 CONFIG_ALPHA_P2K \ Rawhide CONFIG_ALPHA_RAWHIDE \ Ruffian CONFIG_ALPHA_RUFFIAN \ + RX164 CONFIG_ALPHA_RX164 \ SX164 CONFIG_ALPHA_SX164 \ Sable CONFIG_ALPHA_SABLE \ Takara CONFIG_ALPHA_TAKARA" Generic @@ -52,7 +52,7 @@ choice 'Alpha system type' \ 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_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION @@ -131,6 +131,12 @@ then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_MCPCIA y fi +if [ "$CONFIG_ALPHA_RX164" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_POLARIS y +fi if [ "$CONFIG_ALPHA_JENSEN" = "y" ] then define_bool CONFIG_ALPHA_EV4 y @@ -167,6 +173,8 @@ then define_bool CONFIG_ALPHA_AVANTI y fi +bool 'Symmetric multi-processing support' CONFIG_SMP + if [ "$CONFIG_PCI" = "y" ]; then bool 'PCI quirks' CONFIG_PCI_QUIRKS if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -247,8 +255,6 @@ source drivers/char/Config.in source fs/Config.in -source fs/nls/Config.in - if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 96666ced7..cfd366eb5 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -42,6 +42,7 @@ CONFIG_ALPHA_GENERIC=y # CONFIG_ALPHA_SX164 is not set # CONFIG_ALPHA_SABLE is not set # CONFIG_ALPHA_TAKARA is not set +# CONFIG_SMP is not set CONFIG_PCI=y CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y # CONFIG_PCI_QUIRKS is not set diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 68a130f4e..4032c8c0e 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -23,11 +23,11 @@ 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 \ + core_t2.o core_tsunami.o core_polaris.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 \ + sys_sx164.o sys_takara.o sys_rx164.o \ es1888.o smc37c669.o smc37c93x.o else @@ -53,6 +53,9 @@ endif ifdef CONFIG_ALPHA_TSUNAMI O_OBJS += core_tsunami.o endif +ifdef CONFIG_ALPHA_POLARIS +O_OBJS += core_polaris.o +endif # Board support ifneq ($(CONFIG_ALPHA_ALCOR)$(CONFIG_ALPHA_XLT),) @@ -85,6 +88,9 @@ endif ifdef CONFIG_ALPHA_RUFFIAN O_OBJS += sys_ruffian.o endif +ifdef CONFIG_ALPHA_RX164 +O_OBJS += sys_rx164.o +endif ifdef CONFIG_ALPHA_SABLE O_OBJS += sys_sable.o endif @@ -111,7 +117,7 @@ endif endif # GENERIC -ifdef SMP +ifdef CONFIG_SMP O_OBJS += smp.o endif diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 175df318b..65975c168 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -28,6 +28,7 @@ #include <asm/irq.h> #include <asm/machvec.h> #include <asm/pgtable.h> +#include <asm/semaphore.h> #define __KERNEL_SYSCALLS__ #include <asm/unistd.h> @@ -52,6 +53,7 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(screen_info); +EXPORT_SYMBOL(perf_irq); /* platform dependent support */ EXPORT_SYMBOL(_inb); @@ -85,6 +87,7 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(memcmp); @@ -138,6 +141,13 @@ EXPORT_SYMBOL_NOVERS(__do_clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strlen_user); +/* + * The following are specially called from the semaphore assembly stubs. + */ +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__up_wakeup); + /* * SMP-specific symbols. */ diff --git a/arch/alpha/kernel/bios32.h b/arch/alpha/kernel/bios32.h index da08f45c0..8850517ba 100644 --- a/arch/alpha/kernel/bios32.h +++ b/arch/alpha/kernel/bios32.h @@ -32,6 +32,13 @@ #define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */ /* + * We try to make the DEFAULT_MEM_BASE addresses *always* have more than + * a single 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. + */ + +/* * 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 @@ -45,22 +52,20 @@ #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. + * 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 the MCPCIA core logic supports more bits for physical addresses, + * it should allow an expanded range of SPARSE memory addresses. + * However, we do not use them all, in order to avoid the HAE manipulation + * that would be needed. + */ +#define RAWHIDE_DEFAULT_MEM_BASE (64*MB + 2*MB) + +/* * Because CIA and PYXIS and T2 have more bits for physical addresses, * they support an expanded range of SPARSE memory addresses. */ diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c new file mode 100644 index 000000000..b9945402f --- /dev/null +++ b/arch/alpha/kernel/core_polaris.c @@ -0,0 +1,275 @@ +/* + * linux/arch/alpha/kernel/core_polaris.c + * + * POLARIS chip-specific code + * + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/ptrace.h> +#include <asm/pci.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_polaris.h> +#undef __EXTERN_INLINE + +#include "proto.h" +#include "bios32.h" + +/* + * BIOS32-style PCI interface: + */ + +#ifdef DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(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 POLARIS_mcheck_expected = 0; +static volatile unsigned int POLARIS_mcheck_taken = 0; +static volatile unsigned short POLARIS_jd = 0; + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address. This is fairly straightforward + * on POLARIS, since the chip itself generates Type 0 or Type 1 + * cycles automatically depending on the bus number (Bus 0 is + * hardwired to Type 0, all others are Type 1. Peer bridges + * are not supported). + * + * All types: + * + * 3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 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 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1|1|1|1|1|0|0|1|1|1|1|1|1|1|1|0|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|x|x| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 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, u8 *type1) +{ + *type1 = (bus == 0) ? 0 : 1; + *pci_addr = (bus << 16) | (device_fn << 8) | (where) | + POLARIS_DENSE_CONFIG_BASE; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," + " returning address 0x%p\n" + bus, device_fn, where, *pci_addr)); + + return 0; +} + +int +polaris_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)pci_addr); + return PCIBIOS_SUCCESSFUL; +} + + +int +polaris_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)pci_addr); + return PCIBIOS_SUCCESSFUL; +} + + +int +polaris_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)pci_addr; + return PCIBIOS_SUCCESSFUL; +} + + +int +polaris_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)pci_addr); + mb(); + __kernel_ldbu(*(vucp)pci_addr); + return PCIBIOS_SUCCESSFUL; +} + + +int +polaris_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)pci_addr); + mb(); + __kernel_ldbu(*(vusp)pci_addr); + return PCIBIOS_SUCCESSFUL; +} + + +int +polaris_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, + struct linux_hose_info *hose) +{ + unsigned long pci_addr; + unsigned char type1; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)pci_addr = value; + mb(); + *(vuip)pci_addr; + return PCIBIOS_SUCCESSFUL; +} + +void __init +polaris_init_arch(unsigned long *mem_start, unsigned long *mem_end) +{ + /* May need to initialize error reporting (see PCICTL0/1), but + * for now assume that the firmware has done the right thing + * already. + */ +#if 0 + printk("polaris_init_arch(): trusting firmware for setup\n"); +#endif +} + +int polaris_pci_clr_err(void) +{ + POLARIS_jd = *((vusp)POLARIS_W_STATUS); + DBG_MCK(("POLARIS_pci_clr_err: POLARIS_W_STATUS after read 0x%x\n", + POLARIS_jd)); + /* Write 1's to settable bits to clear errors */ + *((vusp)POLARIS_W_STATUS) = 0x7800; mb(); + POLARIS_jd = *((vusp)POLARIS_W_STATUS); + return 0; +} + +void polaris_machine_check(unsigned long vector, unsigned long la_ptr, + struct pt_regs * regs) +{ + struct el_common *mchk_header; + struct el_POLARIS_sysdata_mcheck *mchk_sysdata; + + mchk_header = (struct el_common *)la_ptr; + + mchk_sysdata = + (struct el_POLARIS_sysdata_mcheck *)(la_ptr+mchk_header->sys_offset); + +#if 0 + DBG_MCK(("polaris_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(("polaris_machine_check: expected %d status 0x%lx\n", + POLARIS_mcheck_expected, mchk_sysdata->psc_status)); +#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(); + if (POLARIS_mcheck_expected) { + DBG_MCK(("POLARIS machine check expected\n")); + POLARIS_mcheck_expected = 0; + POLARIS_mcheck_taken = 1; + mb(); + mb(); + draina(); + polaris_pci_clr_err(); + wrmces(0x7); + mb(); + } +#if 1 + else { + printk("POLARIS machine check NOT expected\n") ; + DBG_MCK(("polaris_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)); + POLARIS_mcheck_expected = 0; + POLARIS_mcheck_taken = 1; + mb(); + mb(); + draina(); + polaris_pci_clr_err(); + wrmces(0x7); + mb(); + } +#endif +} diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c index defceb053..c7ec2b6ee 100644 --- a/arch/alpha/kernel/core_t2.c +++ b/arch/alpha/kernel/core_t2.c @@ -143,7 +143,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1) { unsigned long flags; - unsigned int stat0, value, cpu; + unsigned int value, cpu; unsigned long t2_cfg = 0; cpu = smp_processor_id(); @@ -153,11 +153,14 @@ 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. */ - stat0 = *(vulp)T2_IOCSR; - *(vulp)T2_IOCSR = stat0; - mb(); - DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0)); + { + unsigned long stat0; + /* 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. */ @@ -202,7 +205,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char type1) { unsigned long flags; - unsigned int stat0, cpu; + unsigned int cpu; unsigned long t2_cfg = 0; cpu = smp_processor_id(); @@ -210,11 +213,14 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) __save_and_cli(flags); /* avoid getting hit by machine check */ #if 0 - /* 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)); + { + unsigned long stat0; + /* 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. */ @@ -346,7 +352,6 @@ t2_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value, void __init t2_init_arch(unsigned long *mem_start, unsigned long *mem_end) { - unsigned long t2_err; unsigned int i; for (i = 0; i < NR_CPUS; i++) { @@ -355,13 +360,15 @@ t2_init_arch(unsigned long *mem_start, unsigned long *mem_end) } #if 0 - /* - * Set up error reporting. - */ - t2_err = *(vulp)T2_IOCSR ; - t2_err |= (0x1 << 7) ; /* master abort */ - *(vulp)T2_IOCSR = t2_err ; - mb() ; + { + /* Set up error reporting. */ + unsigned long t2_err; + + t2_err = *(vulp)T2_IOCSR; + t2_err |= (0x1 << 7); /* master abort */ + *(vulp)T2_IOCSR = t2_err; + mb(); + } #endif printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE); diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index f2fd19acd..efcce56d5 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -9,7 +9,6 @@ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/sched.h> @@ -302,14 +301,22 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index, * 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. + * Window 0 goes at 1 GB and is 1 GB large, mapping to 0. */ pchip->wsba[0].csr = 1L | (TSUNAMI_DMA_WIN_BASE_DEFAULT & 0xfff00000U); pchip->wsm[0].csr = (TSUNAMI_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000UL; pchip->tba[0].csr = 0; +#if 0 pchip->wsba[1].csr = 0; +#else + /* make the second window at 2Gb for 1Gb mapping to 1Gb */ + pchip->wsba[1].csr = 1L | ((0x80000000U) & 0xfff00000U); + pchip->wsm[1].csr = (0x40000000UL - 1) & 0xfff00000UL; + pchip->tba[1].csr = 0x40000000; +#endif + pchip->wsba[2].csr = 0; pchip->wsba[3].csr = 0; mb(); @@ -359,7 +366,9 @@ tsunami_init_arch(unsigned long *mem_start, unsigned long *mem_end) /* Find how many hoses we have, and initialize them. */ tsunami_init_one_pchip(TSUNAMI_pchip0, 0, mem_start); - tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); + /* must change this for TYPHOON which may have 4 */ + if (TSUNAMI_cchip->csc.csr & 1L<<14) + tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); } static inline void @@ -378,7 +387,9 @@ tsunami_pci_clr_err(void) { int cpu = smp_processor_id(); tsunami_pci_clr_err_1(TSUNAMI_pchip0, cpu); - tsunami_pci_clr_err_1(TSUNAMI_pchip1, cpu); + /* must change this for TYPHOON which may have 4 */ + if (TSUNAMI_cchip->csc.csr & 1L<<14) + tsunami_pci_clr_err_1(TSUNAMI_pchip1, cpu); return 0; } diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index f349ebd6b..380af2c9c 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -8,10 +8,9 @@ #define halt .long PAL_halt #define rti .long PAL_rti -#define SIGCHLD 20 +#define SIGCHLD 20 -#define NR_SYSCALLS 370 -#define osf_vfork sys_fork +#define NR_SYSCALLS 371 /* * These offsets must match with alpha_mv in <asm/machvec.h>. @@ -502,6 +501,17 @@ sys_clone: .end sys_clone .align 3 +.globl sys_vfork +.ent sys_vfork +sys_vfork: + bsr $1,do_switch_stack + bis $30,$30,$16 + jsr $26,alpha_vfork + bsr $1,undo_switch_stack + ret $31,($26),1 +.end sys_vfork + +.align 3 .globl alpha_switch_to .ent alpha_switch_to alpha_switch_to: @@ -689,7 +699,8 @@ ret_from_smpfork: .set at mb /* Make the changed data visible before the freed lock. */ stq $31,scheduler_lock - br ret_from_sys_call + lda $26,ret_from_sys_call + jsr $31,schedule_tail .set noat .end ret_from_smpfork #endif /* __SMP__ */ @@ -821,7 +832,7 @@ sys_call_table: .quad sys_getpgrp .quad sys_getpagesize .quad alpha_ni_syscall /* 65 */ - .quad osf_vfork + .quad sys_vfork .quad sys_newstat .quad sys_newlstat .quad alpha_ni_syscall @@ -1127,4 +1138,4 @@ sys_call_table: .quad sys_getcwd .quad sys_capget .quad sys_capset - .quad sys_ni_syscall /* 370 */ + .quad sys_sendfile /* 370 */ diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 8f6afc14b..e1a53ab57 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -11,6 +11,7 @@ */ #include <linux/config.h> +#include <linux/kernel.h> #include <linux/ptrace.h> #include <linux/errno.h> #include <linux/kernel_stat.h> @@ -38,13 +39,6 @@ unsigned int local_irq_count[NR_CPUS]; unsigned int local_bh_count[NR_CPUS]; unsigned long hardirq_no[NR_CPUS]; -#define RTC_IRQ 8 -#ifdef CONFIG_RTC -#define TIMER_IRQ 0 /* timer is the pit */ -#else -#define TIMER_IRQ RTC_IRQ /* the timer is, in fact, the rtc */ -#endif - #if NR_IRQS > 64 # error Unable to handle more than 64 irq levels. #endif @@ -84,6 +78,15 @@ generic_ack_irq(unsigned long irq) } } + + +static void dummy_perf(unsigned long vector, struct pt_regs *regs) +{ + printk(KERN_CRIT "Performance counter interrupt!\n"); +} + +void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf; + /* * Dispatch device interrupts. */ @@ -102,6 +105,8 @@ generic_ack_irq(unsigned long irq) # define IACK_SC PYXIS_IACK_SC #elif defined(CONFIG_ALPHA_TSUNAMI) # define IACK_SC TSUNAMI_IACK_SC +#elif defined(CONFIG_ALPHA_POLARIS) +# define IACK_SC POLARIS_IACK_SC #else /* This is bogus but necessary to get it to compile on all platforms. */ # define IACK_SC 1L @@ -311,14 +316,14 @@ free_irq(unsigned int irq, void *dev_id) int get_irq_list(char *buf) { - int i, j; + int i; struct irqaction * action; char *p = buf; #ifdef __SMP__ p += sprintf(p, " "); - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "CPU%d ", j); + for (i = 0; i < smp_num_cpus; i++) + p += sprintf(p, "CPU%d ", i); *p++ = '\n'; #endif @@ -330,9 +335,12 @@ int get_irq_list(char *buf) #ifndef __SMP__ p += sprintf(p, "%10u ", kstat_irqs(i)); #else - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); + { + int j; + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); + } #endif p += sprintf(p, " %c%s", (action->flags & SA_INTERRUPT)?'+':' ', @@ -815,7 +823,7 @@ probe_irq_on(void) * Wait about 100ms for spurious interrupts to mask themselves * out again... */ - for (delay = jiffies + HZ/10; delay > jiffies; ) + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) barrier(); /* Now filter out any obviously spurious interrupts. */ @@ -879,8 +887,8 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, __restore_flags(flags); return; case 4: - printk("Performance counter interrupt\n"); - break; + perf_irq(vector, ®s); + return; default: printk("Hardware intr %ld %lx? Huh?\n", type, vector); } diff --git a/arch/alpha/kernel/irq.h b/arch/alpha/kernel/irq.h index c46d5df4e..6849e830b 100644 --- a/arch/alpha/kernel/irq.h +++ b/arch/alpha/kernel/irq.h @@ -8,6 +8,8 @@ * with the IRQ handling routines in irq.c. */ +#include <linux/config.h> + #define STANDARD_INIT_IRQ_PROLOG \ outb(0, DMA1_RESET_REG); \ outb(0, DMA2_RESET_REG); \ @@ -21,3 +23,11 @@ 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); + +#define RTC_IRQ 8 +#ifdef CONFIG_RTC +#define TIMER_IRQ 0 /* timer is the pit */ +#else +#define TIMER_IRQ RTC_IRQ /* timer is the rtc */ +#endif + diff --git a/arch/alpha/kernel/machvec.h b/arch/alpha/kernel/machvec.h index 70c85c451..8420aaf9c 100644 --- a/arch/alpha/kernel/machvec.h +++ b/arch/alpha/kernel/machvec.h @@ -13,6 +13,11 @@ we can read and write it as we like. ;-) */ #define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) +/* Whee. POLARIS 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 POLARIS_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. */ @@ -91,6 +96,7 @@ #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_POLARIS_IO IO(POLARIS,polaris,polaris) #define DO_T2_IO IO(T2,t2,t2) #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami,tsunami) @@ -103,6 +109,7 @@ #define DO_LCA_BUS BUS(lca) #define DO_MCPCIA_BUS BUS(mcpcia) #define DO_PYXIS_BUS BUS(pyxis) +#define DO_POLARIS_BUS BUS(polaris) #define DO_T2_BUS BUS(t2) #define DO_TSUNAMI_BUS BUS(tsunami) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 4c540f696..67c08778d 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1128,11 +1128,16 @@ asmlinkage int osf_utimes(const char *filename, struct timeval32 *tvs) return ret; } +#define MAX_SELECT_SECONDS \ + ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) + asmlinkage int osf_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp) { - fd_set_buffer *fds; + fd_set_bits fds; + char *bits; + size_t size; unsigned long timeout; int ret; @@ -1145,28 +1150,46 @@ osf_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, || (ret = __get_user(usec, &tvp->tv_usec))) goto out_nofds; - timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); - timeout += sec * HZ; + ret = -EINVAL; + if (sec < 0 || usec < 0) + goto out_nofds; + + if ((unsigned long) sec < MAX_SELECT_SECONDS) { + timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); + timeout += sec * (unsigned long) HZ; + } } + ret = -EINVAL; + if (n < 0 || n > KFDS_NR) + goto out_nofds; + + /* + * We need 6 bitmaps (in/out/ex for both incoming and outgoing), + * since we used fdset we need to allocate memory in units of + * long-words. + */ ret = -ENOMEM; - fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL); - if (!fds) + size = FDS_BYTES(n); + bits = kmalloc(6 * size, GFP_KERNEL); + if (!bits) goto out_nofds; - ret = -EINVAL; - if (n < 0) - goto out; - if (n > KFDS_NR) - n = KFDS_NR; - if ((ret = get_fd_set(n, inp->fds_bits, fds->in)) || - (ret = get_fd_set(n, outp->fds_bits, fds->out)) || - (ret = get_fd_set(n, exp->fds_bits, fds->ex))) + fds.in = (unsigned long *) bits; + fds.out = (unsigned long *) (bits + size); + fds.ex = (unsigned long *) (bits + 2*size); + fds.res_in = (unsigned long *) (bits + 3*size); + fds.res_out = (unsigned long *) (bits + 4*size); + fds.res_ex = (unsigned long *) (bits + 5*size); + + if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) || + (ret = get_fd_set(n, outp->fds_bits, fds.out)) || + (ret = get_fd_set(n, exp->fds_bits, fds.ex))) goto out; - zero_fd_set(n, fds->res_in); - zero_fd_set(n, fds->res_out); - zero_fd_set(n, fds->res_ex); + zero_fd_set(n, fds.res_in); + zero_fd_set(n, fds.res_out); + zero_fd_set(n, fds.res_ex); - ret = do_select(n, fds, &timeout); + ret = do_select(n, &fds, &timeout); /* OSF does not copy back the remaining time. */ @@ -1179,12 +1202,12 @@ osf_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, ret = 0; } - set_fd_set(n, inp->fds_bits, fds->res_in); - set_fd_set(n, outp->fds_bits, fds->res_out); - set_fd_set(n, exp->fds_bits, fds->res_ex); + set_fd_set(n, inp->fds_bits, fds.res_in); + set_fd_set(n, outp->fds_bits, fds.res_out); + set_fd_set(n, exp->fds_bits, fds.res_ex); out: - free_page((unsigned long) fds); + kfree(bits); out_nofds: return ret; } @@ -1304,7 +1327,6 @@ asmlinkage int osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *rema { struct timeval tmp; unsigned long ticks; - unsigned long tmp_timeout; if (get_tv32(&tmp, sleep)) goto fault; diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 562778366..55e211a23 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -257,13 +257,19 @@ void release_thread(struct task_struct *dead_task) * with parameters (SIGCHLD, 0). */ int alpha_clone(unsigned long clone_flags, unsigned long usp, - struct switch_stack * swstack) + struct switch_stack * swstack) { if (!usp) usp = rdusp(); return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1)); } +int alpha_vfork(struct switch_stack * swstack) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), + (struct pt_regs *) (swstack+1)); +} + extern void ret_from_sys_call(void); extern void ret_from_smpfork(void); /* diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 15096703d..bee005933 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -76,6 +76,22 @@ extern int mcpcia_hose_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 *); +/* core_polaris.c */ +extern int polaris_hose_read_config_byte (u8, u8, u8, u8 *value, + struct linux_hose_info *hose); +extern int polaris_hose_read_config_word (u8, u8, u8, u16 *value, + struct linux_hose_info *hose); +extern int polaris_hose_read_config_dword (u8, u8, u8, u32 *value, + struct linux_hose_info *hose); +extern int polaris_hose_write_config_byte (u8, u8, u8, u8 value, + struct linux_hose_info *hose); +extern int polaris_hose_write_config_word (u8, u8, u8, u16 value, + struct linux_hose_info *hose); +extern int polaris_hose_write_config_dword (u8, u8, u8, u32 value, + struct linux_hose_info *hose); +extern void polaris_init_arch(unsigned long *, unsigned long *); +extern void polaris_machine_check(u64, u64, struct pt_regs *); + /* core_pyxis.c */ extern int pyxis_hose_read_config_byte (u8, u8, u8, u8 *value, struct linux_hose_info *hose); @@ -129,8 +145,6 @@ 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 */ @@ -143,6 +157,8 @@ extern void reset_for_srm(void); /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); +extern void rtc_init_pit(void); +extern void generic_init_pit(void); extern unsigned long est_cycle_freq; /* smc37c93x.c */ diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index b6194defa..18c9a8b13 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -541,7 +541,9 @@ sys_ptrace(long request, long pid, long addr, long data, /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: + down(&child->mm->mmap_sem); ret = read_long(child, addr, &tmp); + up(&child->mm->mmap_sem); DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); if (ret < 0) goto out; @@ -560,7 +562,9 @@ sys_ptrace(long request, long pid, long addr, long data, case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data)); + down(&child->mm->mmap_sem); ret = write_long(child, addr, data); + up(&child->mm->mmap_sem); goto out; case PTRACE_POKEUSR: /* write the specified register */ diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index f357830e3..42821d903 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -94,62 +94,46 @@ struct screen_info screen_info = { * 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 monet_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; -#pragma weak alcor_mv -#pragma weak alphabook1_mv -#pragma weak avanti_mv -#pragma weak cabriolet_mv -#pragma weak dp264_mv -#pragma weak eb164_mv -#pragma weak eb64p_mv -#pragma weak eb66_mv -#pragma weak eb66p_mv -#pragma weak jensen_mv -#pragma weak lx164_mv -#pragma weak miata_mv -#pragma weak mikasa_mv -#pragma weak mikasa_primo_mv -#pragma weak monet_mv -#pragma weak noname_mv -#pragma weak noritake_mv -#pragma weak noritake_primo_mv -#pragma weak p2k_mv -#pragma weak pc164_mv -#pragma weak rawhide_mv -#pragma weak ruffian_mv -#pragma weak sable_mv -#pragma weak sable_gamma_mv -#pragma weak sx164_mv -#pragma weak takara_mv -#pragma weak xl_mv -#pragma weak xlt_mv +/* GCC 2.7.2 (on alpha at least) is lame. It does not support either + __attribute__((weak)) or #pragma weak. Bypass it and talk directly + to the assembler. */ + +#define WEAK(X) \ + extern struct alpha_machine_vector X; \ + asm(".weak "#X) + +WEAK(alcor_mv); +WEAK(alphabook1_mv); +WEAK(avanti_mv); +WEAK(cabriolet_mv); +WEAK(dp264_mv); +WEAK(eb164_mv); +WEAK(eb64p_mv); +WEAK(eb66_mv); +WEAK(eb66p_mv); +WEAK(jensen_mv); +WEAK(lx164_mv); +WEAK(miata_mv); +WEAK(mikasa_mv); +WEAK(mikasa_primo_mv); +WEAK(monet_mv); +WEAK(noname_mv); +WEAK(noritake_mv); +WEAK(noritake_primo_mv); +WEAK(p2k_mv); +WEAK(pc164_mv); +WEAK(rawhide_mv); +WEAK(ruffian_mv); +WEAK(rx164_mv); +WEAK(sable_mv); +WEAK(sable_gamma_mv); +WEAK(sx164_mv); +WEAK(takara_mv); +WEAK(webbrick_mv); +WEAK(xl_mv); +WEAK(xlt_mv); + +#undef WEAK void __init @@ -264,7 +248,7 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, if (initrd_end > *memory_end_p) { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end, memory_end_p); + initrd_end, (unsigned long) memory_end_p); initrd_start = initrd_end = 0; } } @@ -275,6 +259,16 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, if (alpha_mv.init_arch) alpha_mv.init_arch(memory_start_p, memory_end_p); + /* Initialize the timers. */ + /* ??? There is some circumstantial evidence that this needs + to be done now rather than later in time_init, which would + be more natural. Someone please explain or refute. */ +#if defined(CONFIG_RTC) + rtc_init_pit(); +#else + alpha_mv.init_pit(); +#endif + /* * Give us a default console. TGA users will see nothing until * chr_dev_init is called, rather late in the boot sequence. @@ -349,8 +343,8 @@ static char systype_names[][16] = { 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 eb164_names[][8] = {"EB164", "PC164", "LX164", "SX164", "RX164"}; +static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,4}; 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}; @@ -430,7 +424,7 @@ get_sysvec(long type, long variation, long cpu) static struct alpha_machine_vector *eb164_vecs[] __initlocaldata = { - &eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv + &eb164_mv, &pc164_mv, &lx164_mv, &sx164_mv, &rx164_mv }; static struct alpha_machine_vector *eb64p_vecs[] __initlocaldata = @@ -455,7 +449,7 @@ get_sysvec(long type, long variation, long cpu) &monet_mv, /* monet */ &dp264_mv, /* clipper */ &dp264_mv, /* goldrush */ - &dp264_mv, /* webbrick */ + &webbrick_mv, /* webbrick */ &dp264_mv, /* catamaran */ }; @@ -556,10 +550,12 @@ get_sysvec_byname(const char *name) &pc164_mv, &rawhide_mv, &ruffian_mv, + &rx164_mv, &sable_mv, &sable_gamma_mv, &sx164_mv, &takara_mv, + &webbrick_mv, &xl_mv, &xlt_mv }; diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 19aa9a682..25615e43d 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -30,7 +30,14 @@ #include "proto.h" -struct ipi_msg_flush_tb_struct ipi_msg_flush_tb; +#define DEBUG_SMP 0 +#if DEBUG_SMP +#define DBGS(args) printk args +#else +#define DBGS(args) +#endif + +struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; struct cpuinfo_alpha cpu_data[NR_CPUS]; @@ -39,7 +46,6 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; unsigned int boot_cpu_id = 0; static int smp_activated = 0; -static unsigned long ipicnt[NR_CPUS] = {0,}; /* IPI counts */ int smp_found_config = 0; /* Have we found an SMP box */ static int max_cpus = -1; @@ -53,10 +59,12 @@ int smp_threads_ready = 0; volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +cycles_t cacheflush_time; + unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; -volatile int ipi_bits[NR_CPUS]; +volatile int ipi_bits[NR_CPUS] __cacheline_aligned; unsigned long boot_cpu_palrev; @@ -73,87 +81,80 @@ static void smp_setup_percpu_timer(void); static void secondary_cpu_start(int, struct task_struct *); static void send_cpu_msg(char *, int); -/* process bootcommand SMP options, like "nosmp" and "maxcpus=" */ -__initfunc(void smp_setup(char *str, int *ints)) +/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */ +void __init +smp_setup(char *str, int *ints) { if (ints && ints[0] > 0) max_cpus = ints[1]; - else + else max_cpus = 0; } -void smp_store_cpu_info(int id) +static void __init +smp_store_cpu_info(int id) { /* This is it on Alpha, so far. */ - cpu_data[id].loops_per_sec = loops_per_sec; + cpu_data[id].loops_per_sec = loops_per_sec; } -void smp_commence(void) +void __init +smp_commence(void) { /* Lets the callin's below out of their loop. */ mb(); smp_commenced = 1; } -void smp_callin(void) +void __init +smp_callin(void) { - int cpuid = hard_smp_processor_id(); + int cpuid = hard_smp_processor_id(); -#if 0 - printk("CALLIN %d state 0x%lx\n", cpuid, current->state); -#endif + DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); #ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); + local_flush_cache_all(); + local_flush_tlb_all(); #endif #if 0 - set_irq_udt(mid_xlate[boot_cpu_id]); + set_irq_udt(mid_xlate[boot_cpu_id]); #endif - /* Get our local ticker going. */ - smp_setup_percpu_timer(); + /* Get our local ticker going. */ + smp_setup_percpu_timer(); #if 0 - calibrate_delay(); + calibrate_delay(); #endif - smp_store_cpu_info(cpuid); + smp_store_cpu_info(cpuid); #ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); + local_flush_cache_all(); + local_flush_tlb_all(); #endif - /* Allow master to continue. */ - set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]); + /* Allow master to continue. */ + set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]); #ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); + local_flush_cache_all(); + local_flush_tlb_all(); #endif #ifdef NOT_YET - while(!task[cpuid] || current_set[cpuid] != task[cpuid]) - barrier(); -#endif /* NOT_YET */ - -#if 0 - /* Fix idle thread fields. */ - __asm__ __volatile__("ld [%0], %%g6\n\t" - : : "r" (¤t_set[cpuid]) - : "memory" /* paranoid */); - current->mm->mmap->vm_page_prot = PAGE_SHARED; - current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + while(!task[cpuid] || current_set[cpuid] != task[cpuid]) + barrier(); #endif - + #ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); + local_flush_cache_all(); + local_flush_tlb_all(); #endif #if 0 - __sti(); + __sti(); #endif } -asmlinkage int start_secondary(void *unused) +asmlinkage int __init +start_secondary(void *unused) { extern asmlinkage void entInt(void); extern void paging_init_secondary(void); @@ -163,35 +164,83 @@ asmlinkage int start_secondary(void *unused) trap_init(); wrent(entInt, 0); - smp_callin(); - while (!smp_commenced) + smp_callin(); + while (!smp_commenced) barrier(); #if 1 -printk("start_secondary: commencing CPU %d current %p\n", - hard_smp_processor_id(), current); + printk("start_secondary: commencing CPU %d current %p\n", + hard_smp_processor_id(), current); #endif - cpu_idle(NULL); + cpu_idle(NULL); +} + +static void __init +smp_tune_scheduling (void) +{ + /* + * Rough estimation for SMP scheduling, this is the number of + * cycles it takes for a fully memory-limited process to flush + * the SMP-local cache. + * + * We are not told how much cache there is, so we have to guess. + */ + + struct percpu_struct *cpu; + unsigned long on_chip_cache; + unsigned long freq; + + cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); + switch (cpu->type) + { + case EV45_CPU: + on_chip_cache = 16 + 16; + break; + + case EV5_CPU: + case EV56_CPU: + on_chip_cache = 8 + 8 + 96; + break; + + case PCA56_CPU: + on_chip_cache = 16 + 8; + break; + + case EV6_CPU: + on_chip_cache = 64 + 64; + break; + + default: + on_chip_cache = 8 + 8; + break; + } + + freq = hwrpb->cycle_freq ? : est_cycle_freq; + + /* Magic estimation stolen from x86 port. */ + cacheflush_time = freq / 1024 * on_chip_cache / 5000; } + /* * Cycle through the processors sending START msgs to boot each. */ -void smp_boot_cpus(void) +void __init +smp_boot_cpus(void) { - int cpucount = 0; - int i, first, prev; + int cpucount = 0; + int i, first, prev; - printk("smp_boot_cpus: Entering SMP Mode...\n"); + printk("Entering SMP Mode.\n"); #if 0 - __sti(); + __sti(); #endif - for(i=0; i < NR_CPUS; i++) { + for(i=0; i < NR_CPUS; i++) { cpu_number_map[i] = -1; cpu_logical_map[i] = -1; - prof_counter[i] = 1; - prof_multiplier[i] = 1; + prof_counter[i] = 1; + prof_multiplier[i] = 1; ipi_bits[i] = 0; } @@ -199,159 +248,155 @@ void smp_boot_cpus(void) cpu_logical_map[0] = boot_cpu_id; current->processor = boot_cpu_id; /* ??? */ - smp_store_cpu_info(boot_cpu_id); + smp_store_cpu_info(boot_cpu_id); + smp_tune_scheduling(); #ifdef NOT_YET - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif /* NOT_YET */ - smp_setup_percpu_timer(); + printk("CPU%d: ", boot_cpu_id); + print_cpu_info(&cpu_data[boot_cpu_id]); + set_irq_udt(mid_xlate[boot_cpu_id]); +#endif + smp_setup_percpu_timer(); #ifdef HUH - local_flush_cache_all(); + local_flush_cache_all(); #endif - if (smp_num_probed == 1) + if (smp_num_probed == 1) return; /* Not an MP box. */ #if NOT_YET - /* - * If SMP should be disabled, then really disable it! - */ - if (!max_cpus) + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus) { smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated.\n"); - } -#endif /* NOT_YET */ + printk(KERN_INFO "SMP mode deactivated.\n"); + } +#endif - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (i == boot_cpu_id) continue; - if (cpu_present_map & (1 << i)) { - struct task_struct *idle; - int timeout; + if (cpu_present_map & (1 << i)) { + struct task_struct *idle; + int timeout; - /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_PID); - idle = task[++cpucount]; + /* Cook up an idler for this guy. */ + kernel_thread(start_secondary, NULL, CLONE_PID); + idle = task[++cpucount]; if (!idle) panic("No idle process for CPU %d", i); - idle->processor = i; + idle->processor = i; -#if 0 -printk("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n", - i, idle->state, idle->flags); -#endif + DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n", + i, idle->state, idle->flags)); - /* whirrr, whirrr, whirrrrrrrrr... */ + /* whirrr, whirrr, whirrrrrrrrr... */ #ifdef HUH - local_flush_cache_all(); + local_flush_cache_all(); #endif - secondary_cpu_start(i, idle); + secondary_cpu_start(i, idle); - /* wheee... it's going... wait for 5 secs...*/ - for (timeout = 0; timeout < 50000; timeout++) { + /* wheee... it's going... wait for 5 secs...*/ + for (timeout = 0; timeout < 50000; timeout++) { if (cpu_callin_map[i]) break; - udelay(100); - } - if (cpu_callin_map[i]) { + udelay(100); + } + if (cpu_callin_map[i]) { /* Another "Red Snapper". */ cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; - } else { + cpu_logical_map[cpucount] = i; + } else { cpucount--; - printk("smp_boot_cpus: Processor %d" + printk("smp_boot_cpus: Processor %d" " is stuck 0x%lx.\n", i, idle->flags); - } - } - if (!(cpu_callin_map[i])) { + } + } + if (!(cpu_callin_map[i])) { cpu_present_map &= ~(1 << i); - cpu_number_map[i] = -1; - } - } + cpu_number_map[i] = -1; + } + } #ifdef HUH - local_flush_cache_all(); + local_flush_cache_all(); #endif - if (cpucount == 0) { + if (cpucount == 0) { printk("smp_boot_cpus: ERROR - only one Processor found.\n"); - cpu_present_map = (1 << smp_processor_id()); - } else { + cpu_present_map = (1 << smp_processor_id()); + } else { unsigned long bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_present_map & (1 << i)) bogosum += cpu_data[i].loops_per_sec; - } - printk("smp_boot_cpus: Total of %d Processors activated" + } + printk("smp_boot_cpus: Total of %d Processors activated" " (%lu.%02lu BogoMIPS).\n", - cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); - smp_activated = 1; - smp_num_cpus = cpucount + 1; - } - - /* Setup CPU list for IRQ distribution scheme. */ - first = prev = -1; - for (i = 0; i < NR_CPUS; i++) { + cpucount + 1, + (bogosum + 2500)/500000, + ((bogosum + 2500)/5000)%100); + smp_activated = 1; + smp_num_cpus = cpucount + 1; + } + + /* Setup CPU list for IRQ distribution scheme. */ + first = prev = -1; + for (i = 0; i < NR_CPUS; i++) { if (cpu_present_map & (1 << i)) { if (first == -1) first = i; if (prev != -1) cpu_data[i].next = i; - prev = i; - } - } - cpu_data[prev].next = first; - - /* Ok, they are spinning and ready to go. */ - smp_processors_ready = 1; -} + prev = i; + } + } + cpu_data[prev].next = first; -__initfunc(void ioapic_pirq_setup(char *str, int *ints)) -{ - /* this is prolly INTEL-specific */ + /* Ok, they are spinning and ready to go. */ + smp_processors_ready = 1; } -static void smp_setup_percpu_timer(void) +static void __init +smp_setup_percpu_timer(void) { - int cpu = smp_processor_id(); + int cpu = smp_processor_id(); - prof_counter[cpu] = prof_multiplier[cpu] = 1; + prof_counter[cpu] = prof_multiplier[cpu] = 1; #ifdef NOT_YET - load_profile_irq(mid_xlate[cpu], lvl14_resolution); - if (cpu == boot_cpu_id) + load_profile_irq(mid_xlate[cpu], lvl14_resolution); + if (cpu == boot_cpu_id) enable_pil_irq(14); #endif } extern void update_one_process(struct task_struct *p, unsigned long ticks, - unsigned long user, unsigned long system, + unsigned long user, unsigned long system, int cpu); -void smp_percpu_timer_interrupt(struct pt_regs *regs) +void +smp_percpu_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); #ifdef NOT_YET - clear_profile_irq(mid_xlate[cpu]); - if(!user_mode(regs)) + clear_profile_irq(mid_xlate[cpu]); + if(!user_mode(regs)) alpha_do_profile(regs->pc); #endif - if (!--prof_counter[cpu]) { + if (!--prof_counter[cpu]) { int user = user_mode(regs); - if (current->pid) { + if (current->pid) { update_one_process(current, 1, user, !user, cpu); - if (--current->counter < 0) { + if (--current->counter < 0) { current->counter = 0; - current->need_resched = 1; - } + current->need_resched = 1; + } - spin_lock(&ticker_lock); - if (user) { + spin_lock(&ticker_lock); + if (user) { if (current->priority < DEF_PRIORITY) { kstat.cpu_nice++; kstat.per_cpu_nice[cpu]++; @@ -359,93 +404,86 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) kstat.cpu_user++; kstat.per_cpu_user[cpu]++; } - } else { + } else { kstat.cpu_system++; kstat.per_cpu_system[cpu]++; - } - spin_unlock(&ticker_lock); - } - prof_counter[cpu] = prof_multiplier[cpu]; - } + } + spin_unlock(&ticker_lock); + } + prof_counter[cpu] = prof_multiplier[cpu]; + } } -int setup_profiling_timer(unsigned int multiplier) +int __init +setup_profiling_timer(unsigned int multiplier) { #ifdef NOT_YET - int i; - unsigned long flags; + int i; + unsigned long flags; - /* Prevent level14 ticker IRQ flooding. */ - if((!multiplier) || (lvl14_resolution / multiplier) < 500) - return -EINVAL; + /* Prevent level14 ticker IRQ flooding. */ + if((!multiplier) || (lvl14_resolution / multiplier) < 500) + return -EINVAL; - save_and_cli(flags); - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1 << i)) { - load_profile_irq(mid_xlate[i], lvl14_resolution / multip + save_and_cli(flags); + for(i = 0; i < NR_CPUS; i++) { + if(cpu_present_map & (1 << i)) { + load_profile_irq(mid_xlate[i], lvl14_resolution / multip lier); - prof_multiplier[i] = multiplier; - } - } - restore_flags(flags); + prof_multiplier[i] = multiplier; + } + } + restore_flags(flags); - return 0; + return 0; #endif return -EINVAL; } -/* Only broken Intel needs this, thus it should not even be referenced globally. -*/ -__initfunc(void initialize_secondary(void)) +/* Only broken Intel needs this, thus it should not even be + referenced globally. */ + +void __init +initialize_secondary(void) { - printk("initialize_secondary: entry\n"); } -static void +static void __init secondary_cpu_start(int cpuid, struct task_struct *idle) { struct percpu_struct *cpu; - int timeout; + int timeout; cpu = (struct percpu_struct *) ((char*)hwrpb - + hwrpb->processor_offset - + cpuid * hwrpb->processor_size); + + hwrpb->processor_offset + + cpuid * hwrpb->processor_size); - /* set context to idle thread this CPU will use when running */ - /* assumption is that the idle thread is all set to go... ??? */ + /* Set context to idle thread this CPU will use when running + assumption is that the idle thread is all set to go... ??? */ memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct)); cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */ -#if 0 -printk("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n", - cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb); -printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", - cpuid, idle->state, idle->tss.pal_flags); -#endif - /* setup HWRPB fields that SRM uses to activate secondary CPU */ - hwrpb->CPU_restart = __start_cpu; - hwrpb->CPU_restart_data = (unsigned long) idle; - - /* recalculate and update the HWRPB checksum */ - { - unsigned long sum, *lp1, *lp2; - sum = 0; - lp1 = (unsigned long *)hwrpb; - lp2 = &hwrpb->chksum; - while (lp1 < lp2) - sum += *lp1++; - *lp2 = sum; - } + DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n", + cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb)); + DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", + cpuid, idle->state, idle->tss.pal_flags)); + + /* Setup HWRPB fields that SRM uses to activate secondary CPU */ + hwrpb->CPU_restart = __start_cpu; + hwrpb->CPU_restart_data = (unsigned long) idle; + + /* Recalculate and update the HWRPB checksum */ + hwrpb_update_checksum(hwrpb); /* * Send a "start" command to the specified processor. */ /* SRM III 3.4.1.3 */ - cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */ - cpu->flags &= ~1;/* turn off Bootstrap In Progress */ + cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */ + cpu->flags &= ~1; /* turn off Bootstrap In Progress */ mb(); send_cpu_msg("START\r\n", cpuid); @@ -454,7 +492,7 @@ printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", for (timeout = 10000; !(cpu->flags & 1); timeout--) { if (timeout <= 0) { printk("Processor %d failed to start\n", cpuid); - /* needed for pset_info to work */ + /* needed for pset_info to work */ #if 0 ipc_processor_enable(cpu_to_processor(cpunum)); #endif @@ -462,49 +500,61 @@ printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", } mdelay(1); } -#if 0 - printk("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid); -#endif + DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid)); } static void send_cpu_msg(char *str, int cpuid) { struct percpu_struct *cpu; - register char *cp1, *cp2; - unsigned long cpumask; - int timeout; + register char *cp1, *cp2; + unsigned long cpumask; + size_t len; + int timeout; - cpu = (struct percpu_struct *) ((char*)hwrpb - + hwrpb->processor_offset - + cpuid * hwrpb->processor_size); - - cpumask = (1L << cpuid); - for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) { - if (timeout <= 0) { - printk("Processor %x not ready\n", cpuid); - return; - } - mdelay(1); - } - - cp1 = (char *) &cpu->ipc_buffer[1]; - cp2 = str; - while (*cp2) *cp1++ = *cp2++; - *(unsigned int *)&cpu->ipc_buffer[0] = cp2 - str; /* hack */ - - /* atomic test and set */ - set_bit(cpuid, &hwrpb->rxrdy); - - for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) { - if (timeout <= 0) { - printk("Processor %x not ready\n", cpuid); - return; - } - mdelay(1); - } + + hwrpb->processor_offset + + cpuid * hwrpb->processor_size); + + cpumask = (1L << cpuid); + if (hwrpb->txrdy & cpumask) + goto delay1; + ready1: + + cp2 = str; + len = strlen(cp2); + *(unsigned int *)&cpu->ipc_buffer[0] = len; + cp1 = (char *) &cpu->ipc_buffer[1]; + memcpy(cp1, cp2, len); + + /* atomic test and set */ + set_bit(cpuid, &hwrpb->rxrdy); + + if (hwrpb->txrdy & cpumask) + goto delay2; + ready2: + return; + +delay1: + for (timeout = 10000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready1; + udelay(100); + } + goto timeout; + +delay2: + for (timeout = 10000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready2; + udelay(100); + } + goto timeout; + +timeout: + printk("Processor %x not ready\n", cpuid); + return; } /* @@ -512,7 +562,8 @@ send_cpu_msg(char *str, int cpuid) * * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined */ -__initfunc(void setup_smp(void)) +void __init +setup_smp(void) { struct percpu_struct *cpubase, *cpu; int i; @@ -523,10 +574,10 @@ __initfunc(void setup_smp(void)) } if (hwrpb->nr_processors > 1) { -#if 0 -printk("setup_smp: nr_processors 0x%lx\n", - hwrpb->nr_processors); -#endif + + DBGS(("setup_smp: nr_processors %ld\n", + hwrpb->nr_processors)); + cpubase = (struct percpu_struct *) ((char*)hwrpb + hwrpb->processor_offset); boot_cpu_palrev = cpubase->pal_revision; @@ -541,12 +592,11 @@ printk("setup_smp: nr_processors 0x%lx\n", if (i != boot_cpu_id) cpu->pal_revision = boot_cpu_palrev; } -#if 0 -printk("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", - i, cpu->flags, cpu->type); - printk("setup_smp: CPU %d: PAL rev 0x%lx\n", - i, cpu->pal_revision); -#endif + + DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", + i, cpu->flags, cpu->type)); + DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n", + i, cpu->pal_revision)); } } else { smp_num_probed = 1; @@ -560,132 +610,59 @@ printk("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", static void secondary_console_message(void) { - int mycpu, i, cnt; + int mycpu, i, cnt; unsigned long txrdy = hwrpb->txrdy; char *cp1, *cp2, buf[80]; - struct percpu_struct *cpu; - - mycpu = hard_smp_processor_id(); - -#if 0 -printk("secondary_console_message: TXRDY 0x%lx.\n", txrdy); -#endif - for (i = 0; i < NR_CPUS; i++) { - if (txrdy & (1L << i)) { -#if 0 -printk("secondary_console_message: TXRDY contains CPU %d.\n", i); -#endif - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + i * hwrpb->processor_size); -#if 1 - printk("secondary_console_message: on %d from %d" - " HALT_REASON 0x%lx FLAGS 0x%lx\n", - mycpu, i, cpu->halt_reason, cpu->flags); -#endif - cnt = cpu->ipc_buffer[0] >> 32; - if (cnt <= 0 || cnt >= 80) - strcpy(buf,"<<< BOGUS MSG >>>"); - else { - cp1 = (char *) &cpu->ipc_buffer[11]; - cp2 = buf; - while (cnt--) { - if (*cp1 == '\r' || *cp1 == '\n') { - *cp2++ = ' '; cp1++; - } else - *cp2++ = *cp1++; - } - *cp2 = 0; - } -#if 1 - printk("secondary_console_message: on %d message is '%s'\n", - mycpu, buf); -#endif - } - } - hwrpb->txrdy = 0; - return; -} - -static int -halt_on_panic(unsigned int this_cpu) -{ - halt(); - return 0; -} - -static int -local_flush_tlb_all(unsigned int this_cpu) -{ - tbia(); - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - return 0; -} + struct percpu_struct *cpu; -static int -local_flush_tlb_mm(unsigned int this_cpu) -{ - struct mm_struct * mm = ipi_msg_flush_tb.p.flush_mm; - if (mm == current->mm) - flush_tlb_current(mm); - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - return 0; -} + DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy)); -static int -local_flush_tlb_page(unsigned int this_cpu) -{ - struct vm_area_struct * vma = ipi_msg_flush_tb.p.flush_vma; - struct mm_struct * mm = vma->vm_mm; + mycpu = hard_smp_processor_id(); - if (mm == current->mm) - flush_tlb_current_page(mm, vma, ipi_msg_flush_tb.flush_addr); - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - return 0; -} + for (i = 0; i < NR_CPUS; i++) { + if (!(txrdy & (1L << i))) + continue; -static int -wrapper_local_flush_tlb_page(unsigned int this_cpu) -{ -#if 0 - int cpu = smp_processor_id(); + DBGS(("secondary_console_message: " + "TXRDY contains CPU %d.\n", i)); + + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + i * hwrpb->processor_size); + + printk("secondary_console_message: on %d from %d" + " HALT_REASON 0x%lx FLAGS 0x%lx\n", + mycpu, i, cpu->halt_reason, cpu->flags); + + cnt = cpu->ipc_buffer[0] >> 32; + if (cnt <= 0 || cnt >= 80) + strcpy(buf, "<<< BOGUS MSG >>>"); + else { + cp1 = (char *) &cpu->ipc_buffer[11]; + cp2 = buf; + strcpy(cp2, cp1); + + while ((cp2 = strchr(cp2, '\r')) != 0) { + *cp2 = ' '; + if (cp2[1] == '\n') + cp2[1] = ' '; + } + } - if (cpu) { - printk("wrapper: ipi_msg_flush_tb.flush_addr 0x%lx [%d]\n", - ipi_msg_flush_tb.flush_addr, atomic_read(&global_irq_count)); + printk("secondary_console_message: on %d message is '%s'\n", + mycpu, buf); } -#endif - local_flush_tlb_page(this_cpu); - return 0; -} -static int -unknown_ipi(unsigned int this_cpu) -{ - printk("unknown_ipi() on CPU %d: ", this_cpu); - return 1; + hwrpb->txrdy = 0; } enum ipi_message_type { - CPU_STOP, - TLB_ALL, - TLB_MM, - TLB_PAGE, - TLB_RANGE -}; - -static int (* ipi_func[32])(unsigned int) = { - halt_on_panic, - local_flush_tlb_all, - local_flush_tlb_mm, - wrapper_local_flush_tlb_page, - local_flush_tlb_mm, /* a.k.a. local_flush_tlb_range */ - unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, - unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, - unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, - unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, - unknown_ipi, unknown_ipi, unknown_ipi + IPI_TLB_ALL, + IPI_TLB_MM, + IPI_TLB_PAGE, + IPI_RESCHEDULE, + IPI_CPU_STOP }; void @@ -693,122 +670,165 @@ handle_ipi(struct pt_regs *regs) { int this_cpu = smp_processor_id(); volatile int * pending_ipis = &ipi_bits[this_cpu]; - int ops; + unsigned long ops; + + DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", + this_cpu, *pending_ipis, regs->pc)); + + mb(); /* Order interrupt and bit testing. */ + while ((ops = xchg(pending_ipis, 0)) != 0) { + mb(); /* Order bit clearing and data access. */ + do { + unsigned long which; + + which = ops & -ops; + ops &= ~which; + which = ffz(~which); + + if (which < IPI_RESCHEDULE) { + if (which == IPI_TLB_ALL) + tbia(); + else if (which == IPI_TLB_MM) { + struct mm_struct * mm; + mm = ipi_msg_flush_tb.p.flush_mm; + if (mm == current->mm) + flush_tlb_current(mm); + } + else /* IPI_TLB_PAGE */ { + struct vm_area_struct * vma; + struct mm_struct * mm; + unsigned long addr; - mb(); /* Order bit setting and interrupt. */ -#if 0 - printk("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", - this_cpu, *pending_ipis, regs->pc); -#endif - while ((ops = *pending_ipis)) { - int first; - for (first = 0; (ops & 1) == 0; ++first, ops >>= 1) - ; /* look for the first thing to do */ - clear_bit(first, pending_ipis); - mb(); /* Order bit clearing and data access. */ - if ((*ipi_func[first])(this_cpu)) - printk("%d\n", first); - mb(); /* Order data access and bit clearing. */ + vma = ipi_msg_flush_tb.p.flush_vma; + mm = vma->vm_mm; + addr = ipi_msg_flush_tb.flush_addr; + + if (mm == current->mm) + flush_tlb_current_page(mm, vma, addr); + } + clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); + } + else if (which == IPI_RESCHEDULE) { + /* Reschedule callback. Everything to be done + is done by the interrupt return path. */ + } + else if (which == IPI_CPU_STOP) { + halt(); + } + else { + printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n", + this_cpu, which); + } + } while (ops); + mb(); /* Order data access and bit testing. */ } + + cpu_data[this_cpu].ipi_count++; + if (hwrpb->txrdy) - secondary_console_message(); + secondary_console_message(); } -void -send_ipi_message(long to_whom, enum ipi_message_type operation) +static void +send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) { - int i; - unsigned int j; + long i, j; - mb(); /* Order out-of-band data and bit setting. */ - for (i = 0, j = 1; i < NR_CPUS; ++i, j += j) { - if ((to_whom & j) == 0) - continue; - set_bit(operation, &ipi_bits[i]); - mb(); /* Order bit setting and interrupt. */ - wripir(i); + /* Reduce the number of memory barriers by doing two loops, + one to set the bits, one to invoke the interrupts. */ + + mb(); /* Order out-of-band data and bit setting. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + set_bit(operation, &ipi_bits[i]); + } + + mb(); /* Order bit setting and interrupt. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + wripir(i); } } int smp_info(char *buffer) { - int i; + long i; unsigned long sum = 0; for (i = 0; i < NR_CPUS; i++) - sum += ipicnt[i]; + sum += cpu_data[i].ipi_count; - return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", + return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", smp_num_probed, smp_num_cpus, cpu_present_map, sum); } -/* wrapper for call from panic() */ void -smp_message_pass(int target, int msg, unsigned long data, int wait) +smp_send_reschedule(int cpu) { - int me = smp_processor_id(); - - if (msg != MSG_STOP_CPU) - goto barf; + send_ipi_message(1 << cpu, IPI_RESCHEDULE); +} - 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); - panic("Bogon SMP message pass."); +void +smp_send_stop(void) +{ + unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); + send_ipi_message(to_whom, IPI_CPU_STOP); } void flush_tlb_all(void) { - unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id()); - int timeout = 10000; + unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); + long timeout = 1000000; spin_lock_own(&kernel_flag, "flush_tlb_all"); ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, TLB_ALL); + send_ipi_message(to_whom, IPI_TLB_ALL); tbia(); - while (ipi_msg_flush_tb.flush_tb_mask) { - if (--timeout < 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - break; - } - /* Wait for all clear from other CPUs. */ - udelay(100); + while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { + udelay(1); + barrier(); + } + + if (timeout == 0) { + printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", + smp_processor_id(), + ipi_msg_flush_tb.flush_tb_mask); + ipi_msg_flush_tb.flush_tb_mask = 0; } } void flush_tlb_mm(struct mm_struct *mm) { - unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id()); - int timeout = 10000; + unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); + long timeout = 1000000; spin_lock_own(&kernel_flag, "flush_tlb_mm"); - ipi_msg_flush_tb.p.flush_mm = mm; ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, TLB_MM); + ipi_msg_flush_tb.p.flush_mm = mm; + send_ipi_message(to_whom, IPI_TLB_MM); if (mm != current->mm) flush_tlb_other(mm); else flush_tlb_current(mm); - while (ipi_msg_flush_tb.flush_tb_mask) { - if (--timeout < 0) { - printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - break; - } - udelay(100); - ; /* Wait for all clear from other CPUs. */ + while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { + udelay(1); + barrier(); + } + + if (timeout == 0) { + printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", + smp_processor_id(), + ipi_msg_flush_tb.flush_tb_mask); + ipi_msg_flush_tb.flush_tb_mask = 0; } } @@ -816,68 +836,40 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { int cpu = smp_processor_id(); - unsigned int to_whom = cpu_present_map ^ (1 << cpu); + unsigned long to_whom = cpu_present_map ^ (1 << cpu); struct mm_struct * mm = vma->vm_mm; - int timeout = 10000; + int timeout = 1000000; spin_lock_own(&kernel_flag, "flush_tlb_page"); + ipi_msg_flush_tb.flush_tb_mask = to_whom; ipi_msg_flush_tb.p.flush_vma = vma; ipi_msg_flush_tb.flush_addr = addr; - ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, TLB_PAGE); + send_ipi_message(to_whom, IPI_TLB_PAGE); if (mm != current->mm) flush_tlb_other(mm); else flush_tlb_current_page(mm, vma, addr); - while (ipi_msg_flush_tb.flush_tb_mask) { - if (--timeout < 0) { - printk("flush_tlb_page: STUCK on CPU %d [0x%x,0x%lx,%d]\n", - cpu, ipi_msg_flush_tb.flush_tb_mask, addr, - global_irq_holder); - ipi_msg_flush_tb.flush_tb_mask = 0; - break; - } - udelay(100); - ; /* Wait for all clear from other CPUs. */ + while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { + udelay(1); + barrier(); + } + + if (timeout == 0) { + printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n", + smp_processor_id(), + ipi_msg_flush_tb.flush_tb_mask); + ipi_msg_flush_tb.flush_tb_mask = 0; } } void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { -#if 0 + /* On the Alpha we always flush the whole user tlb. */ flush_tlb_mm(mm); -#else - unsigned int to_whom; - int timeout; - - timeout = 10000; - to_whom = cpu_present_map ^ (1 << smp_processor_id()); - - spin_lock_own(&kernel_flag, "flush_tlb_range"); - - ipi_msg_flush_tb.p.flush_mm = mm; - ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, TLB_MM); - - if (mm != current->mm) - flush_tlb_other(mm); - else - flush_tlb_current(mm); - - while (ipi_msg_flush_tb.flush_tb_mask) { - if (--timeout < 0) { - printk("flush_tlb_range: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - break; - } - udelay(100); /* Wait for all clear from other CPUs. */ - } -#endif } #if DEBUG_SPINLOCK @@ -902,8 +894,8 @@ spinlock_restore_ipl(long prev) #else -#define spinlock_raise_ipl(LOCK) 0 -#define spinlock_restore_ipl(PREV) ((void)0) +#define spinlock_raise_ipl(LOCK) ((void)(LOCK), 0) +#define spinlock_restore_ipl(PREV) ((void)(PREV)) #endif /* MANAGE_SPINLOCK_IPL */ diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 9ac7abb36..656e5d868 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -125,6 +125,7 @@ dp264_init_irq(void) outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; @@ -287,6 +288,29 @@ monet_swizzle(struct pci_dev *dev, int *pinp) return slot; } +static int __init +webbrick_map_irq(struct pci_dev *dev, int slot, int pin) +{ + static char irq_tab[13][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { -1, -1, -1, -1, -1}, /* IdSel 7 ISA Bridge */ + { -1, -1, -1, -1, -1}, /* IdSel 8 unused */ + { 29, 29, 29, 29, 29}, /* IdSel 9 21143 #1 */ + { -1, -1, -1, -1, -1}, /* IdSel 10 unused */ + { 30, 30, 30, 30, 30}, /* IdSel 11 21143 #2 */ + { -1, -1, -1, -1, -1}, /* IdSel 12 unused */ + { -1, -1, -1, -1, -1}, /* IdSel 13 unused */ + { 47, 47, 46, 45, 44}, /* IdSel 14 slot 0 */ + { 39, 39, 38, 37, 36}, /* IdSel 15 slot 1 */ + { 43, 43, 42, 41, 40}, /* IdSel 16 slot 2 */ + { 35, 35, 34, 33, 32}, /* IdSel 17 slot 3 */ +}; + const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5; + int irq = COMMON_TABLE_LOOKUP; + + return irq; +} + static void __init dp264_pci_fixup(void) { @@ -304,6 +328,14 @@ monet_pci_fixup(void) SMC669_Init(); } +static void __init +webbrick_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(webbrick_map_irq, common_swizzle); + SMC669_Init(); +} + /* * The System Vectors @@ -353,5 +385,27 @@ struct alpha_machine_vector monet_mv __initmv = { pci_fixup: monet_pci_fixup, kill_arch: generic_kill_arch, }; -/* No alpha_mv alias for monet, since we compile it in unconditionally + +struct alpha_machine_vector webbrick_mv __initmv = { + vector_name: "Webbrick", + 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: webbrick_pci_fixup, + kill_arch: generic_kill_arch, +}; +/* No alpha_mv alias for webbrick, since we compile it in unconditionally with DP264; setup_arch knows how to cope. */ diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index e8fc32fcd..19d79c060 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -159,7 +159,7 @@ rawhide_map_irq(struct pci_dev *dev, int slot, int pin) static void __init rawhide_pci_fixup(void) { - layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + layout_all_busses(DEFAULT_IO_BASE, RAWHIDE_DEFAULT_MEM_BASE); common_pci_fixup(rawhide_map_irq, common_swizzle); } diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c index a7ae730d8..4d52c256b 100644 --- a/arch/alpha/kernel/sys_ruffian.c +++ b/arch/alpha/kernel/sys_ruffian.c @@ -82,7 +82,7 @@ ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) * then all the PCI slots/INTXs (12-31) * flash(5) :DWH: */ - pld &= 0x00000000ffffff9fUL; /* was ffff7f */ + pld &= 0x00000000ffffff9fUL; /* was ffff7f */ /* * Now for every possible bit set, work through them and call @@ -92,6 +92,12 @@ ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) i = ffz(~pld); pld &= pld - 1; /* clear least bit set */ if (i == 7) { /* if ISA int */ + /* Ruffian does not have the RTC connected to + the CPU timer interrupt. Instead, it uses the + PIT connected to IRQ 0. So we must detect that + and route that specifically to where we expected + to find the timer interrupt come in. */ + /* Copy this code from isa_device_interrupt because we need to hook into int 0 for the timer. I refuse to soil device_interrupt with ifdefs. */ @@ -107,17 +113,17 @@ ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) if (j == 7 && !(inb(0x20) & 0x80)) { /* It's only a passive release... */ } else if (j == 0) { - handle_irq(8, -1, regs); /* fake it */ + handle_irq(TIMER_IRQ, -1, regs); ruffian_ack_irq(0); } else { handle_irq(j, j, regs); } - } else { /* if not an ISA int */ + } else { /* if not an ISA int */ handle_irq(16 + i, 16 + i, regs); } - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - *(vulp)PYXIS_INT_REQ; /* read to force the write */ + *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); + *(vulp)PYXIS_INT_REQ; /* read to force the write */ } } @@ -216,7 +222,7 @@ ruffian_init_arch(unsigned long *mem_start, unsigned long *mem_end) pyxis_enable_errors(); if (!pyxis_srm_window_setup()) { - printk("ruffian_init_arch: Skipping window register rewrites." + printk("ruffian_init_arch: Skipping window register rewrites." "\n... Trust DeskStation firmware!\n"); } pyxis_finish_init_arch(); @@ -227,7 +233,10 @@ ruffian_init_pit (void) { /* Ruffian depends on the system timer established in MILO! */ request_region(0x70, 0x10, "timer"); - init_pit_rest(); + + outb(0xb6, 0x43); /* pit counter 2: speaker */ + outb(0x31, 0x42); + outb(0x13, 0x42); } static void diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c new file mode 100644 index 000000000..5d2cf5288 --- /dev/null +++ b/arch/alpha/kernel/sys_rx164.c @@ -0,0 +1,235 @@ +/* + * linux/arch/alpha/kernel/sys_rx164.c + * + * Copyright (C) 1995 David A Rusling + * Copyright (C) 1996 Jay A Estabrook + * Copyright (C) 1998 Richard Henderson + * + * Code supporting the RX164 (PCA56+POLARIS). + */ + +#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_polaris.h> + +#include "proto.h" +#include "irq.h" +#include "bios32.h" +#include "machvec.h" + + +static void +rx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ + if (irq >= 16) { + unsigned int temp; + pcibios_write_config_dword(0, 0, 0x74, ~mask >> 16); + pcibios_read_config_dword(0, 0, 0x74, &temp); + } + else if (irq >= 8) + outb(mask >> 8, 0xA1); /* ISA PIC2 */ + else + outb(mask, 0x21); /* ISA PIC1 */ +} + +static void +rx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +{ +#if 0 + 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 */ +#endif +} + +static void +rx164_isa_device_interrupt(unsigned long vector, struct pt_regs * regs) +{ + 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 the PIC 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 */ + + while (pic) { + int j = ffz(~pic); + pic &= pic - 1; + handle_irq(j, j, regs); + } +} + +static void +rx164_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + int i; + + /* Read the interrupt summary register. On Polaris, + * this is the DIRR register in PCI config space (offset 0x84) + */ + pld = 0; + pcibios_read_config_dword(0, 0, 0x84, (unsigned int *)&pld); + +#if 0 + printk("PLD 0x%lx\n", pld); +#endif + + if (pld & 0xffffffff00000000UL) pld &= 0x00000000ffffffffUL; + + /* + * 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 == 20) { + rx164_isa_device_interrupt(vector, regs); + } else { + handle_irq(16+i, 16+i, regs); + } + } +} + +static void +rx164_init_irq(void) +{ + unsigned int temp; + + STANDARD_INIT_IRQ_PROLOG; + + pcibios_write_config_dword(0, 0, 0x74, (~alpha_irq_mask >> 16)); + pcibios_read_config_dword(0, 0, 0x74, &temp); + + enable_irq(16 + 20); /* enable ISA interrupts */ + enable_irq(2); /* enable cascade */ +} +/* The RX164 changed its interrupt routing between pass1 and pass2... + * + * PASS1: + * + * Slot IDSEL INTA INTB INTC INTD + * 0 6 5 10 15 20 + * 1 7 4 9 14 19 + * 2 5 3 8 13 18 + * 3 9 2 7 12 17 + * 4 10 1 6 11 16 + * + * PASS2: + * Slot IDSEL INTA INTB INTC INTD + * 0 5 1 7 12 17 + * 1 6 2 8 13 18 + * 2 8 3 9 14 19 + * 3 9 4 10 15 20 + * 4 10 5 11 16 6 + * + */ + +/* + * IdSel + * 5 32 bit PCI option slot 0 + * 6 64 bit PCI option slot 1 + * 7 PCI-ISA bridge + * 7 64 bit PCI option slot 2 + * 9 32 bit PCI option slot 3 + * 10 PCI-PCI bridge + * + */ + +static int __init +rx164_map_irq(struct pci_dev *dev, int slot, int pin) +{ +#if 0 + char irq_tab_pass1[6][5] = { + /*INT INTA INTB INTC INTD */ + { 16+3, 16+3, 16+8, 16+13, 16+18}, /* IdSel 5, slot 2 */ + { 16+5, 16+5, 16+10, 16+15, 16+20}, /* IdSel 6, slot 0 */ + { 16+4, 16+4, 16+9, 16+14, 16+19}, /* IdSel 7, slot 1 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, PCI/ISA bridge */ + { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */ + { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */ + }; +#endif + char irq_tab[6][5] = { + /*INT INTA INTB INTC INTD */ + { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */ + { 16+1, 16+1, 16+7, 16+12, 16+17}, /* IdSel 6, slot 1 */ + { -1, -1, -1, -1, -1}, /* IdSel 7, PCI/ISA bridge */ + { 16+2, 16+2, 16+8, 16+13, 16+18}, /* IdSel 8, slot 2 */ + { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */ + { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */ + }; + const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; + /* JRP - Need to figure out how to distinguish pass1 from pass2, + * and use the correct table... + */ + return COMMON_TABLE_LOOKUP; +} + +void __init +rx164_pci_fixup(void) +{ + layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); + common_pci_fixup(rx164_map_irq, common_swizzle); +} + + +/* + * The System Vector + */ + +struct alpha_machine_vector rx164_mv __initmv = { + vector_name: "RX164", + DO_EV5_MMU, + DO_DEFAULT_RTC, + DO_POLARIS_IO, + DO_POLARIS_BUS, + machine_check: polaris_machine_check, + max_dma_address: ALPHA_MAX_DMA_ADDRESS, + + nr_irqs: 40, + irq_probe_mask: _PROBE_MASK(40), + update_irq_hw: rx164_update_irq_hw, + ack_irq: generic_ack_irq, + device_interrupt: rx164_device_interrupt, + + init_arch: polaris_init_arch, + init_irq: rx164_init_irq, + init_pit: generic_init_pit, + pci_fixup: rx164_pci_fixup, + kill_arch: generic_kill_arch, +}; +ALIAS_MV(rx164) diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index b5aaf5d81..70d8720e9 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -232,7 +232,7 @@ noname_pci_fixup(void) * selected... :-( */ layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - sio_pci_fixup(noname_map_irq, 0x0b0a0f09); + sio_pci_fixup(noname_map_irq, 0x0b0a0f0d); sio_fixup_irq_levels(sio_collect_irq_levels()); enable_ide(0x26e); } diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index acbb76896..2f9363113 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -10,6 +10,8 @@ * 1995-03-26 Markus Kuhn * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 * precision CMOS clock update + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills * 1997-01-09 Adrian Sun * use interval timer if CONFIG_RTC=y * 1997-10-29 John Bowman (bowman@math.ualberta.ca) @@ -35,12 +37,7 @@ #include <linux/timex.h> #include "proto.h" - -#ifdef CONFIG_RTC -#define TIMER_IRQ 0 /* using pit for timer */ -#else -#define TIMER_IRQ 8 /* using rtc for timer */ -#endif +#include "irq.h" static int set_rtc_mmss(unsigned long); @@ -117,10 +114,10 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs) * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ - if (time_state != TIME_BAD + if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > state.last_rtc_update + 660 - && xtime.tv_usec >= 500000 - (tick >> 1) - && xtime.tv_usec <= 500000 + (tick >> 1)) { + && xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 + && xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { int tmp = set_rtc_mmss(xtime.tv_sec); state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); } @@ -163,43 +160,28 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, * drivers depend on them being initialized (e.g., joystick driver). */ -/* It is (normally) only counter 0 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); -#endif - - outb(0xb6, 0x43); /* counter 2: speaker */ - outb(0x31, 0x42); - outb(0x13, 0x42); -} - #ifdef CONFIG_RTC -static inline void +void rtc_init_pit (void) { unsigned char control; - /* Setup interval timer if /dev/rtc is being used */ + /* Turn off RTC interrupts before /dev/rtc is initialized */ + control = CMOS_READ(RTC_CONTROL); + control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); + CMOS_WRITE(control, RTC_CONTROL); + (void) CMOS_READ(RTC_INTR_FLAGS); + + request_region(0x40, 0x20, "timer"); /* reserve pit */ + + /* Setup interval timer. */ 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 */ - - /* Turn off RTC interrupts before /dev/rtc is initialized */ - control = CMOS_READ(RTC_CONTROL); - control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); - CMOS_WRITE(control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - init_pit_rest(); + outb(0xb6, 0x43); /* pit counter 2: speaker */ + outb(0x31, 0x42); + outb(0x13, 0x42); } #endif @@ -208,7 +190,7 @@ generic_init_pit (void) { unsigned char x; - /* Reset periodic interrupt frequency. */ + /* Reset periodic interrupt frequency. */ x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; if (x != 0x26 && x != 0x19 && x != 0x06) { printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); @@ -223,36 +205,26 @@ generic_init_pit (void) x &= ~(RTC_AIE | RTC_UIE); CMOS_WRITE(x, RTC_CONTROL); } - CMOS_READ(RTC_INTR_FLAGS); + (void) CMOS_READ(RTC_INTR_FLAGS); request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */ - /* Turn off the PIT. */ - outb(0x36, 0x43); /* counter 0: system timer */ + outb(0x36, 0x43); /* pit counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); - init_pit_rest(); + outb(0xb6, 0x43); /* pit counter 2: speaker */ + outb(0x31, 0x42); + outb(0x13, 0x42); } -/* 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 - - void time_init(void) { - void (*irq_handler)(int, void *, struct pt_regs *); + void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; unsigned long cycle_freq; - /* Initialize the timers. */ - init_pit(); - /* * The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the @@ -327,8 +299,8 @@ time_init(void) state.partial_tick = 0L; /* setup timer */ - irq_handler = timer_interrupt; - if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) + irq_handler = timer_interrupt; + if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) panic("Could not allocate timer IRQ!"); } @@ -383,9 +355,11 @@ do_settimeofday(struct timeval *tv) { cli(); xtime = *tv; - time_state = TIME_BAD; - time_maxerror = 0x70000000; - time_esterror = 0x70000000; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_state = TIME_ERROR; /* p. 24, (a) */ + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; sti(); } @@ -396,6 +370,9 @@ do_settimeofday(struct timeval *tv) * nowtime is written into the registers of the CMOS clock, it will * jump to the next second precisely 500 ms later. Check the Motorola * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! */ static int set_rtc_mmss(unsigned long nowtime) @@ -437,8 +414,12 @@ set_rtc_mmss(unsigned long nowtime) } CMOS_WRITE(real_seconds,RTC_SECONDS); CMOS_WRITE(real_minutes,RTC_MINUTES); - } else - retval = -1; + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } /* The following flags have to be released exactly in this order, * otherwise the DS12887 (popular MC146818A clone with integrated diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index e87f8b903..400adf0e1 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 strcasecmp.o \ + csum_ipv6_magic.o strcasecmp.o semaphore.o \ srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o lib.a: $(OBJS) diff --git a/arch/alpha/lib/semaphore.S b/arch/alpha/lib/semaphore.S new file mode 100644 index 000000000..3dbeeec5f --- /dev/null +++ b/arch/alpha/lib/semaphore.S @@ -0,0 +1,183 @@ +/* + * linux/arch/alpha/lib/semaphore.S + * + * Copyright (C) 1999 Richard Henderson + */ + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + */ + + .set noat + .set noreorder + .align 4 + +/* __down_failed takes the semaphore in $24, clobbers $24 and $28. */ + + .globl __down_failed + .ent __down_failed +__down_failed: + ldgp $29,0($27) + lda $30, -20*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $25, 17*8($30) + stq $26, 18*8($30) + .frame $30, 20*8, $28 + .prologue 1 + + mov $24, $16 + jsr __down + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $25, 17*8($30) + ldq $26, 18*8($30) + lda $30, 20*8($30) + ret $31, ($28), 0 + .end __down_failed + +/* __down_failed_interruptible takes the semaphore in $24, + clobbers $28, returns success in $24. */ + + .globl __down_failed_interruptible + .ent __down_failed_interruptible +__down_failed_interruptible: + ldgp $29,0($27) + lda $30, -20*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $25, 17*8($30) + stq $26, 18*8($30) + .frame $30, 20*8, $28 + .prologue 1 + + mov $24, $16 + jsr __down_interruptible + mov $0, $24 + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $25, 17*8($30) + ldq $26, 18*8($30) + lda $30, 20*8($30) + ret $31, ($28), 0 + .end __down_failed_interruptible + +/* __up_wakeup takes the semaphore in $24, clobbers $24 and $28. */ + + .globl __up_wakeup + .ent __up_wakeup +__up_wakeup: + ldgp $29,0($27) + lda $30, -20*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $25, 17*8($30) + stq $26, 18*8($30) + .frame $30, 20*8, $28 + .prologue 1 + + mov $24, $16 + jsr __up + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $25, 17*8($30) + ldq $26, 18*8($30) + lda $30, 20*8($30) + ret $31, ($28), 0 + .end __up_wakeup |