summaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /arch/alpha
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/Makefile35
-rw-r--r--arch/alpha/config.in14
-rw-r--r--arch/alpha/defconfig1
-rw-r--r--arch/alpha/kernel/Makefile12
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c10
-rw-r--r--arch/alpha/kernel/bios32.h29
-rw-r--r--arch/alpha/kernel/core_polaris.c275
-rw-r--r--arch/alpha/kernel/core_t2.c47
-rw-r--r--arch/alpha/kernel/core_tsunami.c19
-rw-r--r--arch/alpha/kernel/entry.S23
-rw-r--r--arch/alpha/kernel/irq.c40
-rw-r--r--arch/alpha/kernel/irq.h10
-rw-r--r--arch/alpha/kernel/machvec.h7
-rw-r--r--arch/alpha/kernel/osf_sys.c66
-rw-r--r--arch/alpha/kernel/process.c8
-rw-r--r--arch/alpha/kernel/proto.h20
-rw-r--r--arch/alpha/kernel/ptrace.c4
-rw-r--r--arch/alpha/kernel/setup.c118
-rw-r--r--arch/alpha/kernel/smp.c932
-rw-r--r--arch/alpha/kernel/sys_dp264.c56
-rw-r--r--arch/alpha/kernel/sys_rawhide.c2
-rw-r--r--arch/alpha/kernel/sys_ruffian.c23
-rw-r--r--arch/alpha/kernel/sys_rx164.c235
-rw-r--r--arch/alpha/kernel/sys_sio.c2
-rw-r--r--arch/alpha/kernel/time.c103
-rw-r--r--arch/alpha/lib/Makefile2
-rw-r--r--arch/alpha/lib/semaphore.S183
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, &regs);
+ 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" (&current_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