summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-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
-rw-r--r--arch/arm/Makefile7
-rw-r--r--arch/arm/config.in34
-rw-r--r--arch/arm/kernel/Makefile54
-rw-r--r--arch/arm/kernel/calls.S2
-rw-r--r--arch/arm/kernel/dec21285.c100
-rw-r--r--arch/arm/kernel/dma-a5k.c2
-rw-r--r--arch/arm/kernel/dma-ebsa285.c123
-rw-r--r--arch/arm/kernel/dma-isa.c107
-rw-r--r--arch/arm/kernel/dma-isa.h25
-rw-r--r--arch/arm/kernel/dma-vnc.c51
-rw-r--r--arch/arm/kernel/dma.c20
-rw-r--r--arch/arm/kernel/ecard.c360
-rw-r--r--arch/arm/kernel/entry-armo.S52
-rw-r--r--arch/arm/kernel/entry-armv.S87
-rw-r--r--arch/arm/kernel/entry-common.S2
-rw-r--r--arch/arm/kernel/fiq.c9
-rw-r--r--arch/arm/kernel/head-armo.S3
-rw-r--r--arch/arm/kernel/head-armv.S49
-rw-r--r--arch/arm/kernel/hw-ebsa285.c161
-rw-r--r--arch/arm/kernel/init_task.c1
-rw-r--r--arch/arm/kernel/irq.c6
-rw-r--r--arch/arm/kernel/setup.c65
-rw-r--r--arch/arm/kernel/sys_arm.c3
-rw-r--r--arch/arm/kernel/time.c10
-rw-r--r--arch/arm/kernel/traps.c4
-rw-r--r--arch/arm/lib/Makefile4
-rw-r--r--arch/arm/lib/io-ebsa285.S71
-rw-r--r--arch/arm/mm/fault-armo.c2
-rw-r--r--arch/arm/mm/fault-armv.c2
-rw-r--r--arch/arm/mm/init.c9
-rw-r--r--arch/arm/mm/mm-ebsa285.c62
-rw-r--r--arch/arm/mm/mm-rpc.c3
-rw-r--r--arch/arm/mm/mm-vnc.c19
-rw-r--r--arch/arm/mm/proc-sa110.S16
-rw-r--r--arch/i386/Makefile4
-rw-r--r--arch/i386/boot/Makefile2
-rw-r--r--arch/i386/config.in64
-rw-r--r--arch/i386/defconfig79
-rw-r--r--arch/i386/kernel/Makefile12
-rw-r--r--arch/i386/kernel/apm.c206
-rw-r--r--arch/i386/kernel/bios32.c6
-rw-r--r--arch/i386/kernel/entry.S10
-rw-r--r--arch/i386/kernel/head.S12
-rw-r--r--arch/i386/kernel/i386_ksyms.c5
-rw-r--r--arch/i386/kernel/io_apic.c15
-rw-r--r--arch/i386/kernel/ioport.c10
-rw-r--r--arch/i386/kernel/irq.c403
-rw-r--r--arch/i386/kernel/irq.h58
-rw-r--r--arch/i386/kernel/mtrr.c8
-rw-r--r--arch/i386/kernel/process.c71
-rw-r--r--arch/i386/kernel/ptrace.c8
-rw-r--r--arch/i386/kernel/setup.c325
-rw-r--r--arch/i386/kernel/smp.c838
-rw-r--r--arch/i386/kernel/sys_i386.c96
-rw-r--r--arch/i386/kernel/time.c194
-rw-r--r--arch/i386/kernel/traps.c121
-rw-r--r--arch/i386/kernel/visws_apic.c407
-rw-r--r--arch/i386/lib/Makefile3
-rw-r--r--arch/i386/lib/checksum.S447
-rw-r--r--arch/i386/lib/checksum.c459
-rw-r--r--arch/i386/lib/delay.c12
-rw-r--r--arch/i386/lib/old-checksum.c19
-rw-r--r--arch/i386/lib/usercopy.c28
-rw-r--r--arch/i386/mm/init.c62
-rw-r--r--arch/i386/vmlinux.lds4
-rw-r--r--arch/m68k/Makefile12
-rw-r--r--arch/m68k/amiga/amiints.c4
-rw-r--r--arch/m68k/amiga/config.c2
-rw-r--r--arch/m68k/amiga/pcmcia.c3
-rw-r--r--arch/m68k/apollo/dn_ints.c2
-rw-r--r--arch/m68k/atari/atakeyb.c7
-rw-r--r--arch/m68k/atari/config.c2
-rw-r--r--arch/m68k/bvme6000/bvmeints.c9
-rw-r--r--arch/m68k/bvme6000/config.c9
-rw-r--r--arch/m68k/config.in42
-rw-r--r--arch/m68k/defconfig34
-rw-r--r--arch/m68k/fpsp040/skeleton.S7
-rw-r--r--arch/m68k/hp300/config.c6
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S7
-rw-r--r--arch/m68k/kernel/Makefile9
-rw-r--r--arch/m68k/kernel/entry.S101
-rw-r--r--arch/m68k/kernel/head.S3855
-rw-r--r--arch/m68k/kernel/m68k_defs.c72
-rw-r--r--arch/m68k/kernel/m68k_defs.h6
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c7
-rw-r--r--arch/m68k/kernel/process.c69
-rw-r--r--arch/m68k/kernel/ptrace.c13
-rw-r--r--arch/m68k/kernel/setup.c8
-rw-r--r--arch/m68k/kernel/signal.c4
-rw-r--r--arch/m68k/kernel/sys_m68k.c85
-rw-r--r--arch/m68k/kernel/time.c51
-rw-r--r--arch/m68k/mac/config.c49
-rw-r--r--arch/m68k/mac/debug.c156
-rw-r--r--arch/m68k/mac/macboing.c357
-rw-r--r--arch/m68k/mac/macints.c203
-rw-r--r--arch/m68k/mac/mackeyb.c75
-rw-r--r--arch/m68k/mac/via6522.c23
-rw-r--r--arch/m68k/mm/fault.c47
-rw-r--r--arch/m68k/mm/init.c287
-rw-r--r--arch/m68k/mm/kmap.c696
-rw-r--r--arch/m68k/mm/memory.c136
-rw-r--r--arch/m68k/mvme16x/16xints.c9
-rw-r--r--arch/m68k/vmlinux.lds3
-rw-r--r--arch/mips/config.in36
-rw-r--r--arch/mips/defconfig55
-rw-r--r--arch/mips/kernel/irq.c4
-rw-r--r--arch/mips/kernel/mips_ksyms.c3
-rw-r--r--arch/mips/kernel/ptrace.c6
-rw-r--r--arch/mips/kernel/scall_o32.S1
-rw-r--r--arch/mips/kernel/signal.c4
-rw-r--r--arch/mips/kernel/syscall.c19
-rw-r--r--arch/mips/kernel/sysirix.c54
-rw-r--r--arch/mips/kernel/time.c28
-rw-r--r--arch/mips/mm/init.c7
-rw-r--r--arch/ppc/8xx_io/enet.c8
-rw-r--r--arch/ppc/8xx_io/uart.c2
-rw-r--r--arch/ppc/Makefile2
-rw-r--r--arch/ppc/amiga/amiints.c4
-rw-r--r--arch/ppc/amiga/bootinfo.c4
-rw-r--r--arch/ppc/amiga/config.c2
-rw-r--r--arch/ppc/apus_defconfig1
-rw-r--r--arch/ppc/boot/Makefile3
-rw-r--r--arch/ppc/boot/misc.c36
-rw-r--r--arch/ppc/boot/ns16550.c56
-rw-r--r--arch/ppc/boot/ns16550.h34
-rw-r--r--arch/ppc/chrp_defconfig1
-rw-r--r--arch/ppc/coffboot/Makefile12
-rw-r--r--arch/ppc/common_defconfig99
-rw-r--r--arch/ppc/config.in4
-rw-r--r--arch/ppc/defconfig72
-rw-r--r--arch/ppc/kernel/Makefile9
-rw-r--r--arch/ppc/kernel/apus_setup.c4
-rw-r--r--arch/ppc/kernel/head.S162
-rw-r--r--arch/ppc/kernel/idle.c21
-rw-r--r--arch/ppc/kernel/irq.c75
-rw-r--r--arch/ppc/kernel/mbx_setup.c28
-rw-r--r--arch/ppc/kernel/misc.S185
-rw-r--r--arch/ppc/kernel/pci.c33
-rw-r--r--arch/ppc/kernel/ppc_htab.c3
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c19
-rw-r--r--arch/ppc/kernel/prep_pci.c20
-rw-r--r--arch/ppc/kernel/prep_setup.c5
-rw-r--r--arch/ppc/kernel/process.c24
-rw-r--r--arch/ppc/kernel/ptrace.c4
-rw-r--r--arch/ppc/kernel/setup.c31
-rw-r--r--arch/ppc/kernel/smp.c60
-rw-r--r--arch/ppc/kernel/time.c53
-rw-r--r--arch/ppc/kernel/traps.c3
-rw-r--r--arch/ppc/lib/Makefile2
-rw-r--r--arch/ppc/lib/locks.c10
-rw-r--r--arch/ppc/mbx_defconfig89
-rw-r--r--arch/ppc/mm/fault.c2
-rw-r--r--arch/ppc/mm/init.c132
-rw-r--r--arch/ppc/pmac_defconfig72
-rw-r--r--arch/ppc/prep_defconfig1
-rw-r--r--arch/ppc/vmlinux.lds3
-rw-r--r--arch/sparc/ap1000/util.c2
-rw-r--r--arch/sparc/config.in3
-rw-r--r--arch/sparc/defconfig1
-rw-r--r--arch/sparc/kernel/Makefile24
-rw-r--r--arch/sparc/kernel/ptrace.c8
-rw-r--r--arch/sparc/kernel/time.c30
-rw-r--r--arch/sparc/lib/Makefile4
-rw-r--r--arch/sparc/lib/checksum.S4
-rw-r--r--arch/sparc/mm/Makefile2
-rw-r--r--arch/sparc/mm/srmmu.c10
-rw-r--r--arch/sparc64/Makefile2
-rw-r--r--arch/sparc64/config.in3
-rw-r--r--arch/sparc64/defconfig1
-rw-r--r--arch/sparc64/kernel/Makefile27
-rw-r--r--arch/sparc64/kernel/time.c16
198 files changed, 10828 insertions, 5172 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
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 5ef8ea75e..967ee6766 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -120,6 +120,7 @@ COMPRESSED_HEAD = head-nexuspci.o
endif
ifeq ($(CONFIG_ARCH_VNC),y)
+TEXTADDR = 0xC000C000
MACHINE = vnc
ARCHDIR = vnc
endif
@@ -141,7 +142,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
OBJDUMP = $(CROSS_COMPILE)objdump
CPP = $(CC) -E
ARCHCC := $(word 1,$(CC))
-GCCLIB := `$(ARCHCC) $(CFLAGS_PROC) --print-libgcc-file-name`
+GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name`
#GCCARCH := -B/usr/bin/arm-linuxelf-
HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=)
ifeq ($(CONFIG_FRAME_POINTER),y)
@@ -160,10 +161,10 @@ LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
BLOCK_DRIVERS := drivers/block/block.a
CDROM_DRIVERS := drivers/cdrom/cdrom.a
ifeq ($(CONFIG_FB),y)
-CHAR_DRIVERS := arch/arm/drivers/char1/char.a
+CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
else
ifeq ($(CONFIG_VGA_CONSOLE),y)
-CHAR_DRIVERS := arch/arm/drivers/char1/char.a
+CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a
else
CHAR_DRIVERS := arch/arm/drivers/char/char.a
endif
diff --git a/arch/arm/config.in b/arch/arm/config.in
index 2b59a964c..467218db7 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -38,15 +38,22 @@ if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
define_bool CONFIG_BUS_I2C y
fi
-# These machines have PCI/may have PCI
+# These machines always have PCI
if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
"$CONFIG_ARCH_VNC" = "y" ]; then
define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
+ bool "PCI support" CONFIG_PCI
+fi
+
+# These machines have ISA-DMA
+if [ "$CONFIG_CATS" = "y" -o \
+ "$CONFIG_ARCH_VNC" = "y" ]; then
+ define_bool CONFIG_ISA_DMA y
else
- if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
- bool "PCI support" CONFIG_PCI
- fi
+ define_bool CONFIG_ISA_DMA n
fi
# Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has
@@ -122,6 +129,11 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
fi
fi
fi
+if [ "$CONFIG_ARCH_EBSA285" = "y" -o \
+ "$CONFIG_ARCH_EBSA110" = "y" -o \
+ "$CONFIG_ARCH_VNC" = "y" ]; then
+ string 'Initial kernel command string' CONFIG_CMDLINE
+fi
endmenu
source drivers/pnp/Config.in
@@ -132,16 +144,20 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
source drivers/acorn/block/Config.in
fi
-source arch/arm/drivers/char/Config.in
+if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then
+ source arch/arm/drivers/char/Config.in
+else
+ source drivers/char/Config.in
+fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ source drivers/acorn/char/Config.in
+fi
if [ "$CONFIG_VT" = "y" ]; then
mainmenu_option next_comment
comment 'Console drivers'
if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
bool 'VGA text console' CONFIG_VGA_CONSOLE
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Video mode selection support' CONFIG_VIDEO_SELECT
- fi
fi
bool 'Support Frame buffer devices' CONFIG_FB
source drivers/video/Config.in
@@ -195,8 +211,6 @@ fi
source fs/Config.in
-source fs/nls/Config.in
-
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 542ca995a..23b2c1267 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,44 +10,54 @@ ENTRY_OBJ = entry-$(PROCESSOR).o
O_TARGET := kernel.o
O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \
- signal.o sys_arm.o time.o traps.o fiq.o
+ signal.o sys_arm.o time.o traps.o
+
+DMA_OBJS_arc = dma-arc.o
+DMA_OBJS_a5k = dma-a5k.o
+DMA_OBJS_rpc = dma-rpc.o
+DMA_OBJS_ebsa110 = dma-dummy.o
+DMA_OBJS_ebsa285 = dma-ebsa285.o
+DMA_OBJS_nexuspci =
+DMA_OBJS_vnc = dma-vnc.o
+
+O_OBJS_arc = ecard.o iic.o fiq.o oldlatches.o
+O_OBJS_a5k = ecard.o iic.o fiq.o
+O_OBJS_rpc = ecard.o iic.o fiq.o
+O_OBJS_ebsa110 = leds-ebsa110.o
+O_OBJS_ebsa285 = leds-ebsa285.o hw-ebsa285.o
+O_OBJS_nexuspci =
+O_OBJS_vnc = leds-ebsa285.o hw-vnc.o
all: lib kernel.o $(HEAD_OBJ) init_task.o
ifeq ($(CONFIG_MODULES),y)
-OX_OBJS = armksyms.o
+ OX_OBJS = armksyms.o
else
-O_OBJS += armksyms.o
+ O_OBJS += armksyms.o
endif
-ifdef CONFIG_ARCH_ACORN
- O_OBJS += ecard.o iic.o
- ifdef CONFIG_ARCH_ARC
- O_OBJS += oldlatches.o
+ifeq ($(MACHINE),nexuspci)
+ ifdef CONFIG_PCI
+ O_OBJS += plx9080.o
endif
- O_OBJS += dma-$(MACHINE).o
- OX_OBJS += dma.o
-endif
-
-ifeq ($(MACHINE),ebsa110)
- O_OBJS += dma-dummy.o leds-ebsa110.o
-endif
-
-ifeq ($(MACHINE),ebsa285)
- OX_OBJS += dma.o
- O_OBJS += dma-ebsa285.o leds-ebsa285.o
+else
ifdef CONFIG_PCI
O_OBJS += dec21285.o
endif
endif
-ifeq ($(MACHINE),nexuspci)
- O_OBJS += dma-dummy.o
- ifdef CONFIG_PCI
- O_OBJS += plx9080.o
+ifneq ($(DMA_OBJS_$(MACHINE)),)
+ OX_OBJS += dma.o
+ O_OBJS += $(DMA_OBJS_$(MACHINE))
+ ifeq ($(CONFIG_ISA_DMA),y)
+ O_OBJS += dma-isa.o
endif
+else
+ O_OBJS += dma-dummy.o
endif
+O_OBJS += $(O_OBJS_$(MACHINE))
+
$(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
$(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 751f9616a..46f71fa92 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -9,7 +9,7 @@
#define NR_syscalls 256
#else
-/* 0 */ .long SYMBOL_NAME(sys_setup)
+/* 0 */ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork_wrapper)
.long SYMBOL_NAME(sys_read)
diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c
index de4861b82..aa66ee04a 100644
--- a/arch/arm/kernel/dec21285.c
+++ b/arch/arm/kernel/dec21285.c
@@ -3,14 +3,23 @@
*
* Copyright (C) 1998 Russell King, Phil Blundell
*/
+#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
#include <linux/init.h>
+#include <asm/irq.h>
#include <asm/system.h>
#define MAX_SLOTS 20
+extern void pcibios_fixup_ebsa285(struct pci_dev *dev);
+extern void pcibios_init_ebsa285(void);
+extern void pcibios_fixup_vnc(struct pci_dev *dev);
+extern void pcibios_init_vnc(void);
+
int
pcibios_present(void)
{
@@ -24,12 +33,11 @@ pcibios_base_address(unsigned char bus, unsigned char dev_fn)
int slot = PCI_SLOT(dev_fn);
if (slot < MAX_SLOTS)
- return 0xf8c00000 + (slot << 11);
+ return 0xf8c00000 + (slot << 11) + (PCI_FUNC(dev_fn) << 8);
else
return 0;
- } else {
+ } else
return 0xf9000000 | (bus << 16) | (dev_fn << 8);
- }
}
int
@@ -119,56 +127,35 @@ pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_SUCCESSFUL;
}
-static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
-static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
-
-__initfunc(static int ebsa_irqval(struct pci_dev *dev))
+__initfunc(void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set))
{
- unsigned char pin;
-
- pcibios_read_config_byte(dev->bus->number,
- dev->devfn,
- PCI_INTERRUPT_PIN,
- &pin);
-
- return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
+ unsigned short cmd;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd = (cmd & ~clear) | set;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
}
-__initfunc(static int cats_irqval(struct pci_dev *dev))
+__initfunc(void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr))
{
- if (dev->irq >= 128)
- return 32 + (dev->irq & 0x1f);
-
- switch (dev->irq) {
- case 1:
- case 2:
- case 3:
- case 4:
- return irqmap_cats[dev->irq - 1];
- case 0:
- return 0;
- }
+ int reg = PCI_BASE_ADDRESS_0 + (idx << 2);
- printk("PCI: device %02x:%02x has unknown irq line %x\n",
- dev->bus->number, dev->devfn, dev->irq);
- return 0;
+ pci_write_config_dword(dev, reg, addr);
+ pci_read_config_dword(dev, reg, &addr);
+
+ dev->base_address[idx] = addr;
}
__initfunc(void pcibios_fixup(void))
{
struct pci_dev *dev;
- unsigned char cmd;
for (dev = pci_devices; dev; dev = dev->next) {
- /* sort out the irq mapping for this device */
- switch (machine_type) {
- case MACH_TYPE_EBSA285:
- dev->irq = ebsa_irqval(dev);
- break;
- case MACH_TYPE_CATS:
- dev->irq = cats_irqval(dev);
- break;
- }
+ if (machine_is_ebsa285() || machine_is_cats())
+ pcibios_fixup_ebsa285(dev);
+ if (machine_is_netwinder())
+ pcibios_fixup_vnc(dev);
+
pcibios_write_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_LINE, dev->irq);
@@ -176,34 +163,19 @@ __initfunc(void pcibios_fixup(void))
"PCI: %02x:%02x [%04x/%04x] on irq %d\n",
dev->bus->number, dev->devfn,
dev->vendor, dev->device, dev->irq);
-
- /* Turn on bus mastering - boot loader doesn't
- * - perhaps it should! - dag
- */
- pcibios_read_config_byte(dev->bus->number, dev->devfn,
- PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pcibios_write_config_byte(dev->bus->number, dev->devfn,
- PCI_COMMAND, cmd);
}
+ if (machine_is_netwinder())
+ hw_init();
}
__initfunc(void pcibios_init(void))
{
- int rev;
-
- rev = *(unsigned char *)0xfe000008;
- printk("DEC21285 PCI revision %02X\n", rev);
-
- /*
- * Map our SDRAM at a known address in PCI space, just in case
- * the firmware had other ideas. Using a nonzero base is slightly
- * bizarre but apparently necessary to avoid problems with some
- * video cards.
- *
- * We should really only do this if we are the configuration master.
- */
- *((unsigned long *)0xfe000018) = 0x10000000;
+ if (machine_is_ebsa285() || machine_is_cats())
+ pcibios_init_ebsa285();
+ if (machine_is_netwinder())
+ pcibios_init_vnc();
+
+ printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008);
}
__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
diff --git a/arch/arm/kernel/dma-a5k.c b/arch/arm/kernel/dma-a5k.c
index 50ee42435..18bbf0c9c 100644
--- a/arch/arm/kernel/dma-a5k.c
+++ b/arch/arm/kernel/dma-a5k.c
@@ -16,7 +16,7 @@
#include "dma.h"
-static struct fiq_handler fh = { "floppydma", NULL };
+static struct fiq_handler fh = { NULL, "floppydma", NULL, NULL };
int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_id)
{
diff --git a/arch/arm/kernel/dma-ebsa285.c b/arch/arm/kernel/dma-ebsa285.c
index 74af95584..f1c42dac2 100644
--- a/arch/arm/kernel/dma-ebsa285.c
+++ b/arch/arm/kernel/dma-ebsa285.c
@@ -4,6 +4,9 @@
* Copyright (C) 1998 Phil Blundell
*
* DMA functions specific to EBSA-285/CATS architectures
+ *
+ * Changelog:
+ * 09/11/1998 RMK Split out ISA DMA functions to dma-isa.c
*/
#include <linux/config.h>
@@ -19,44 +22,19 @@
#include <asm/hardware.h>
#include "dma.h"
-
-/* 8237 DMA controllers */
-#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
-#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
-
-/* 8237 DMA controller registers */
-#define DMA1_CMD_REG 0x08 /* command register (w) */
-#define DMA1_STAT_REG 0x08 /* status register (r) */
-#define DMA1_REQ_REG 0x09 /* request register (w) */
-#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
-#define DMA1_MODE_REG 0x0B /* mode register (w) */
-#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
-#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
-#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
-
-#define DMA2_CMD_REG 0xD0 /* command register (w) */
-#define DMA2_STAT_REG 0xD0 /* status register (r) */
-#define DMA2_REQ_REG 0xD2 /* request register (w) */
-#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
-#define DMA2_MODE_REG 0xD6 /* mode register (w) */
-#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
-#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
-#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
+#include "dma-isa.h"
int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
{
- /* 21285 internal channels */
- if (channel == 0 || channel == 1)
+ switch (channel) {
+ case 0:
+ case 1: /* 21285 internal channels */
return 0;
- /* ISA channels */
-// if (machine_is_cats() && ((channel >= 2 && channel <= 5) ||
-// (channel >= 7 && channel <= 9)))
-// return 0;
+ case 2 ... 9:
+ if (machine_is_cats())
+ return isa_request_dma(channel - 2, dma, dev_name);
+ }
return -EINVAL;
}
@@ -75,14 +53,9 @@ int arch_get_dma_residue(dmach_t channel, dma_t *dma)
case 1:
break;
#ifdef CONFIG_CATS
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
+ case 2 ... 9:
+ if (machine_is_cats())
+ residue = isa_get_dma_residue(channel - 2);
#endif
}
return residue;
@@ -98,56 +71,9 @@ void arch_enable_dma(dmach_t channel, dma_t *dma)
*/
break;
#ifdef CONFIG_CATS
- case 2:
- case 3:
- case 4:
- case 5:
- case 7:
- case 8:
- case 9:
- if (dma->invalid) {
- static unsigned char dma_page[] = { 0x87, 0x83, 0x81, 0x82,
- 0x00, 0x8b, 0x89, 0x8a };
- unsigned long int address = dma->buf.address,
- length = dma->buf.length - 1;
- outb(address >> 24, dma_page[channel - DMA_ISA_BASE] | 0x400);
- outb(address >> 16, dma_page[channel - DMA_ISA_BASE]);
- if (channel >= DMA_ISA_BASE + 5) {
- outb(0, DMA2_CLEAR_FF_REG);
- outb(address >> 1,
- IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2));
- outb(address >> 9,
- IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2));
- outb((length >> 1) & 0xfe,
- IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2));
- outb(length >> 9,
- IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2));
- outb(dma->dma_mode | (channel - DMA_ISA_BASE - 4), DMA2_MODE_REG);
- } else {
- outb(0, DMA1_CLEAR_FF_REG);
- outb(address >> 0, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1));
- outb(address >> 8, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1));
- outb(length >> 0,
- IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1));
- outb(length >> 8,
- IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1));
- outb(dma->dma_mode | (channel - DMA_ISA_BASE), DMA1_MODE_REG);
- }
- switch (dma->dma_mode) {
- case DMA_MODE_READ:
- dma_cache_inv(__bus_to_virt(address), length + 1);
- break;
- case DMA_MODE_WRITE:
- dma_cache_wback(__bus_to_virt(address), length + 1);
- break;
- }
- dma->invalid = 0;
- }
-
- if (channel >= DMA_ISA_BASE + 5)
- outb(channel - DMA_ISA_BASE - 4, DMA2_MASK_REG);
- else
- outb(channel - DMA_ISA_BASE, DMA1_MASK_REG);
+ case 2 ... 9:
+ if (machine_is_cats())
+ isa_enable_dma(channel - 2, dma);
#endif
}
}
@@ -162,18 +88,9 @@ void arch_disable_dma(dmach_t channel, dma_t *dma)
*/
break;
#ifdef CONFIG_CATS
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- if (channel >= DMA_ISA_BASE + 5)
- outb(channel - DMA_ISA_BASE, DMA2_MASK_REG);
- else
- outb((channel - DMA_ISA_BASE) | 4, DMA1_MASK_REG);
+ case 2 ... 9:
+ if (machine_is_cats())
+ isa_disable_dma(channel - 2, dma);
#endif
}
}
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c
new file mode 100644
index 000000000..bdf7c6147
--- /dev/null
+++ b/arch/arm/kernel/dma-isa.c
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/kernel/dma-isa.c: ISA DMA primitives
+ *
+ * Copyright (C) Russell King
+ *
+ * Taken from various sources, including:
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen and John Boyd, Nov. 1992.
+ * arch/arm/kernel/dma-ebsa285.c
+ * Copyright (C) 1998 Phil Blundell
+ */
+#include <linux/sched.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+
+#include "dma.h"
+#include "dma-isa.h"
+
+#define ISA_DMA_MASK 0
+#define ISA_DMA_MODE 1
+#define ISA_DMA_CLRFF 2
+#define ISA_DMA_PGHI 3
+#define ISA_DMA_PGLO 4
+#define ISA_DMA_ADDR 5
+#define ISA_DMA_COUNT 6
+
+static unsigned int isa_dma_port[8][7] = {
+ /* MASK MODE CLRFF PAGE_HI PAGE_LO ADDR COUNT */
+ { 0x0a, 0x0b, 0x0c, 0x487, 0x087, 0x00, 0x01 },
+ { 0x0a, 0x0b, 0x0c, 0x483, 0x083, 0x02, 0x03 },
+ { 0x0a, 0x0b, 0x0c, 0x481, 0x081, 0x04, 0x05 },
+ { 0x0a, 0x0b, 0x0c, 0x482, 0x082, 0x06, 0x07 },
+ { 0xd4, 0xd6, 0xd8, 0x000, 0x000, 0xc0, 0xc2 },
+ { 0xd4, 0xd6, 0xd8, 0x48b, 0x08b, 0xc4, 0xc6 },
+ { 0xd4, 0xd6, 0xd8, 0x489, 0x089, 0xc8, 0xca },
+ { 0xd4, 0xd6, 0xd8, 0x48a, 0x08a, 0xcc, 0xce }
+};
+
+int isa_request_dma(int channel, dma_t *dma, const char *dev_name)
+{
+ if (channel != 4)
+ return 0;
+
+ return -EINVAL;
+}
+
+void isa_free_dma(int channel, dma_t *dma)
+{
+ /* nothing to do */
+}
+
+int isa_get_dma_residue(int channel, dma_t *dma)
+{
+ unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT];
+ int count;
+
+ count = 1 + inb(io_port) + (inb(io_port) << 8);
+
+ return channel < 4 ? count : (count << 1);
+}
+
+void isa_enable_dma(int channel, dma_t *dma)
+{
+ unsigned long address, length;
+
+ if (dma->invalid) {
+ address = dma->buf.address;
+ length = dma->buf.length - 1;
+
+ outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]);
+ outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]);
+
+ if (channel >= 4) {
+ address >>= 1;
+ length = (length >> 1) & 0xfe; /* why &0xfe? */
+ }
+
+ outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]);
+
+ outb(address, isa_dma_port[channel][ISA_DMA_ADDR]);
+ outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]);
+
+ outb(length, isa_dma_port[channel][ISA_DMA_COUNT]);
+ outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]);
+
+ outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]);
+
+ switch (dma->dma_mode) {
+ case DMA_MODE_READ:
+ dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length);
+ break;
+
+ case DMA_MODE_WRITE:
+ dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length);
+ break;
+ }
+ dma->invalid = 0;
+ }
+ outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]);
+}
+
+void isa_disable_dma(int channel, dma_t *dma)
+{
+ outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]);
+}
diff --git a/arch/arm/kernel/dma-isa.h b/arch/arm/kernel/dma-isa.h
new file mode 100644
index 000000000..3fcbdb3c7
--- /dev/null
+++ b/arch/arm/kernel/dma-isa.h
@@ -0,0 +1,25 @@
+/*
+ * Request an ISA DMA channel
+ */
+int isa_request_dma(int channel, dma_t *dma, const char *dev_name);
+
+/*
+ * Free an ISA DMA channel
+ */
+void isa_free_dma(int channel, dma_t *dma);
+
+/*
+ * Get ISA DMA channel residue
+ */
+int isa_get_dma_residue(int channel, dma_t *dma);
+
+/*
+ * Enable (and set up) an ISA DMA channel
+ */
+void isa_enable_dma(int channel, dma_t *dma);
+
+/*
+ * Disable an ISA DMA channel
+ */
+void isa_disable_dma(int channel, dma_t *dma);
+
diff --git a/arch/arm/kernel/dma-vnc.c b/arch/arm/kernel/dma-vnc.c
new file mode 100644
index 000000000..132fa627a
--- /dev/null
+++ b/arch/arm/kernel/dma-vnc.c
@@ -0,0 +1,51 @@
+/*
+ * arch/arm/kernel/dma-vnc.c
+ *
+ * Copyright (C) 1998 Russell King
+ */
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+#include "dma-isa.h"
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
+{
+ if (channel < 8)
+ return isa_request_dma(channel, dma, dev_name);
+ return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+ isa_free_dma(channel, dma);
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+ return isa_get_dma_residue(channel, dma);
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+ isa_enable_dma(channel, dma);
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+ isa_disable_dma(channel, dma);
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+ /* Nothing to do */
+}
+
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index 592cc979c..a164073ae 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -26,6 +26,26 @@
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/spinlock.h>
+
+
+/* A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `request_dma()' and `free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.
+ * When releasing them, first release the DMA, then release the IRQ.
+ * If you don't, you may cause allocation requests to fail unnecessarily.
+ * This doesn't really matter now, but it will once we get real semaphores
+ * in the kernel.
+ */
+
+
+spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED;
#include "dma.h"
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index f7d204787..fe1c75f5c 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -3,7 +3,7 @@
*
* Find all installed expansion cards, and handle interrupts from them.
*
- * Copyright 1995,1996,1997 Russell King
+ * Copyright 1995-1998 Russell King
*
* Created from information from Acorns RiscOS3 PRMs
*
@@ -14,6 +14,7 @@
* 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from
* Linux. (Caused cards not to respond under RiscOS without hard reset).
* 15-Feb-1998 RMK Added DMA support
+ * 12-Sep-1998 RMK Added EASI support
*/
#define ECARD_C
@@ -79,7 +80,7 @@ static signed char irqno_to_expcard[16];
static unsigned int ecard_numcards, ecard_numirqcards;
static unsigned int have_expmask;
-static void ecard_def_irq_enable (ecard_t *ec, int irqnr)
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
{
#ifdef HAS_EXPMASK
if (irqnr < 4 && have_expmask) {
@@ -89,7 +90,7 @@ static void ecard_def_irq_enable (ecard_t *ec, int irqnr)
#endif
}
-static void ecard_def_irq_disable (ecard_t *ec, int irqnr)
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
{
#ifdef HAS_EXPMASK
if (irqnr < 4 && have_expmask) {
@@ -99,14 +100,14 @@ static void ecard_def_irq_disable (ecard_t *ec, int irqnr)
#endif
}
-static void ecard_def_fiq_enable (ecard_t *ec, int fiqnr)
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
{
- panic ("ecard_def_fiq_enable called - impossible");
+ panic("ecard_def_fiq_enable called - impossible");
}
-static void ecard_def_fiq_disable (ecard_t *ec, int fiqnr)
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
{
- panic ("ecard_def_fiq_disable called - impossible");
+ panic("ecard_def_fiq_disable called - impossible");
}
static expansioncard_ops_t ecard_default_ops = {
@@ -122,7 +123,7 @@ static expansioncard_ops_t ecard_default_ops = {
*
* They are not meant to be called directly, but via enable/disable_irq.
*/
-void ecard_enableirq (unsigned int irqnr)
+void ecard_enableirq(unsigned int irqnr)
{
irqnr &= 7;
if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
@@ -132,14 +133,14 @@ void ecard_enableirq (unsigned int irqnr)
ec->ops = &ecard_default_ops;
if (ec->claimed && ec->ops->irqenable)
- ec->ops->irqenable (ec, irqnr);
+ ec->ops->irqenable(ec, irqnr);
else
- printk (KERN_ERR "ecard: rejecting request to "
+ printk(KERN_ERR "ecard: rejecting request to "
"enable IRQs for %d\n", irqnr);
}
}
-void ecard_disableirq (unsigned int irqnr)
+void ecard_disableirq(unsigned int irqnr)
{
irqnr &= 7;
if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
@@ -149,11 +150,11 @@ void ecard_disableirq (unsigned int irqnr)
ec->ops = &ecard_default_ops;
if (ec->ops && ec->ops->irqdisable)
- ec->ops->irqdisable (ec, irqnr);
+ ec->ops->irqdisable(ec, irqnr);
}
}
-void ecard_enablefiq (unsigned int fiqnr)
+void ecard_enablefiq(unsigned int fiqnr)
{
fiqnr &= 7;
if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
@@ -163,14 +164,14 @@ void ecard_enablefiq (unsigned int fiqnr)
ec->ops = &ecard_default_ops;
if (ec->claimed && ec->ops->fiqenable)
- ec->ops->fiqenable (ec, fiqnr);
+ ec->ops->fiqenable(ec, fiqnr);
else
- printk (KERN_ERR "ecard: rejecting request to "
+ printk(KERN_ERR "ecard: rejecting request to "
"enable FIQs for %d\n", fiqnr);
}
}
-void ecard_disablefiq (unsigned int fiqnr)
+void ecard_disablefiq(unsigned int fiqnr)
{
fiqnr &= 7;
if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
@@ -180,7 +181,7 @@ void ecard_disablefiq (unsigned int fiqnr)
ec->ops = &ecard_default_ops;
if (ec->ops->fiqdisable)
- ec->ops->fiqdisable (ec, fiqnr);
+ ec->ops->fiqdisable(ec, fiqnr);
}
}
@@ -198,8 +199,27 @@ static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
}
}
cli();
- if (called == 0)
- printk (KERN_WARNING "Wild interrupt from backplane?\n");
+ if (called == 0) {
+ static int last, lockup;
+
+ if (last == jiffies) {
+ lockup += 1;
+ if (lockup > 1000000) {
+ printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n");
+ disable_irq(intr_no);
+ printk("Expansion card IRQ state:\n");
+ for (i = 0; i < num_cards; i++)
+ printk(" %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32,
+ expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr);
+ }
+ } else
+ lockup = 0;
+
+ if (!last || time_after(jiffies, last + 5*HZ)) {
+ last = jiffies;
+ printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
+ }
+ }
}
#ifdef HAS_EXPMASK
@@ -214,7 +234,7 @@ static unsigned char first_set[] =
0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
};
-static void ecard_irq_expmask (int intr_no, void *dev_id, struct pt_regs *regs)
+static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
{
const unsigned int statusmask = 15;
unsigned int status;
@@ -239,22 +259,22 @@ again:
*/
oldexpmask = have_expmask;
EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]);
- sti ();
- do_ecard_IRQ (ec->irq, regs);
- cli ();
+ sti();
+ do_ecard_IRQ(ec->irq, regs);
+ cli();
EXPMASK_ENABLE = have_expmask = oldexpmask;
status = EXPMASK_STATUS & statusmask;
if (status)
goto again;
} else {
- printk (KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
+ printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno);
EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno));
}
} else
- printk (KERN_WARNING "Wild interrupt from backplane (masks)\n");
+ printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
}
-static int ecard_checkirqhw (void)
+static int ecard_checkirqhw(void)
{
int found;
@@ -267,7 +287,7 @@ static int ecard_checkirqhw (void)
}
#endif
-static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int useld)
+static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
{
extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader);
unsigned char *a = (unsigned char *)addr;
@@ -287,7 +307,7 @@ static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int usel
* If we require a low address or address 0, then reset, and start again...
*/
if (!off || lowaddress > laddr) {
- outb (0, ec->podaddr);
+ outb(0, ec->podaddr);
lowaddress = 0;
}
while (lowaddress <= laddr) {
@@ -314,15 +334,136 @@ static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int usel
}
}
+static int ecard_prints(char *buffer, ecard_t *ec)
+{
+ char *start = buffer;
+
+ buffer += sprintf(buffer, "\n %d: ", ec->slot_no);
+
+ if (ec->cid.id == 0) {
+ struct in_chunk_dir incd;
+
+ buffer += sprintf(buffer, "[%04X:%04X] ",
+ ec->cid.manufacturer, ec->cid.product);
+
+ if (!ec->card_desc && ec->cid.is && ec->cid.cd &&
+ ecard_readchunk(&incd, ec, 0xf5, 0))
+ ec->card_desc = incd.d.string;
+
+ if (!ec->card_desc)
+ ec->card_desc = "*unknown*";
+
+ buffer += sprintf(buffer, "%s", ec->card_desc);
+ } else
+ buffer += sprintf(buffer, "Simple card %d", ec->cid.id);
+
+ return buffer - start;
+}
+
+static inline unsigned short ecard_getu16(unsigned char *v)
+{
+ return v[0] | v[1] << 8;
+}
+
+static inline signed long ecard_gets24(unsigned char *v)
+{
+ return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type))
+{
+ ecard_t *ec = expcard + freeslot;
+ struct ex_ecid cid;
+ char buffer[200];
+ int i;
+
+ irqno_to_expcard[card] = -1;
+
+ ec->slot_no = card;
+ ec->irq = NO_IRQ;
+ ec->fiq = NO_IRQ;
+ ec->dma = NO_DMA;
+ ec->card_desc = NULL;
+ ec->ops = &ecard_default_ops;
+
+ if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
+ return 0;
+
+ cid.r_zero = 1;
+ ecard_readbytes(&cid, ec, 0, 16, 0);
+ if (cid.r_zero)
+ return 0;
+
+ irqno_to_expcard[card] = freeslot;
+
+ ec->type = type;
+ ec->cid.id = cid.r_id;
+ ec->cid.cd = cid.r_cd;
+ ec->cid.is = cid.r_is;
+ ec->cid.w = cid.r_w;
+ ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+ ec->cid.product = ecard_getu16(cid.r_prod);
+ ec->cid.country = cid.r_country;
+ ec->cid.irqmask = cid.r_irqmask;
+ ec->cid.irqoff = ecard_gets24(cid.r_irqoff);
+ ec->cid.fiqmask = cid.r_fiqmask;
+ ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
+ ec->fiqaddr =
+ ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr);
+
+ if (ec->cid.cd && ec->cid.is) {
+ ec->irqmask = ec->cid.irqmask;
+ ec->irqaddr += ec->cid.irqoff;
+ ec->fiqmask = ec->cid.fiqmask;
+ ec->fiqaddr += ec->cid.fiqoff;
+ } else {
+ ec->irqmask = 1;
+ ec->fiqmask = 4;
+ }
+
+ for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
+ if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+ blacklist[i].product == ec->cid.product) {
+ ec->loader = blacklist[i].loader;
+ ec->card_desc = blacklist[i].type;
+ break;
+ }
+
+ ecard_prints(buffer, ec);
+ printk("%s", buffer);
+
+ ec->irq = 32 + card;
+#ifdef IO_EC_MEMC8_BASE
+ if (card == 8)
+ ec->irq = 11;
+#endif
+#ifdef CONFIG_ARCH_RPC
+ /* On RiscPC, only first two slots have DMA capability */
+ if (card < 2)
+ ec->dma = 2 + card;
+#endif
+#if 0 /* We don't support FIQs on expansion cards at the moment */
+ ec->fiq = 96 + card;
+#endif
+
+ return 1;
+}
+
/*
* This is called to reset the loaders for each expansion card on reboot.
*
* This is required to make sure that the card is in the correct state
* that RiscOS expects it to be.
*/
-void ecard_reset (int card)
+void ecard_reset(int card)
{
- extern int ecard_loader_reset (volatile unsigned int pa, loader_t loader);
+ extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader);
if (card >= ecard_numcards)
return;
@@ -330,11 +471,11 @@ void ecard_reset (int card)
if (card < 0) {
for (card = 0; card < ecard_numcards; card++)
if (expcard[card].loader)
- ecard_loader_reset (BUS_ADDR(expcard[card].podaddr),
+ ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
expcard[card].loader);
} else
if (expcard[card].loader)
- ecard_loader_reset (BUS_ADDR(expcard[card].podaddr),
+ ecard_loader_reset(BUS_ADDR(expcard[card].podaddr),
expcard[card].loader);
#ifdef HAS_EXPMASK
@@ -347,18 +488,19 @@ void ecard_reset (int card)
static unsigned int ecard_startcard;
-void ecard_startfind (void)
+void ecard_startfind(void)
{
ecard_startcard = 0;
}
-ecard_t *ecard_find (int cld, const card_ids *cids)
+ecard_t *ecard_find(int cid, const card_ids *cids)
{
int card;
+
if (!cids) {
for (card = ecard_startcard; card < ecard_numcards; card++)
if (!expcard[card].claimed &&
- ((expcard[card].cld.ecld ^ cld) & 0x78) == 0)
+ (expcard[card].cid.id ^ cid) == 0)
break;
} else {
for (card = ecard_startcard; card < ecard_numcards; card++) {
@@ -368,8 +510,8 @@ ecard_t *ecard_find (int cld, const card_ids *cids)
if (expcard[card].claimed)
continue;
- manufacturer = expcard[card].cld.manufacturer;
- product = expcard[card].cld.product;
+ manufacturer = expcard[card].cid.manufacturer;
+ product = expcard[card].cid.product;
for (i = 0; cids[i].manufacturer != 65535; i++)
if (manufacturer == cids[i].manufacturer &&
@@ -380,16 +522,21 @@ ecard_t *ecard_find (int cld, const card_ids *cids)
break;
}
}
+
ecard_startcard = card + 1;
+
return card < ecard_numcards ? &expcard[card] : NULL;
}
-int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
{
struct ex_chunk_dir excd;
int index = 16;
int useld = 0;
+ if (!ec->cid.is || !ec->cid.cd)
+ return 0;
+
while(1) {
ecard_readbytes(&excd, ec, index, 8, useld);
index += 8;
@@ -427,124 +574,49 @@ int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
}
}
cd->start_offset = c_start(&excd);
- memcpy (cd->d.string, excd.d.string, 256);
+ memcpy(cd->d.string, excd.d.string, 256);
return 1;
}
-unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed)
+unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
{
switch (ec->slot_no) {
case 0 ... 3:
switch (type) {
case ECARD_MEMC:
- return MEMCECIO_BASE + (ec->slot_no << 12);
+ return IO_EC_MEMC_BASE + (ec->slot_no << 12);
case ECARD_IOC:
- return IOCECIO_BASE + (speed << 17) + (ec->slot_no << 12);
+ return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12);
- default:
- return 0;
+#ifdef IO_EC_EASI_BASE
+ case ECARD_EASI:
+ return IO_EC_EASI_BASE + (ec->slot_no << 22);
+#endif
}
+ break;
-#ifdef IOCEC4IO_BASE
case 4 ... 7:
- if (type != ECARD_IOC)
- return 0;
-
- return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
+ switch (type) {
+#ifdef IO_EC_IOC4_BASE
+ case ECARD_IOC:
+ return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
#endif
-#ifdef MEMCEC8IO_BASE
- case 8:
- return MEMCEC8IO_BASE;
+#ifdef IO_EC_EASI_BASE
+ case ECARD_EASI:
+ return IO_EC_EASI_BASE + (ec->slot_no << 22);
#endif
- }
- return 0;
-}
-
-/*
- * Probe for an expansion card.
- *
- * If bit 1 of the first byte of the card is set,
- * then the card does not exist.
- */
-__initfunc(static int ecard_probe (int card, int freeslot))
-{
- ecard_t *ec = expcard + freeslot;
- struct ex_ecld excld;
- const char *card_desc = NULL;
- int i;
-
- irqno_to_expcard[card] = -1;
-
- ec->slot_no = card;
- if ((ec->podaddr = ecard_address (ec, ECARD_IOC, ECARD_SYNC)) == 0)
- return 0;
-
- excld.r_ecld = 2;
- ecard_readbytes (&excld, ec, 0, 16, 0);
- if (excld.r_ecld & 2)
- return 0;
-
- irqno_to_expcard[card] = freeslot;
-
- ec->irq = NO_IRQ;
- ec->fiq = NO_IRQ;
- ec->dma = NO_DMA;
- ec->cld.ecld = e_ecld(&excld);
- ec->cld.manufacturer = e_manu(&excld);
- ec->cld.product = e_prod(&excld);
- ec->cld.country = e_country(&excld);
- ec->cld.fiqmask = e_fiqmask(&excld);
- ec->cld.irqmask = e_irqmask(&excld);
- ec->cld.fiqaddr = e_fiqaddr(&excld);
- ec->cld.irqaddr = e_irqaddr(&excld);
- ec->fiqaddr =
- ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr);
- ec->fiqmask = 4;
- ec->irqmask = 1;
- ec->ops = &ecard_default_ops;
-
- for (i = 0; i < sizeof (blacklist) / sizeof (*blacklist); i++)
- if (blacklist[i].manufacturer == ec->cld.manufacturer &&
- blacklist[i].product == ec->cld.product) {
- ec->loader = blacklist[i].loader;
- card_desc = blacklist[i].type;
+ default:
break;
}
+ break;
- ec->irq = 32 + card;
-#if 0
- /* We don't support FIQs on expansion cards at the moment */
- ec->fiq = 96 + card;
-#endif
-#ifdef CONFIG_ARCH_RPC
- if (card != 8) {
- /* On RiscPC, only first two slots have DMA capability
- */
- if (card < 2)
- ec->dma = 2 + card;
- } else
- ec->irq = 11;
+#ifdef IO_EC_MEMC8_BASE
+ case 8:
+ return IO_EC_MEMC8_BASE;
#endif
-
- if ((ec->cld.ecld & 0x78) == 0) {
- struct in_chunk_dir incd;
- printk ("\n %d: [%04X:%04X] ", card, ec->cld.manufacturer, ec->cld.product);
- if (e_is (&excld)) {
- ec->fiqmask = e_fiqmask (&excld);
- ec->irqmask = e_irqmask (&excld);
- ec->fiqaddr += e_fiqaddr (&excld);
- ec->irqaddr += e_irqaddr (&excld);
- }
- if (!card_desc && e_cd (&excld) && ecard_readchunk (&incd, ec, 0xf5, 0))
- card_desc = incd.d.string;
- if (card_desc)
- printk ("%s", card_desc);
- else
- printk ("*Unknown*");
- } else
- printk("\n %d: Simple card %d\n", card, (ec->cld.ecld >> 3) & 15);
- return 1;
+ }
+ return 0;
}
static struct irqaction irqexpansioncard = {
@@ -565,11 +637,11 @@ __initfunc(void ecard_init(void))
{
int i, nc = 0;
- memset (expcard, 0, sizeof (expcard));
+ memset(expcard, 0, sizeof(expcard));
#ifdef HAS_EXPMASK
if (ecard_checkirqhw()) {
- printk (KERN_DEBUG "Expansion card interrupt management hardware found\n");
+ printk(KERN_DEBUG "Expansion card interrupt management hardware found\n");
irqexpansioncard.handler = ecard_irq_expmask;
irqexpansioncard.flags |= SA_IRQNOMASK;
have_expmask = -1;
@@ -581,8 +653,8 @@ __initfunc(void ecard_init(void))
/*
* First of all, probe all cards on the expansion card interrupt line
*/
- for (i = 0; i < 4; i++)
- if (ecard_probe (i, nc))
+ for (i = 0; i < 8; i++)
+ if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI))
nc += 1;
else
have_expmask &= ~(1<<i);
@@ -591,8 +663,8 @@ __initfunc(void ecard_init(void))
/* Now probe other cards with different interrupt lines
*/
-#ifdef MEMCEC8IO_BASE
- if (ecard_probe (8, nc))
+#ifdef IO_EC_MEMC8_BASE
+ if (ecard_probe(8, nc, ECARD_IOC))
nc += 1;
#endif
@@ -600,7 +672,7 @@ __initfunc(void ecard_init(void))
ecard_numcards = nc;
if (nc && setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
- printk ("Could not allocate interrupt for expansion cards\n");
+ printk("Could not allocate interrupt for expansion cards\n");
return;
}
@@ -609,5 +681,5 @@ __initfunc(void ecard_init(void))
EXPMASK_ENABLE = have_expmask;
#endif
- oldlatch_init ();
+ oldlatch_init();
}
diff --git a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S
index 4c65fc892..3ca29cd2c 100644
--- a/arch/arm/kernel/entry-armo.S
+++ b/arch/arm/kernel/entry-armo.S
@@ -271,26 +271,18 @@ vector_undefinstr:
mov fp, #0
teqp pc, #I_BIT | MODE_SVC
.Lbug_undef:
- adr r1, .LC2
- ldmia r1, {r1, r4}
- ldr r1, [r1]
- get_current_task r2
- teq r1, r2
- stmnefd sp!, {ip, lr}
- blne SYMBOL_NAME(math_state_restore)
- ldmnefd sp!, {ip, lr}
+ ldr r4, .LC2
ldr pc, [r4] @ Call FP module USR entry point
.globl SYMBOL_NAME(fpundefinstr)
SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr
-SYMBOL_NAME(fpundefinstrsvc):
mov r0, lr
mov r1, sp
teqp pc, #MODE_SVC
bl SYMBOL_NAME(do_undefinstr)
b ret_from_exception @ Normal FP exit
-__und_svc: SVC_SAVE_ALL @ Non-user mode
+__und_svc: SVC_SAVE_ALL @ Non-user mode
mask_pc r0, lr
and r2, lr, #3
sub r0, r0, #4
@@ -298,8 +290,44 @@ __und_svc: SVC_SAVE_ALL @ Non-user mode
bl SYMBOL_NAME(do_undefinstr)
SVC_RESTORE_ALL
-.LC2: .word SYMBOL_NAME(last_task_used_math)
- .word SYMBOL_NAME(fp_enter)
+/* We get here if an undefined instruction happens and the floating
+ * point emulator is not present. If the offending instruction was
+ * a WFS, we just perform a normal return as if we had emulated the
+ * operation. This is a hack to allow some basic userland binaries
+ * to run so that the emulator module proper can be loaded. --philb
+ */
+fpe_not_present:
+ adr r10, wfs_mask_data
+ ldmia r10, {r4, r5, r6, r7, r8}
+ ldr r10, [sp, #S_PC] @ Load PC
+ sub r10, r10, #4
+ mask_pc r10, r10
+ ldrt r10, [r10] @ get instruction
+ and r5, r10, r5
+ teq r5, r4 @ Is it WFS?
+ beq ret_from_exception
+ and r5, r10, r8
+ teq r5, r6 @ Is it LDF/STF on sp or fp?
+ teqne r5, r7
+ bne fpundefinstr
+ tst r10, #0x00200000 @ Does it have WB
+ beq ret_from_exception
+ and r4, r10, #255 @ get offset
+ and r6, r10, #0x000f0000
+ tst r10, #0x00800000 @ +/-
+ rsbeq r4, r4, #0
+ ldr r5, [sp, r6, lsr #14] @ Load reg
+ add r5, r5, r4, lsl #2
+ str r5, [sp, r6, lsr #14] @ Save reg
+ b ret_from_exception
+
+wfs_mask_data: .word 0x0e200110 @ WFS
+ .word 0x0fff0fff
+ .word 0x0d0d0100 @ LDF [sp]/STF [sp]
+ .word 0x0d0b0100 @ LDF [fp]/STF [fp]
+ .word 0x0f0f0f00
+
+.LC2: .word SYMBOL_NAME(fp_enter)
/*=============================================================================
* Prefetch abort handler
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 7ecf1d59a..bcc938b32 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -231,60 +231,68 @@ irq_prio_ebsa110:
.macro disable_fiq
.endm
+ .equ pci_iack_high, PCI_IACK & 0xff000000
+ .equ pci_iack_low, PCI_IACK & 0x00ff0000
+
.macro get_irqnr_and_base, irqnr, irqstat, base
mov r4, #IO_BASE_ARM_CSR
- ldr \irqstat, [r4, #IRQ_STATUS] @ just show us the unmasked ones
+ ldr \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones
@ run through hard priorities
@ timer
tst \irqstat, #IRQ_MASK_TIMER0
movne \irqnr, #IRQ_TIMER0
- bne 1f
+ bne 1001f
@ ether10
tst \irqstat, #IRQ_MASK_ETHER10
movne \irqnr, #IRQ_ETHER10
- bne 1f
+ bne 1001f
@ ether100
tst \irqstat, #IRQ_MASK_ETHER100
movne \irqnr, #IRQ_ETHER100
- bne 1f
+ bne 1001f
@ video compressor
- tst \irqstat, #IRQ_VIDCOMP_MASK
+ tst \irqstat, #IRQ_MASK_VIDCOMP
movne \irqnr, #IRQ_VIDCOMP
- bne 1f
+ bne 1001f
@ now try all the PIC sources
@ determine whether we have an irq
tst \irqstat, #IRQ_MASK_EXTERN_IRQ
- beq 3f
- mov r4, #(IO_BASE_PCI_IACK & 0xff000000)
- orr r4, r4, #(IO_BASE_PCI_IACK & 0x00ff0000)
+ beq 1002f
+ mov r4, #pci_iack_high
+ orr r4, r4, #pci_iack_low
ldrb \irqnr, [r4] @ get the IACK byte
- b 1f
+ b 1001f
-3: @ PCI errors
+1002: @ PCI errors
tst \irqstat, #IRQ_MASK_PCI_ERR
movne \irqnr, #IRQ_PCI_ERR
- bne 1f
+ bne 1001f
@ softint
- tst \irqstat, #IRQ_MASK_SOFT_IRQ
- movne \irqnr, #IRQ_SOFT_IRQ
- bne 1f
+ tst \irqstat, #IRQ_MASK_SOFTIRQ
+ movne \irqnr, #IRQ_SOFTIRQ
+ bne 1001f
@ debug uart
tst \irqstat, #IRQ_MASK_UART_DEBUG
- movne \irqnr, #IRQ_UART_DEBUG
- bne 1f
+ movne \irqnr, #IRQ_CONRX
+ bne 1001f
@ watchdog
- tst \irqstat, #IRQ_WATCHDOG_MASK
+ tst \irqstat, #IRQ_MASK_WATCHDOG
movne \irqnr, #IRQ_WATCHDOG
-1: @ If Z is set, then we will not enter an interrupt
+1001: @ If Z is set, then we will not enter an interrupt
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
#else
#error Unknown architecture
#endif
@@ -696,8 +704,8 @@ __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go
adrsvc al, lr, fpundefinstr @ lr = undefined instr return
1: get_current_task r10
- mov lr, #1
- strb lr, [r10, #TSK_USED_MATH] @ set current->used_math
+ mov r8, #1
+ strb r8, [r10, #TSK_USED_MATH] @ set current->used_math
add r10, r10, #TSS_FPESAVE @ r10 = workspace
ldr r4, .LC2
ldr pc, [r4] @ Call FP module USR entry point
@@ -742,6 +750,43 @@ __und_invalid: sub sp, sp, #S_FRAME_SIZE
and r2, r6, #31 @ int mode
b SYMBOL_NAME(bad_mode) @ Does not ever return...
+/* We get here if an undefined instruction happens and the floating
+ * point emulator is not present. If the offending instruction was
+ * a WFS, we just perform a normal return as if we had emulated the
+ * operation. This is a hack to allow some basic userland binaries
+ * to run so that the emulator module proper can be loaded. --philb
+ */
+fpe_not_present:
+ adr r10, wfs_mask_data
+ ldmia r10, {r4, r5, r6, r7, r8}
+ ldr r10, [sp, #S_PC] @ Load PC
+ sub r10, r10, #4
+ mask_pc r10, r10
+ ldrt r10, [r10] @ get instruction
+ and r5, r10, r5
+ teq r5, r4 @ Is it WFS?
+ moveq pc, r9
+ and r5, r10, r8
+ teq r5, r6 @ Is it LDF/STF on sp or fp?
+ teqne r5, r7
+ movne pc, lr
+ tst r10, #0x00200000 @ Does it have WB
+ moveq pc, r9
+ and r4, r10, #255 @ get offset
+ and r6, r10, #0x000f0000
+ tst r10, #0x00800000 @ +/-
+ rsbeq r4, r4, #0
+ ldr r5, [sp, r6, lsr #14] @ Load reg
+ add r5, r5, r4, lsl #2
+ str r5, [sp, r6, lsr #14] @ Save reg
+ mov pc, r9
+
+wfs_mask_data: .word 0x0e200110 @ WFS
+ .word 0x0fff0fff
+ .word 0x0d0d0100 @ LDF [sp]/STF [sp]
+ .word 0x0d0b0100 @ LDF [fp]/STF [fp]
+ .word 0x0f0f0f00
+
#include "entry-common.S"
.data
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 6e0e9e38c..c77c0ea51 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -288,4 +288,4 @@ ENTRY(trap_init)
.data
ENTRY(fp_enter)
- .word fpundefinstr
+ .word fpe_not_present
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index c32fef3c8..a5da15c7f 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -106,14 +106,7 @@ void set_fiq_handler(void *start, unsigned int length)
memcpy((void *)FIQ_VECTOR, start, length);
protect_page_0();
-#if 0
- /* This doesn'w work correctly. Ok, it's a misuse
- * of the DMA flushing code, but it ought to work.
- * More investigation required. Maybe it really
- * needs the cache flushed.
- */
- dma_cache_wback(FIQ_VECTOR, length);
-#else
+#ifdef CONFIG_CPU_32
processor.u.armv3v4._flush_cache_area(FIQ_VECTOR, FIQ_VECTOR + length, 1);
#endif
}
diff --git a/arch/arm/kernel/head-armo.S b/arch/arm/kernel/head-armo.S
index 1dc4fde13..d6b2b79e6 100644
--- a/arch/arm/kernel/head-armo.S
+++ b/arch/arm/kernel/head-armo.S
@@ -58,6 +58,3 @@ Loldparams: mov r4, #0x02000000
cmp r4, r3
blt 1b
movs pc, lr
-
- .align 13
-ENTRY(this_must_match_init_task)
diff --git a/arch/arm/kernel/head-armv.S b/arch/arm/kernel/head-armv.S
index 88e71adab..cd4be86cb 100644
--- a/arch/arm/kernel/head-armv.S
+++ b/arch/arm/kernel/head-armv.S
@@ -8,9 +8,23 @@
#include <linux/config.h>
#include <linux/linkage.h>
+#ifndef CONFIG_ARCH_VNC
#if (TEXTADDR & 0xffff) != 0x8000
#error TEXTADDR must start at 0xXXXX8000
#endif
+#else
+ .text
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, r0
+ mov r0, #0
+ mov r1, #5
+#endif
#define DEBUG
@@ -97,6 +111,15 @@ __entry: teq r0, #0 @ check for illegal entry...
add r3, r3, #1 << 20
teq r0, r2
bne 1b
+#ifdef CONFIG_ARCH_VNC
+ add r0, r4, #0x3f00
+ add r0, r0, #0x00f8
+ mov r3, #0x7c000000
+ orr r3, r3, r8
+ str r3, [r0], #4
+ add r3, r3, #1 << 20
+ str r3, [r0], #4
+#endif
#endif
#ifdef CONFIG_ARCH_RPC
/* Map in screen at 0x02000000 & SCREEN2_BASE
@@ -339,7 +362,7 @@ __entry: teq r0, #0 @ check for illegal entry...
beq 1001b
.endm
-#elif defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_VNC)
+#elif defined(CONFIG_ARCH_EBSA285)
.macro addruart,rx
mov \rx, #0xfe000000
.endm
@@ -374,6 +397,30 @@ __entry: teq r0, #0 @ check for illegal entry...
.macro waituart,rd,rx
.endm
+
+#elif defined(CONFIG_ARCH_VNC)
+ .macro addruart,rx
+ mov \rx, #0xff000000
+ orr \rx, \rx, #0x00e00000
+ orr \rx, \rx, #0x000003f8
+ .endm
+
+ .macro senduart,rd,rx
+ strb \rd, [\rx]
+ .endm
+
+ .macro busyuart,rd,rx
+1002: ldrb \rd, [\rx, #0x5]
+ and \rd, \rd, #0x60
+ teq \rd, #0x60
+ bne 1002b
+ .endm
+
+ .macro waituart,rd,rx
+1001: ldrb \rd, [\rx, #0x6]
+ tst \rd, #0x10
+ beq 1001b
+ .endm
#else
#error Unknown architecture
#endif
diff --git a/arch/arm/kernel/hw-ebsa285.c b/arch/arm/kernel/hw-ebsa285.c
new file mode 100644
index 000000000..e3385696b
--- /dev/null
+++ b/arch/arm/kernel/hw-ebsa285.c
@@ -0,0 +1,161 @@
+/*
+ * arch/arm/kernel/hw-ebsa286.c
+ *
+ * EBSA285 hardware specific functions
+ *
+ * Copyright (C) 1998 Russell King, Phil Blundel
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+
+extern int setup_arm_irq(int, struct irqaction *);
+
+extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set);
+extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr);
+extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq);
+
+static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
+static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
+
+__initfunc(static int ebsa_irqval(struct pci_dev *dev))
+{
+ unsigned char pin;
+
+ pcibios_read_config_byte(dev->bus->number,
+ dev->devfn,
+ PCI_INTERRUPT_PIN,
+ &pin);
+
+ return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
+}
+
+__initfunc(static int cats_irqval(struct pci_dev *dev))
+{
+ if (dev->irq >= 128)
+ return 32 + (dev->irq & 0x1f);
+
+ switch (dev->irq) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return irqmap_cats[dev->irq - 1];
+ case 0:
+ return 0;
+ }
+
+ printk("PCI: device %02x:%02x has unknown irq line %x\n",
+ dev->bus->number, dev->devfn, dev->irq);
+ return 0;
+}
+
+__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev))
+{
+ char cmd;
+
+ /* sort out the irq mapping for this device */
+ switch (machine_type) {
+ case MACH_TYPE_EBSA285:
+ dev->irq = ebsa_irqval(dev);
+ break;
+ case MACH_TYPE_CATS:
+ dev->irq = cats_irqval(dev);
+ break;
+ }
+
+ /* Turn on bus mastering - boot loader doesn't
+ * - perhaps it should! - dag
+ */
+ pci_read_config_byte(dev, PCI_COMMAND, &cmd);
+ pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+}
+
+static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs)
+{
+ const char *err = "unknown";
+ unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff;
+ unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07;
+ static unsigned long next_warn[7];
+ int idx = 6;
+
+ switch(irq) {
+ case IRQ_PCIPARITY:
+ *(unsigned long *)0xfe000004 = cmd | 1 << 31;
+ idx = 0;
+ err = "parity";
+ break;
+
+ case IRQ_PCITARGETABORT:
+ *(unsigned long *)0xfe000004 = cmd | 1 << 28;
+ idx = 1;
+ err = "target abort";
+ break;
+
+ case IRQ_PCIMASTERABORT:
+ *(unsigned long *)0xfe000004 = cmd | 1 << 29;
+ idx = 2;
+ err = "master abort";
+ break;
+
+ case IRQ_PCIDATAPARITY:
+ *(unsigned long *)0xfe000004 = cmd | 1 << 24;
+ idx = 3;
+ err = "data parity";
+ break;
+
+ case IRQ_DISCARDTIMER:
+ *(unsigned long *)0xfe00013c = ctrl | 1 << 8;
+ idx = 4;
+ err = "discard timer";
+ break;
+
+ case IRQ_SERR:
+ *(unsigned long *)0xfe00013c = ctrl | 1 << 3;
+ idx = 5;
+ err = "system";
+ break;
+ }
+ if (time_after_eq(jiffies, next_warn[idx])) {
+ next_warn[idx] = jiffies + 3 * HZ / 100;
+ printk(KERN_ERR "PCI %s error detected\n", err);
+ }
+}
+
+static struct irqaction irq_pci_error = {
+ irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL
+};
+
+__initfunc(void pcibios_init_ebsa285(void))
+{
+ setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error);
+ setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error);
+ setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error);
+ setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error);
+ setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error);
+ setup_arm_irq(IRQ_SERR, &irq_pci_error);
+
+ /*
+ * Map our SDRAM at a known address in PCI space, just in case
+ * the firmware had other ideas. Using a nonzero base is slightly
+ * bizarre but apparently necessary to avoid problems with some
+ * video cards.
+ *
+ * We should really only do this if the central function is enabled.
+ */
+ *(unsigned long *)0xfe000010 = 0;
+ *(unsigned long *)0xfe000018 = 0xe0000000;
+ *(unsigned long *)0xfe0000f8 = 0;
+ *(unsigned long *)0xfe0000fc = 0;
+ *(unsigned long *)0xfe000100 = 0x01fc0000;
+ *(unsigned long *)0xfe000104 = 0;
+ *(unsigned long *)0xfe000108 = 0x80000000;
+ *(unsigned long *)0xfe000004 = 0x17;
+}
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index 689c43589..99577f1b7 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -6,7 +6,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index b4950ace2..332e8940d 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -119,7 +119,9 @@ int get_irq_list(char *buf)
*p++ = '\n';
}
+#ifdef CONFIG_ACORN
p += get_fiq_list(p);
+#endif
return p - buf;
}
@@ -354,7 +356,7 @@ unsigned long probe_irq_on(void)
/*
* wait for spurious interrupts to mask themselves out again
*/
- for (delay = jiffies + HZ/10; delay > jiffies; )
+ for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
/* min 100ms delay */;
/*
@@ -424,6 +426,8 @@ __initfunc(void init_IRQ(void))
}
irq_init_irq();
+#ifdef CONFIG_ARCH_ACORN
init_FIQ();
+#endif
init_dma();
}
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 767faff9e..cddc3fab3 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -57,13 +57,15 @@
#endif
#ifndef CONFIG_CMDLINE
-#define CONFIG_CMDLINE "root=nfs rw console=ttyS1,38400n8"
+#define CONFIG_CMDLINE "root=/dev/nfs rw"
#endif
#define MEM_SIZE (16*1024*1024)
#define COMMAND_LINE_SIZE 256
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info = {
+ orig_video_lines: 30,
+ orig_video_cols: 80,
orig_video_mode: 0,
orig_video_ega_bx: 0,
orig_video_isVGA: 1,
@@ -210,6 +212,8 @@ setup_params(unsigned long *mem_end_p))
#ifdef CONFIG_ARCH_ACORN
*mem_end_p = GET_MEMORY_END(params);
+#elif defined(CONFIG_ARCH_EBSA285)
+ *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages;
#else
*mem_end_p = PAGE_OFFSET + MEM_SIZE;
#endif
@@ -305,18 +309,18 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
__initfunc(static void
setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
{
- char c = ' ', *to = command_line;
+ char c, *to = command_line;
int len = 0;
*mem_start = (unsigned long)&_end;
for (;;) {
- if (c == ' ' &&
- cmd_line[0] == 'm' &&
- cmd_line[1] == 'e' &&
- cmd_line[2] == 'm' &&
- cmd_line[3] == '=') {
- *mem_end = simple_strtoul(cmd_line+4, &cmd_line, 0);
+ if (cmd_line[0] == ' ' &&
+ cmd_line[1] == 'm' &&
+ cmd_line[2] == 'e' &&
+ cmd_line[3] == 'm' &&
+ cmd_line[4] == '=') {
+ *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0);
switch(*cmd_line) {
case 'M':
case 'm':
@@ -336,7 +340,7 @@ setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
*to++ = c;
}
- *to = '\0';
+ *to = '\0';
}
__initfunc(void
@@ -381,33 +385,27 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * mem
conswitchp = &dummy_con;
#endif
#endif
-printascii("setup_arch done\n");
}
+static const struct {
+ char *machine_name;
+ char *bus_name;
+} machine_desc[] = {
+ { "DEC-EBSA110", "DEC" },
+ { "Acorn-RiscPC", "Acorn" },
+ { "Nexus-NexusPCI", "PCI" },
+ { "DEC-EBSA285", "PCI" },
+ { "Corel-Netwinder", "PCI/ISA" },
+ { "Chalice-CATS", "PCI" },
+ { "unknown-TBOX", "PCI" }
+};
+
#if defined(CONFIG_ARCH_ARC)
#define HARDWARE "Acorn-Archimedes"
#define IO_BUS "Acorn"
#elif defined(CONFIG_ARCH_A5K)
#define HARDWARE "Acorn-A5000"
#define IO_BUS "Acorn"
-#elif defined(CONFIG_ARCH_RPC)
-#define HARDWARE "Acorn-RiscPC"
-#define IO_BUS "Acorn"
-#elif defined(CONFIG_ARCH_EBSA110)
-#define HARDWARE "DEC-EBSA110"
-#define IO_BUS "DEC"
-#elif defined(CONFIG_ARCH_EBSA285)
-#define HARDWARE "DEC-EBSA285"
-#define IO_BUS "PCI"
-#elif defined(CONFIG_ARCH_NEXUSPCI)
-#define HARDWARE "Nexus-NexusPCI"
-#define IO_BUS "PCI"
-#elif defined(CONFIG_ARCH_VNC)
-#define HARDWARE "Corel-VNC"
-#define IO_BUS "PCI"
-#else
-#define HARDWARE "unknown"
-#define IO_BUS "unknown"
#endif
#if defined(CONFIG_CPU_ARM2)
@@ -439,8 +437,17 @@ int get_cpuinfo(char * buffer)
(int)processor_id & 15,
(loops_per_sec+2500) / 500000,
((loops_per_sec+2500) / 5000) % 100,
+#ifdef HARDWARE
HARDWARE,
+#else
+ machine_desc[machine_type].machine_name,
+#endif
OPTIMISATION,
- IO_BUS);
+#ifdef IO_BUS
+ IO_BUS
+#else
+ machine_desc[machine_type].bus_name
+#endif
+ );
return len;
}
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 56ada1dc7..5996398f8 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -77,7 +77,8 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
goto out;
if (!(a.flags & MAP_ANONYMOUS)) {
error = -EBADF;
- if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+ if (a.fd >= current->files->max_fds ||
+ !(file = current->files->fd[a.fd]))
goto out;
}
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 7445921d9..22c3639da 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -9,7 +9,7 @@
*
* 1994-07-02 Alan Modra
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/errno.h>
@@ -125,9 +125,11 @@ void do_settimeofday(struct timeval *tv)
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = MAXPHASE;
- time_esterror = MAXPHASE;
+ 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 ();
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 6da813aa2..5d04f325b 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -51,7 +51,7 @@ static int verify_stack_pointer (unsigned long stackptr, int size)
if (stackptr < 0x02048000 || stackptr + size > 0x03000000)
return -EFAULT;
#else
- if (stackptr < 0xc0000000 || stackptr + size > (unsigned long)high_memory)
+ if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory)
return -EFAULT;
#endif
return 0;
@@ -175,7 +175,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret)
printk("(sp underflow)");
printk("\n");
- dump_mem(cstack, sstack + 4096);
+ dump_mem(cstack - 16, sstack + 4096);
frameptr = regs->ARM_fp;
if (frameptr) {
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index d47a092cb..684db2a47 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -26,6 +26,10 @@ ifeq ($(MACHINE),ebsa110)
L_OBJS += io-ebsa110.o
endif
+ifeq ($(MACHINE),vnc)
+ L_OBJS += io-ebsa285.o
+endif
+
ifeq ($(MACHINE),ebsa285)
L_OBJS += io-ebsa285.o
endif
diff --git a/arch/arm/lib/io-ebsa285.S b/arch/arm/lib/io-ebsa285.S
index 0ee1e37fc..a86983d43 100644
--- a/arch/arm/lib/io-ebsa285.S
+++ b/arch/arm/lib/io-ebsa285.S
@@ -104,24 +104,75 @@ ENTRY(outswb)
ENTRY(outsw)
add r0, r0, #0xff000000
add r0, r0, #0x00e00000
-1: teq r2, #0
- ldrneh r3, [r1], #2
- strneh r3, [r0]
- subne r2, r2, #1
- bne 1b
+1: subs r2, r2, #1
+ ldrgeh r3, [r1], #2
+ strgeh r3, [r0]
+ bgt 1b
mov pc, lr
ENTRY(inswb)
mov r2, r2, lsr #1
ENTRY(insw)
+ stmfd sp!, {r4, r5, lr}
add r0, r0, #0xff000000
add r0, r0, #0x00e00000
-1: teq r2, #0
+ @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17
+ subs ip, r2, #8
+ blo too_little
+ @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
+ ands lr, r1, #3 @ check alignment
+ beq 1f
+
+ ldrh r3, [r0]
+ strh r3, [r1], #2
+ sub ip, ip, #1
+ cmn ip, #8
+ blo too_little
+
+1: ldrh r2, [r0]
+ ldrh r3, [r0]
+ orr r2, r2, r3, lsl #16
+ ldrh r3, [r0]
+ ldrh r4, [r0]
+ orr r3, r3, r4, lsl #16
+ ldrh r4, [r0]
+ ldrh r5, [r0]
+ orr r4, r4, r5, lsl #16
+ ldrh r5, [r0]
+ ldrh lr, [r0]
+ orr r5, r5, lr, lsl #16
+ stmia r1!, {r2, r3, r4, r5}
+ subs ip, ip, #8
+ @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1
+ bhs 1b
+ @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7
+ cmn ip, #4
+ ldrhsh r2, [r0] @ ... ... ... ... - 4 - 3 - 2 - 1 ... ...
+ ldrhsh r3, [r0]
+ orrhs r2, r2, r3, lsl #16
+ ldrhsh r3, [r0]
+ ldrhsh r4, [r0]
+ orrhs r3, r3, r4, lsl #16
+ stmhsia r1!, {r2, r3}
+
+ tst ip, #2
+ ldrneh r2, [r0] @ ... ... - 6 - 5 ... ... - 2 - 1 ... ...
ldrneh r3, [r0]
- strneh r3, [r1], #2
- subne r2, r2, #1
- bne 1b
- mov pc, lr
+ orrne r2, r2, r3, lsl #16
+ strne r2, [r1], #4
+
+ tst ip, #1
+ ldrneh r2, [r0]
+ strneh r2, [r1], #2
+
+ ldmfd sp!, {r4, r5, pc}
+
+too_little: subs r2, r2, #1
+ ldrgeh r3, [r0]
+ strgeh r3, [r1], #2
+ bgt too_little
+
+ ldmfd sp!, {r4, r5, pc}
ENTRY(insb)
diff --git a/arch/arm/mm/fault-armo.c b/arch/arm/mm/fault-armo.c
index 4e244a297..6fe1f30ff 100644
--- a/arch/arm/mm/fault-armo.c
+++ b/arch/arm/mm/fault-armo.c
@@ -174,7 +174,7 @@ bad_area:
}
/* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(regs->ARM_pc)) != 0) {
+ if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
tsk->comm, regs->ARM_pc, addr, fixup);
regs->ARM_pc = fixup;
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 98134abac..f090c5f2c 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -208,7 +208,7 @@ bad_area:
}
/* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(regs->ARM_pc)) != 0) {
+ if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
tsk->comm, regs->ARM_pc, addr, fixup);
regs->ARM_pc = fixup;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 613fefce1..b3b0ecf56 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -192,6 +192,15 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10));
+
+#ifdef CONFIG_CPU_26
+ if (max_mapnr <= 128) {
+ extern int sysctl_overcommit_memory;
+ /* On a machine this small we won't get anywhere without
+ overcommit, so turn it on by default. */
+ sysctl_overcommit_memory = 1;
+ }
+#endif
}
void free_initmem (void)
diff --git a/arch/arm/mm/mm-ebsa285.c b/arch/arm/mm/mm-ebsa285.c
index 82bbce899..a5b17c6b9 100644
--- a/arch/arm/mm/mm-ebsa285.c
+++ b/arch/arm/mm/mm-ebsa285.c
@@ -5,7 +5,6 @@
*
* Copyright (C) 1998 Russell King, Dave Gilbert.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -14,46 +13,7 @@
#include <asm/page.h>
#include <asm/io.h>
#include <asm/proc/mm-init.h>
-
-/*
- * These two functions convert PCI bus addresses to virtual addresses
- * and back again.
- */
-unsigned long __virt_to_bus(unsigned long res)
-{
- if (res < PAGE_OFFSET || res >= 0xD0000000) {
- printk("__virt_to_bus: invalid address 0x%08lx\n", res);
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- } else
- res = (res - PAGE_OFFSET) + 0x10000000;
-
- return res;
-}
-
-unsigned long __bus_to_virt(unsigned long res)
-{
- if (res < 0x10000000 || res >= 0x20000000) {
- printk("__bus_to_virt: invalid address 0x%08lx\n", res);
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- } else
- res = (res - 0x10000000) + PAGE_OFFSET;
-
- return res;
-}
-
-/* Logical Physical
- * 0xfff00000 0x40000000 X-Bus
- * 0xffe00000 0x7c000000 PCI I/O space
- * 0xfe000000 0x42000000 CSR
- * 0xfd000000 0x78000000 Outbound write flush
- * 0xfc000000 0x79000000 PCI IACK/special space
- * 0xf9000000 0x7a000000 PCI Config type 1
- * 0xf8000000 0x7b000000 PCI Config type 0
- */
+#include <asm/dec21285.h>
/*
* This is to allow us to fiddle with the EEPROM
@@ -65,15 +25,15 @@ unsigned long __bus_to_virt(unsigned long res)
* until we're happy with them...
*/
#define MAPPING \
- { 0xd8000000, 0x41000000, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \
- { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \
- { 0xe0000000, 0x80000000, 0x10000000, DOMAIN_USER, 1, 1 }, /* VGA */ \
- { 0xf8000000, 0x7b000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
- { 0xf9000000, 0x7a000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
- { 0xfc000000, 0x79000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
- { 0xfd000000, 0x78000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* Outbound wflsh*/ \
- { 0xfe000000, 0x42000000, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
- { 0xffe00000, 0x7c000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
- { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */
+ { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \
+ { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \
+ { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \
+ { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
+ { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
+ { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
+ { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
+ { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
+ { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
+ { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */
#include "mm-armv.c"
diff --git a/arch/arm/mm/mm-rpc.c b/arch/arm/mm/mm-rpc.c
index 18ebe4a47..1c755faaf 100644
--- a/arch/arm/mm/mm-rpc.c
+++ b/arch/arm/mm/mm-rpc.c
@@ -91,7 +91,8 @@ init_dram_banks(struct param_struct *params))
#define MAPPING \
{ SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1 }, /* VRAM */ \
- { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 } /* IO space */
+ { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ \
+ { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1 } /* EASI space */
/*
* Include common routine to set up page tables
*/
diff --git a/arch/arm/mm/mm-vnc.c b/arch/arm/mm/mm-vnc.c
index eed49eb29..94e037485 100644
--- a/arch/arm/mm/mm-vnc.c
+++ b/arch/arm/mm/mm-vnc.c
@@ -13,20 +13,19 @@
#include <asm/page.h>
#include <asm/io.h>
#include <asm/proc/mm-init.h>
+#include <asm/dec21285.h>
/* Table describing the MMU translation mapping
* mainly used to set up the I/O mappings.
*/
#define MAPPING \
- { 0xe0000000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO, 0, 1 }, /* PCI I/O */ \
- { 0xe0100000, DC21285_PCI_TYPE_0_CONFIG, 0x00f00000, DOMAIN_IO, 0, 1 }, /* Type 0 Config */ \
- { 0xe1000000, DC21285_ARMCSR_BASE, 0x00100000, DOMAIN_IO, 0, 1 }, /* ARM CSR */ \
- { 0xe1100000, DC21285_PCI_IACK, 0x00100000, DOMAIN_IO, 0, 1 }, /* PCI IACK */ \
- { 0xe1300000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \
- { 0xe1400000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \
- { 0xe1500000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \
- { 0xe1600000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \
- { 0xe1700000, DC21285_OUTBOUND_WRITE_FLUSH, 0x00100000, DOMAIN_IO, 0, 1 }, /* Out wrflsh */ \
- { 0xe1800000, DC21285_FLASH, 0x00800000, DOMAIN_IO, 0, 1 } /* Flash */
+ { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \
+ { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \
+ { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
+ { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
+ { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
+ { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
+ { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
+ { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
#include "mm-armv.c"
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index d077ab1d2..221797862 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -10,6 +10,11 @@
#include <asm/assembler.h>
#include "../lib/constants.h"
+/* This is the maximum size of an area which will be flushed. If the area
+ * is larger than this, then we flush the whole cache
+ */
+#define MAX_AREA_SIZE 32768
+
.data
Lclean_switch: .long 0
.text
@@ -52,7 +57,7 @@ _sa110_flush_cache_all_r2:
.align 5
_sa110_flush_cache_area:
sub r3, r1, r0
- cmp r3, #32768
+ cmp r3, #MAX_AREA_SIZE
bgt _sa110_flush_cache_all_r2
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c6, 1 @ flush D entry
@@ -79,16 +84,17 @@ _sa110_flush_cache_area:
.align 5
_sa110_cache_wback_area:
sub r3, r1, r0
- cmp r3, #32768
- movgt r2, #0
- bgt _sa110_flush_cache_all
+ cmp r3, #MAX_AREA_SIZE
+ mov r2, #0
+ bgt _sa110_flush_cache_all_r2
+ bic r0, r0, #31
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #32
mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #32
cmp r0, r1
blt 1b
- mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mcr p15, 0, r2, c7, c10, 4 @ drain WB
mov pc, lr
/*
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 3e5c4e7ff..322b53210 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -35,6 +35,10 @@ ifdef CONFIG_M586
CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
endif
+ifdef CONFIG_M586TSC
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
+endif
+
ifdef CONFIG_M686
CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686
endif
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index ff26d087c..64b9377a2 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -40,7 +40,7 @@ zlilo: $(CONFIGURE) $(BOOTIMAGE)
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
install: $(CONFIGURE) $(BOOTIMAGE)
- sh -x ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
+ sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
tools/build: tools/build.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
diff --git a/arch/i386/config.in b/arch/i386/config.in
index a22692bca..3c42052e4 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -14,12 +14,28 @@ comment 'Processor type and features'
choice 'Processor family' \
"386 CONFIG_M386 \
486/Cx486 CONFIG_M486 \
- Pentium/K5/5x86/6x86 CONFIG_M586 \
- PPro/K6/6x86MX CONFIG_M686" Pentium
-bool 'Math emulation' CONFIG_MATH_EMULATION
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
+ 586/K5/5x86/6x86 CONFIG_M586 \
+ Pentium/K6/TSC CONFIG_M586TSC \
+ PPro/6x86MX CONFIG_M686" PPro
+#
+# Define implied options from the CPU selection here
+#
+if [ "$CONFIG_M386" != "y" ]; then
+ define_bool CONFIG_X86_WP_WORKS_OK y
+ define_bool CONFIG_X86_INVLPG y
+ define_bool CONFIG_X86_BSWAP y
+ define_bool CONFIG_X86_POPAD_OK y
+fi
+if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" ]; then
+ define_bool CONFIG_X86_TSC y
fi
+if [ "$CONFIG_M686" = "y" ]; then
+ define_bool CONFIG_X86_GOOD_APIC y
+fi
+
+bool 'Math emulation' CONFIG_MATH_EMULATION
+bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
+bool 'Symmetric multi-processing support' CONFIG_SMP
endmenu
mainmenu_option next_comment
@@ -37,8 +53,16 @@ comment 'General setup'
bool 'Networking support' CONFIG_NET
bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCI BIOS support' CONFIG_PCI_BIOS
- bool ' PCI direct access support' CONFIG_PCI_DIRECT
+ choice 'PCI access mode' \
+ "BIOS CONFIG_PCI_GOBIOS \
+ Direct CONFIG_PCI_GODIRECT \
+ Any CONFIG_PCI_GOANY" Any
+ if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+ define_bool CONFIG_PCI_BIOS y
+ fi
+ if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
+ define_bool CONFIG_PCI_DIRECT y
+ fi
bool ' PCI quirks' CONFIG_PCI_QUIRKS
if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
@@ -46,6 +70,17 @@ if [ "$CONFIG_PCI" = "y" ]; then
bool ' Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
fi
bool 'MCA support' CONFIG_MCA
+bool 'SGI Visual Workstation support' CONFIG_VISWS
+if [ "$CONFIG_VISWS" = "y" ]; then
+ define_bool CONFIG_X86_VISWS_APIC y
+ define_bool CONFIG_X86_LOCAL_APIC y
+else
+ if [ "$CONFIG_SMP" = "y" ]; then
+ define_bool CONFIG_X86_IO_APIC y
+ define_bool CONFIG_X86_LOCAL_APIC y
+ fi
+fi
+
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
@@ -73,6 +108,8 @@ if [ "$CONFIG_APM" = "y" ]; then
bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
+ bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
fi
endmenu
@@ -108,12 +145,15 @@ fi
source net/ax25/Config.in
+source net/irda/Config.in
+
mainmenu_option next_comment
comment 'ISDN subsystem'
-
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
+if [ "$CONFIG_NET" != "n" ]; then
+ tristate 'ISDN support' CONFIG_ISDN
+ if [ "$CONFIG_ISDN" != "n" ]; then
+ source drivers/isdn/Config.in
+ fi
fi
endmenu
@@ -130,8 +170,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/i386/defconfig b/arch/i386/defconfig
index 78351e2d5..200716f59 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -12,9 +12,18 @@
#
# CONFIG_M386 is not set
# CONFIG_M486 is not set
-CONFIG_M586=y
-# CONFIG_M686 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+CONFIG_M686=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_TSC=y
+CONFIG_X86_GOOD_APIC=y
# CONFIG_MATH_EMULATION is not set
+# CONFIG_MTRR is not set
+CONFIG_SMP=y
#
# Loadable module support
@@ -28,11 +37,17 @@ CONFIG_MODULES=y
#
CONFIG_NET=y
CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_QUIRKS=y
CONFIG_PCI_OLD_PROC=y
# CONFIG_MCA is not set
+# CONFIG_VISWS is not set
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_LOCAL_APIC=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
@@ -139,6 +154,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
@@ -146,14 +162,16 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
@@ -206,6 +224,8 @@ CONFIG_EEXPRESS_PRO100=y
# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
# CONFIG_WAN_DRIVERS is not set
# CONFIG_LAPBETHER is not set
# CONFIG_X25_ASY is not set
@@ -237,6 +257,10 @@ CONFIG_SERIAL=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
CONFIG_MOUSE=y
+
+#
+# Mice
+#
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
# CONFIG_MS_BUSMOUSE is not set
@@ -245,9 +269,17 @@ CONFIG_82C710_MOUSE=y
# CONFIG_PC110_PAD is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -259,36 +291,43 @@ CONFIG_82C710_MOUSE=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
-CONFIG_NFSD=y
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_MAC_PARTITION is not set
# CONFIG_NLS is not set
#
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index b8a94af18..0c3f24889 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -38,8 +38,16 @@ ifdef CONFIG_APM
OX_OBJS += apm.o
endif
-ifdef SMP
-O_OBJS += io_apic.o smp.o trampoline.o
+ifdef CONFIG_SMP
+O_OBJS += smp.o trampoline.o
+endif
+
+ifdef CONFIG_X86_IO_APIC
+O_OBJS += io_apic.o
+endif
+
+ifdef CONFIG_X86_VISWS_APIC
+O_OBJS += visws_apic.o
endif
head.o: head.S $(TOPDIR)/include/linux/tasks.h
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 1cbc824f5..6eba89025 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -31,6 +31,8 @@
* Aug 1998, Version 1.5
* Sep 1998, Version 1.6
* Nov 1998, Version 1.7
+ * Jan 1999, Version 1.8
+ * Jan 1999, Version 1.9
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -72,6 +74,22 @@
* Make boot messages far less verbose by default
* Make asm safer
* Stephen Rothwell
+ * 1.8: Add CONFIG_APM_RTC_IS_GMT
+ * Richard Gooch <rgooch@atnf.csiro.au>
+ * change APM_NOINTS to CONFIG_APM_ALLOW_INTS
+ * remove dependency on CONFIG_PROC_FS
+ * Stephen Rothwell
+ * 1.9: Fix small typo. <laslo@ilo.opole.pl>
+ * Try to cope with BIOS's that need to have all display
+ * devices blanked and not just the first one.
+ * Ross Paterson <ross@soi.city.ac.uk>
+ * Fix segment limit setting it has always been wrong as
+ * the segments needed to have byte granularity.
+ * Mark a few things __init.
+ * Add hack to allow power off of SMP systems by popular request.
+ * Use CONFIG_SMP instead of __SMP__
+ * Ignore BOUNCES for three seconds.
+ * Stephen Rothwell
*
* APM 1.1 Reference:
*
@@ -105,10 +123,8 @@
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/linkage.h>
-#ifdef CONFIG_PROC_FS
#include <linux/stat.h>
#include <linux/proc_fs.h>
-#endif
#include <linux/miscdevice.h>
#include <linux/apm_bios.h>
#include <linux/init.h>
@@ -202,13 +218,6 @@ extern unsigned long get_cmos_time(void);
#define ALWAYS_CALL_BUSY
/*
- * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
- * should turn interrupts on before it does a 'hlt').
- * This reportedly needs undefining for the ThinkPad 600.
- */
-#define APM_NOINTS
-
-/*
* Define to make the APM BIOS calls zero all data segment registers (so
* that an incorrect BIOS implementation will cause a kernel panic if it
* tries to write to arbitrary memory).
@@ -216,7 +225,7 @@ extern unsigned long get_cmos_time(void);
#define APM_ZERO_SEGS
/*
- * Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
+ * Define to make all _set_limit calls use 64k limits. The APM 1.1 BIOS is
* supposed to provide limit information that it recognizes. Many machines
* do this correctly, but many others do not restrict themselves to their
* claimed limit. When this happens, they will cause a segmentation
@@ -245,6 +254,12 @@ extern unsigned long get_cmos_time(void);
#define APM_CHECK_TIMEOUT (HZ)
/*
+ * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then
+ * ignore suspend events for this amount of time
+ */
+#define BOUNCE_INTERVAL (3 * HZ)
+
+/*
* Save a segment register away
*/
#define savesegment(seg, where) \
@@ -266,9 +281,7 @@ static ssize_t do_read(struct file *, char *, size_t , loff_t *);
static unsigned int do_poll(struct file *, poll_table *);
static int do_ioctl(struct inode *, struct file *, u_int, u_long);
-#ifdef CONFIG_PROC_FS
static int apm_get_info(char *, char **, off_t, int, int);
-#endif
extern int apm_register_callback(int (*)(apm_event_t));
extern void apm_unregister_callback(int (*)(apm_event_t));
@@ -281,6 +294,7 @@ static asmlinkage struct {
unsigned short segment;
} apm_bios_entry;
static int apm_enabled = 0;
+static int smp_hack = 0;
#ifdef CONFIG_APM_CPU_IDLE
static int clock_slowed = 0;
#endif
@@ -290,8 +304,13 @@ static int standbys_pending = 0;
static int waiting_for_resume = 0;
#endif
+#ifdef CONFIG_APM_RTC_IS_GMT
+# define clock_cmos_diff 0
+# define got_clock_diff 1
+#else
static long clock_cmos_diff;
static int got_clock_diff = 0;
+#endif
static int debug = 0;
static int apm_disabled = 0;
@@ -300,7 +319,7 @@ static struct apm_bios_struct * user_list = NULL;
static struct timer_list apm_timer;
-static char driver_version[] = "1.7"; /* no spaces */
+static char driver_version[] = "1.9"; /* no spaces */
#ifdef APM_DEBUG
static char * apm_event_name[] = {
@@ -375,22 +394,22 @@ static const lookup_t error_table[] = {
#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
/*
- * These are the actual BIOS calls. Depending on APM_ZERO_SEGS
- * and APM_NOINTS, we are being really paranoid here! Not only are
- * interrupts disabled, but all the segment registers (except SS) are
- * saved and zeroed this means that if the BIOS tries to reference any
- * data without explicitly loading the segment registers, the kernel will
- * fault immediately rather than have some unforeseen circumstances for
- * the rest of the kernel. And it will be very obvious! :-) Doing this
- * depends on CS referring to the same physical memory as DS so that DS
- * can be zeroed before the call. Unfortunately, we can't do anything
+ * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and
+ * CONFIG_APM_ALLOW_INTS, we are being really paranoid here! Not only
+ * are interrupts disabled, but all the segment registers (except SS)
+ * are saved and zeroed this means that if the BIOS tries to reference
+ * any data without explicitly loading the segment registers, the kernel
+ * will fault immediately rather than have some unforeseen circumstances
+ * for the rest of the kernel. And it will be very obvious! :-) Doing
+ * this depends on CS referring to the same physical memory as DS so that
+ * DS can be zeroed before the call. Unfortunately, we can't do anything
* about the stack segment/pointer. Also, we tell the compiler that
* everything could change.
*
* Also, we KNOW that for the non error case of apm_bios_call, there
* is no useful data returned in the low order 8 bits of eax.
*/
-#ifdef APM_NOINTS
+#ifndef CONFIG_APM_ALLOW_INTS
# define APM_DO_CLI __cli()
#else
# define APM_DO_CLI
@@ -526,7 +545,15 @@ static int apm_set_power_state(u_short state)
void apm_power_off(void)
{
- if (apm_enabled)
+ /*
+ * smp_hack == 2 means that we would have enabled APM support
+ * except there is more than one processor and so most of
+ * the APM stuff is unsafe. We will still try power down
+ * because is is useful to some people and they know what
+ * they are doing because they booted with the smp-power-off
+ * kernel option.
+ */
+ if (apm_enabled || (smp_hack == 2))
(void) apm_set_power_state(APM_STATE_OFF);
}
@@ -534,12 +561,19 @@ void apm_power_off(void)
/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
static int apm_set_display_power_state(u_short state)
{
- return set_power_state(0x0100, state);
+ int error;
+
+ /* Blank the first display device */
+ error = set_power_state(0x0100, state);
+ if (error == APM_BAD_DEVICE)
+ /* try to blank them all instead */
+ error = set_power_state(0x01ff, state);
+ return error;
}
#endif
#ifdef CONFIG_APM_DO_ENABLE
-static int apm_enable_power_management(void)
+static int __init apm_enable_power_management(void)
{
u32 eax;
@@ -568,12 +602,9 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
return APM_SUCCESS;
}
-#if 0
-/* not used anywhere */
-static int apm_get_battery_status(u_short which,
+static int apm_get_battery_status(u_short which, u_short *status,
u_short *bat, u_short *life, u_short *nbat)
{
- u_short status;
u32 eax;
u32 ebx;
u32 ecx;
@@ -585,20 +616,20 @@ static int apm_get_battery_status(u_short which,
if (which != 1)
return APM_BAD_DEVICE;
*nbat = 1;
- return apm_get_power_status(&status, bat, life);
+ return apm_get_power_status(status, bat, life);
}
if (apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax,
&ebx, &ecx, &edx, &esi))
return (eax >> 8) & 0xff;
+ *status = ebx;
*bat = ecx;
*life = edx;
*nbat = esi;
return APM_SUCCESS;
}
-#endif
-static int apm_engage_power_management(u_short device)
+static int __init apm_engage_power_management(u_short device)
{
u32 eax;
@@ -747,14 +778,17 @@ static void suspend(void)
unsigned long flags;
int err;
- /* Estimate time zone so that set_time can
- update the clock */
+#ifndef CONFIG_APM_RTC_IS_GMT
+ /*
+ * Estimate time zone so that set_time can update the clock
+ */
save_flags(flags);
clock_cmos_diff = -get_cmos_time();
cli();
clock_cmos_diff += CURRENT_TIME;
got_clock_diff = 1;
restore_flags(flags);
+#endif
err = apm_set_power_state(APM_STATE_SUSPEND);
if (err)
@@ -826,7 +860,7 @@ static void check_events(void)
apm_event_t event;
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
static unsigned long last_resume = 0;
- static int did_resume = 0;
+ static int ignore_bounce = 0;
#endif
while ((event = get_event()) != 0) {
@@ -838,6 +872,11 @@ static void check_events(void)
printk(KERN_DEBUG "apm: received unknown "
"event 0x%02x\n", event);
#endif
+#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ if (ignore_bounce
+ && ((jiffies - last_resume) > BOUNCE_INTERVAL))
+ ignore_bounce = 0;
+#endif
switch (event) {
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
@@ -859,7 +898,7 @@ static void check_events(void)
#endif
case APM_SYS_SUSPEND:
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
- if (did_resume && ((jiffies - last_resume) < HZ))
+ if (ignore_bounce)
break;
#endif
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
@@ -880,7 +919,7 @@ static void check_events(void)
#endif
#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
last_resume = jiffies;
- did_resume = 1;
+ ignore_bounce = 1;
#endif
set_time();
send_event(event, 0, NULL);
@@ -1139,13 +1178,13 @@ static int do_open(struct inode * inode, struct file * filp)
return 0;
}
-#ifdef CONFIG_PROC_FS
int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
{
char * p;
unsigned short bx;
unsigned short cx;
unsigned short dx;
+ unsigned short nbat;
unsigned short error;
unsigned short ac_line_status = 0xff;
unsigned short battery_status = 0xff;
@@ -1167,13 +1206,8 @@ int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
if (apm_bios_info.version > 0x100) {
battery_flag = (cx >> 8) & 0xff;
if (dx != 0xffff) {
- if ((dx & 0x8000) == 0x8000) {
- units = "min";
- time_units = dx & 0x7ffe;
- } else {
- units = "sec";
- time_units = dx & 0x7fff;
- }
+ units = (dx & 0x8000) ? "min" : "sec";
+ time_units = dx & 0x7fff;
}
}
}
@@ -1228,7 +1262,6 @@ int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
return p - buf;
}
-#endif
void __init apm_setup(char *str, int *dummy)
{
@@ -1244,6 +1277,8 @@ void __init apm_setup(char *str, int *dummy)
str += 3;
if (strncmp(str, "debug", 5) == 0)
debug = !invert;
+ if (strncmp(str, "smp-power-off", 13) == 0)
+ smp_hack = !invert;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
@@ -1284,17 +1319,18 @@ void __init apm_bios_init(void)
/* BIOS < 1.2 doesn't set cseg_16_len */
if (apm_bios_info.version < 0x102)
- apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */
+ apm_bios_info.cseg_16_len = 0; /* 64k */
if (debug) {
printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
apm_bios_info.cseg, apm_bios_info.offset,
apm_bios_info.cseg_16, apm_bios_info.dseg);
if (apm_bios_info.version > 0x100)
- printk(" cseg len %x, cseg16 len %x, dseg len %x",
+ printk(" cseg len %x, dseg len %x",
apm_bios_info.cseg_len,
- apm_bios_info.cseg_16_len,
apm_bios_info.dseg_len);
+ if (apm_bios_info.version > 0x101)
+ printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
printk("\n");
}
@@ -1302,12 +1338,6 @@ void __init apm_bios_init(void)
printk(KERN_NOTICE "apm: disabled on user request.\n");
return;
}
-#ifdef __SMP__
- if (smp_num_cpus > 1) {
- printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
- return;
- }
-#endif
/*
* Set up a segment that references the real mode segment 0x40
@@ -1317,7 +1347,7 @@ void __init apm_bios_init(void)
*/
set_base(gdt[APM_40 >> 3],
__va((unsigned long)0x40 << 4));
- set_limit(gdt[APM_40 >> 3], 4096 - (0x40 << 4));
+ _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
apm_bios_entry.offset = apm_bios_info.offset;
apm_bios_entry.segment = APM_CS;
@@ -1327,23 +1357,36 @@ void __init apm_bios_init(void)
__va((unsigned long)apm_bios_info.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
__va((unsigned long)apm_bios_info.dseg << 4));
- if (apm_bios_info.version == 0x100) {
- set_limit(gdt[APM_CS >> 3], 64 * 1024);
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
- set_limit(gdt[APM_DS >> 3], 64 * 1024);
- } else {
-#ifdef APM_RELAX_SEGMENTS
+#ifndef APM_RELAX_SEGMENTS
+ if (apm_bios_info.version == 0x100)
+#endif
+ {
/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
- set_limit(gdt[APM_CS >> 3], 64 * 1024);
+ _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
/* For some unknown machine. */
- set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
+ _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1);
/* For the DEC Hinote Ultra CT475 (and others?) */
- set_limit(gdt[APM_DS >> 3], 64 * 1024);
-#else
- set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
- set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len);
- set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
+ _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1);
+ }
+#ifndef APM_RELAX_SEGMENTS
+ else {
+ _set_limit((char *)&gdt[APM_CS >> 3],
+ (apm_bios_info.cseg_len - 1) & 0xffff);
+ _set_limit((char *)&gdt[APM_CS_16 >> 3],
+ (apm_bios_info.cseg_16_len - 1) & 0xffff);
+ _set_limit((char *)&gdt[APM_DS >> 3],
+ (apm_bios_info.dseg_len - 1) & 0xffff);
+ }
+#endif
+#ifdef CONFIG_SMP
+ if (smp_num_cpus > 1) {
+ printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+ if (smp_hack)
+ smp_hack = 2;
+ return;
+ }
#endif
+ if (apm_bios_info.version > 0x100) {
/*
* We only support BIOSs up to version 1.2
*/
@@ -1355,7 +1398,7 @@ void __init apm_bios_init(void)
}
}
if (debug) {
- printk(KERN_INFO "apm: onnection version %d.%d\n",
+ printk(KERN_INFO "apm: Connection version %d.%d\n",
(apm_bios_info.version >> 8) & 0xff,
apm_bios_info.version & 0xff );
@@ -1376,23 +1419,23 @@ void __init apm_bios_init(void)
case 3: bat_stat = "charging"; break;
default: bat_stat = "unknown"; break;
}
- printk(KERN_INFO "apm: AC %s, battery status %s, battery life ",
+ printk(KERN_INFO
+ "apm: AC %s, battery status %s, battery life ",
power_stat, bat_stat);
if ((cx & 0xff) == 0xff)
printk("unknown\n");
else
printk("%d%%\n", cx & 0xff);
if (apm_bios_info.version > 0x100) {
- printk("apm: battery flag 0x%02x, battery life ",
+ printk(KERN_INFO
+ "apm: battery flag 0x%02x, battery life ",
(cx >> 8) & 0xff);
if (dx == 0xffff)
printk("unknown\n");
- else {
- if ((dx & 0x8000))
- printk("%d minutes\n", dx & 0x7ffe );
- else
- printk("%d seconds\n", dx & 0x7fff );
- }
+ else
+ printk("%d %s\n", dx & 0x7fff,
+ (dx & 0x8000) ?
+ "minutes" : "seconds");
}
}
}
@@ -1422,10 +1465,9 @@ void __init apm_bios_init(void)
apm_timer.expires = APM_CHECK_TIMEOUT + jiffies;
add_timer(&apm_timer);
-#ifdef CONFIG_PROC_FS
ent = create_proc_entry("apm", 0, 0);
- ent->get_info = apm_get_info;
-#endif
+ if (ent != NULL)
+ ent->get_info = apm_get_info;
misc_register(&apm_device);
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index 9543fc7ba..e7383e55b 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -352,6 +352,10 @@ __initfunc(int pci_sanity_check(struct pci_access *a))
{
u16 dfn, x;
+#ifdef CONFIG_VISWS
+ return 1; /* Lithium PCI Bridges are non-standard */
+#endif
+
if (pci_probe & PCI_NO_CHECKS)
return 1;
for(dfn=0; dfn < 0x100; dfn++)
@@ -1051,7 +1055,7 @@ __initfunc(void pcibios_fixup_devices(void))
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
-#ifdef __SMP__
+#if defined(CONFIG_X86_IO_APIC)
/*
* Recalculate IRQ numbers if we use the I/O APIC
*/
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 390c10c1f..0153c4b40 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -153,10 +153,10 @@ ENTRY(lcall7)
ALIGN
.globl ret_from_fork
ret_from_fork:
- GET_CURRENT(%ebx)
#ifdef __SMP__
- btrl $0, SYMBOL_NAME(scheduler_lock)
+ call SYMBOL_NAME(schedule_tail)
#endif /* __SMP__ */
+ GET_CURRENT(%ebx)
jmp ret_from_sys_call
/*
@@ -193,6 +193,7 @@ restore_all:
ALIGN
signal_return:
+ sti # we can get here from an interrupt handler
testl $(VM_MASK),EFLAGS(%esp)
movl %esp,%eax
jne v86_signal_return
@@ -558,13 +559,14 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_vfork) /* 190 */
/*
- * NOTE!! This doesn' thave to be exact - we just have
+ * NOTE!! This doesn't have to be exact - we just have
* to make sure we have _enough_ of the "sys_ni_syscall"
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-189
+ .rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 7343cd64f..acbc3e325 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -534,10 +534,14 @@ ENTRY(gdt_table)
.quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
- .quad 0x00c0920000000000 /* 0x40 APM set up for bad BIOS's */
- .quad 0x00c09a0000000000 /* 0x48 APM CS code */
- .quad 0x00809a0000000000 /* 0x50 APM CS 16 code (16 bit) */
- .quad 0x00c0920000000000 /* 0x58 APM DS data */
+ /*
+ * The APM segments have byte granularity and their bases
+ * and limits are set at run time.
+ */
+ .quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */
+ .quad 0x00409a0000000000 /* 0x48 APM CS code */
+ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */
+ .quad 0x0040920000000000 /* 0x58 APM DS data */
.fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
/*
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index e1833f43c..cd9074796 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -58,6 +58,10 @@ EXPORT_SYMBOL_NOVERS(__put_user_1);
EXPORT_SYMBOL_NOVERS(__put_user_2);
EXPORT_SYMBOL_NOVERS(__put_user_4);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strstr);
+
EXPORT_SYMBOL(strncpy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(clear_user);
@@ -83,7 +87,6 @@ EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(smp_message_pass);
EXPORT_SYMBOL(mtrr_hook);
#endif
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index fa8ef26bb..232abf78d 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -225,6 +225,13 @@ static void __init clear_IO_APIC_pin(unsigned int pin)
int pirq_entries [MAX_PIRQS];
int pirqs_enabled;
+void __init ioapic_setup(char *str, int *ints)
+{
+ extern int skip_ioapic_setup; /* defined in arch/i386/kernel/smp.c */
+
+ skip_ioapic_setup = 1;
+}
+
void __init ioapic_pirq_setup(char *str, int *ints)
{
int i, max;
@@ -675,7 +682,8 @@ void __init print_IO_APIC(void)
printk(".... register #01: %08X\n", *(int *)&reg_01);
printk("....... : max redirection entries: %04X\n", reg_01.entries);
if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */
- (reg_01.entries != 0x17) /* ISA+PCI boards */
+ (reg_01.entries != 0x17) && /* ISA+PCI boards */
+ (reg_01.entries != 0x3F) /* Xeon boards */
)
UNEXPECTED_IO_APIC();
if (reg_01.entries == 0x0f)
@@ -683,7 +691,8 @@ void __init print_IO_APIC(void)
printk("....... : IO APIC version: %04X\n", reg_01.version);
if ( (reg_01.version != 0x10) && /* oldest IO-APICs */
- (reg_01.version != 0x11) /* my IO-APIC */
+ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
+ (reg_01.version != 0x13) /* Xeon IO-APICs */
)
UNEXPECTED_IO_APIC();
if (reg_01.__reserved_1 || reg_01.__reserved_2)
@@ -946,7 +955,7 @@ static inline void self_IPI(unsigned int irq)
if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
desc->status = status | IRQ_REPLAY;
- send_IPI(APIC_DEST_SELF, IO_APIC_VECTOR(irq));
+ send_IPI_self(IO_APIC_VECTOR(irq));
}
}
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index 2e3beb11b..445a26613 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -58,7 +58,7 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
+ if (turn_on && !capable(CAP_SYS_RAWIO))
return -EPERM;
/*
* If it's the first ioperm() call in this thread's lifetime, set the
@@ -91,11 +91,15 @@ asmlinkage int sys_iopl(unsigned long unused)
{
struct pt_regs * regs = (struct pt_regs *) &unused;
unsigned int level = regs->ebx;
+ unsigned int old = (regs->eflags >> 12) & 3;
if (level > 3)
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
+ /* Trying to gain more privileges? */
+ if (level > old) {
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ }
regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12);
return 0;
}
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index e0fd62653..37878f59f 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -15,6 +15,7 @@
* Naturally it's not a 1:1 relation, but there are similarities.
*/
+#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
@@ -47,46 +48,28 @@ unsigned int local_irq_count[NR_CPUS];
atomic_t nmi_counter;
/*
- * About the IO-APIC, the architecture is 'merged' into our
- * current irq architecture, seemlessly. (i hope). It is only
- * visible through a few more more hardware interrupt lines, but
- * otherwise drivers are unaffected. The main code is believed
- * to be NR_IRQS-safe (nothing anymore thinks we have 16
- * irq lines only), but there might be some places left ...
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
*/
/*
- * This contains the irq mask for both 8259A irq controllers,
+ * Micro-access to controllers is serialized over the whole
+ * system. We never hold this lock when we call the actual
+ * IRQ handler.
*/
-static unsigned int cached_irq_mask = 0xffff;
-
-#define __byte(x,y) (((unsigned char *)&(y))[x])
-#define __word(x,y) (((unsigned short *)&(y))[x])
-#define __long(x,y) (((unsigned int *)&(y))[x])
-
-#define cached_21 (__byte(0,cached_irq_mask))
-#define cached_A1 (__byte(1,cached_irq_mask))
-
spinlock_t irq_controller_lock;
-/*
- * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
- * boards the timer interrupt is not connected to any IO-APIC pin, it's
- * fed to the CPU IRQ line directly.
- *
- * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
- * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ,
- * but we have _much_ higher compatibility and robustness this way.
- */
-unsigned long long io_apic_irqs = 0;
-
-static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs);
-static void enable_8259A_irq(unsigned int irq);
-void disable_8259A_irq(unsigned int irq);
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define startup_8259A_irq enable_8259A_irq
-#define shutdown_8259A_irq disable_8259A_irq
/*
* Dummy controller type for unused interrupts
@@ -108,6 +91,19 @@ static struct hw_interrupt_type no_irq_type = {
disable_none
};
+/*
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ */
+
+static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs);
+static void enable_8259A_irq(unsigned int irq);
+void disable_8259A_irq(unsigned int irq);
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define startup_8259A_irq enable_8259A_irq
+#define shutdown_8259A_irq disable_8259A_irq
+
static struct hw_interrupt_type i8259A_irq_type = {
"XT-PIC",
startup_8259A_irq,
@@ -117,11 +113,38 @@ static struct hw_interrupt_type i8259A_irq_type = {
disable_8259A_irq
};
-irq_desc_t irq_desc[NR_IRQS] = {
- [0 ... 15] = { 0, &i8259A_irq_type, }, /* default to standard ISA IRQs */
- [16 ... NR_IRQS-1] = { 0, &no_irq_type, }, /* 'high' PCI IRQs filled in on demand */
-};
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+
+
+/*
+ * 8259A PIC functions to handle ISA devices:
+ */
+
+/*
+ * This contains the irq mask for both 8259A irq controllers,
+ */
+static unsigned int cached_irq_mask = 0xffff;
+#define __byte(x,y) (((unsigned char *)&(y))[x])
+#define __word(x,y) (((unsigned short *)&(y))[x])
+#define __long(x,y) (((unsigned int *)&(y))[x])
+
+#define cached_21 (__byte(0,cached_irq_mask))
+#define cached_A1 (__byte(1,cached_irq_mask))
+
+/*
+ * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
+ * boards the timer interrupt is not connected to any IO-APIC pin, it's
+ * fed to the CPU IRQ line directly.
+ *
+ * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
+ * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ,
+ * but we have _much_ higher compatibility and robustness this way.
+ */
+unsigned long long io_apic_irqs = 0;
/*
* These have to be protected by the irq controller spinlock
@@ -149,6 +172,77 @@ static void enable_8259A_irq(unsigned int irq)
}
}
+int i8259A_irq_pending(unsigned int irq)
+{
+ unsigned int mask = 1<<irq;
+
+ if (irq < 8)
+ return (inb(0x20) & mask);
+ return (inb(0xA0) & (mask >> 8));
+}
+
+void make_8259A_irq(unsigned int irq)
+{
+ disable_irq(irq);
+ __long(0,io_apic_irqs) &= ~(1<<irq);
+ irq_desc[irq].handler = &i8259A_irq_type;
+ enable_irq(irq);
+}
+
+/*
+ * Careful! The 8259A is a fragile beast, it pretty
+ * much _has_ to be done exactly like this (mask it
+ * first, _then_ send the EOI, and the order of EOI
+ * to the two 8259s is important!
+ */
+static inline void mask_and_ack_8259A(unsigned int irq)
+{
+ cached_irq_mask |= 1 << irq;
+ if (irq & 8) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x62,0x20); /* Specific EOI to cascade */
+ outb(0x20,0xA0);
+ } else {
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
+ outb(0x20,0x20);
+ }
+}
+
+static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
+{
+ struct irqaction * action;
+ irq_desc_t *desc = irq_desc + irq;
+
+ spin_lock(&irq_controller_lock);
+ {
+ unsigned int status;
+ mask_and_ack_8259A(irq);
+ status = desc->status & ~IRQ_REPLAY;
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ action = desc->action;
+ desc->status = status | IRQ_INPROGRESS;
+ }
+ spin_unlock(&irq_controller_lock);
+
+ /* Exit early if we had no action or it was disabled */
+ if (!action)
+ return;
+
+ handle_IRQ_event(irq, regs, action);
+
+ spin_lock(&irq_controller_lock);
+ {
+ unsigned int status = desc->status & ~IRQ_INPROGRESS;
+ desc->status = status;
+ if (!(status & IRQ_DISABLED))
+ enable_8259A_irq(irq);
+ }
+ spin_unlock(&irq_controller_lock);
+}
+
/*
* This builds up the IRQ handler stubs using some ugly macros in irq.h
*
@@ -168,8 +262,7 @@ BUILD_IRQ(4) BUILD_IRQ(5) BUILD_IRQ(6) BUILD_IRQ(7)
BUILD_IRQ(8) BUILD_IRQ(9) BUILD_IRQ(10) BUILD_IRQ(11)
BUILD_IRQ(12) BUILD_IRQ(13) BUILD_IRQ(14) BUILD_IRQ(15)
-#ifdef __SMP__
-
+#ifdef CONFIG_X86_IO_APIC
/*
* The IO-APIC gives us many more interrupt sources..
*/
@@ -185,11 +278,13 @@ BUILD_IRQ(48) BUILD_IRQ(49) BUILD_IRQ(50) BUILD_IRQ(51)
BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54) BUILD_IRQ(55)
BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59)
BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63)
+#endif
+#ifdef __SMP__
/*
* The following vectors are part of the Linux architecture, there
* is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs), via smp_message_pass():
+ * through the ICC by us (IPIs)
*/
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
@@ -213,7 +308,7 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
-#ifdef __SMP__
+#ifdef CONFIG_X86_IO_APIC
,IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,
IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,
IRQ24_interrupt, IRQ25_interrupt, IRQ26_interrupt, IRQ27_interrupt,
@@ -231,12 +326,16 @@ static void (*interrupt[NR_IRQS])(void) = {
#endif
};
+
/*
* Initial irq handlers.
*/
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+#ifndef CONFIG_VISWS
/*
* Note that on a 486, we don't want to do a SIGFPE on an irq13
* as the irq is unreliable, and exception 16 works correctly
@@ -262,7 +361,13 @@ static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL };
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
+
static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
+#endif
+
+/*
+ * Generic, controller-independent functions:
+ */
int get_irq_list(char *buf)
{
@@ -297,7 +402,7 @@ int get_irq_list(char *buf)
}
p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
#ifdef __SMP__
- p += sprintf(p, "IPI: %10lu\n", ipi_count);
+ p += sprintf(p, "ERR: %10lu\n", ipi_count);
#endif
return p - buf;
}
@@ -335,22 +440,22 @@ static void show(char * str)
int i;
unsigned long *stack;
int cpu = smp_processor_id();
+ extern char *get_options(char *str, int *ints);
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
printk("bh: %d [%d %d]\n",
atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
- stack = (unsigned long *) &str;
+ stack = (unsigned long *) &stack;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
- if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
+ if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) {
printk("<[%08lx]> ", x);
}
}
}
-
#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
@@ -607,79 +712,6 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction *
return status;
}
-int i8259A_irq_pending(unsigned int irq)
-{
- unsigned int mask = 1<<irq;
-
- if (irq < 8)
- return (inb(0x20) & mask);
- return (inb(0xA0) & (mask >> 8));
-}
-
-
-void make_8259A_irq(unsigned int irq)
-{
- disable_irq(irq);
- __long(0,io_apic_irqs) &= ~(1<<irq);
- irq_desc[irq].handler = &i8259A_irq_type;
- enable_irq(irq);
-}
-
-/*
- * Careful! The 8259A is a fragile beast, it pretty
- * much _has_ to be done exactly like this (mask it
- * first, _then_ send the EOI, and the order of EOI
- * to the two 8259s is important!
- */
-static inline void mask_and_ack_8259A(unsigned int irq)
-{
- cached_irq_mask |= 1 << irq;
- if (irq & 8) {
- inb(0xA1); /* DUMMY */
- outb(cached_A1,0xA1);
- outb(0x62,0x20); /* Specific EOI to cascade */
- outb(0x20,0xA0);
- } else {
- inb(0x21); /* DUMMY */
- outb(cached_21,0x21);
- outb(0x20,0x20);
- }
-}
-
-static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
-{
- struct irqaction * action;
- irq_desc_t *desc = irq_desc + irq;
-
- spin_lock(&irq_controller_lock);
- {
- unsigned int status;
- mask_and_ack_8259A(irq);
- status = desc->status & ~IRQ_REPLAY;
- action = NULL;
- if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- action = desc->action;
- desc->status = status | IRQ_INPROGRESS;
- }
- spin_unlock(&irq_controller_lock);
-
- /* Exit early if we had no action or it was disabled */
- if (!action)
- return;
-
- handle_IRQ_event(irq, regs, action);
-
- spin_lock(&irq_controller_lock);
- {
- unsigned int status = desc->status & ~IRQ_INPROGRESS;
- desc->status = status;
- if (!(status & IRQ_DISABLED))
- enable_8259A_irq(irq);
- }
- spin_unlock(&irq_controller_lock);
-}
-
-
/*
* Generic enable/disable code: this just calls
* down into the PIC-specific version for the actual
@@ -691,8 +723,10 @@ void disable_irq(unsigned int irq)
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->disable(irq);
+ if (!irq_desc[irq].depth++) {
+ irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].handler->disable(irq);
+ }
spin_unlock_irqrestore(&irq_controller_lock, flags);
if (irq_desc[irq].status & IRQ_INPROGRESS)
@@ -704,16 +738,18 @@ void enable_irq(unsigned int irq)
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- /*
- * In contrast to the above, we should _not_ have any concurrent
- * interrupt activity here, so we just clear both disabled bits.
- *
- * This allows us to have IRQ_INPROGRESS set until we actually
- * install a handler for this interrupt (make irq autodetection
- * work by just looking at the status field for the irq)
- */
- irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
- irq_desc[irq].handler->enable(irq);
+ switch (irq_desc[irq].depth) {
+ case 1:
+ irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+ irq_desc[irq].handler->enable(irq);
+ /* fall throught */
+ default:
+ irq_desc[irq].depth--;
+ break;
+ case 0:
+ printk("enable_irq() unbalanced from %p\n",
+ __builtin_return_address(0));
+ }
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
@@ -798,6 +834,7 @@ int setup_x86_irq(unsigned int irq, struct irqaction * new)
*p = new;
if (!shared) {
+ irq_desc[irq].depth = 0;
irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
irq_desc[irq].handler->startup(irq);
}
@@ -894,7 +931,7 @@ unsigned long probe_irq_on(void)
/*
* Wait for spurious interrupts to trigger
*/
- for (delay = jiffies + HZ/10; delay > jiffies; )
+ for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
/* about 100ms delay */ synchronize_irq();
/*
@@ -949,21 +986,75 @@ int probe_irq_off(unsigned long unused)
return irq_found;
}
-__initfunc(void init_IRQ(void))
+/*
+ * Silly, horrible hack
+ */
+static char uglybuffer[10*256];
+
+__asm__("\n" __ALIGN_STR"\n"
+ "common_unexpected:\n\t"
+ SAVE_ALL
+ "pushl $ret_from_intr\n\t"
+ "jmp strange_interrupt");
+
+void strange_interrupt(int irqnum)
+{
+ printk("Unexpected interrupt %d\n", irqnum & 255);
+ for (;;);
+}
+
+extern int common_unexpected;
+__initfunc(void init_unexpected_irq(void))
{
int i;
+ for (i = 0; i < 256; i++) {
+ char *code = uglybuffer + 10*i;
+ unsigned long jumpto = (unsigned long) &common_unexpected;
- /* set the clock to 100 Hz */
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
+ jumpto -= (unsigned long)(code+10);
+ code[0] = 0x68; /* pushl */
+ *(int *)(code+1) = i - 512;
+ code[5] = 0xe9; /* jmp */
+ *(int *)(code+6) = jumpto;
+
+ set_intr_gate(i,code);
+ }
+}
+
+
+void init_ISA_irqs (void)
+{
+ int i;
- for (i=0; i<NR_IRQS; i++)
+ for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 0;
+
+ if (i < 16) {
+ /*
+ * 16 old-style INTA-cycle interrupt gates:
+ */
+ irq_desc[i].handler = &i8259A_irq_type;
+ } else {
+ /*
+ * 'high' PCI IRQs filled in on demand
+ */
+ irq_desc[i].handler = &no_irq_type;
+ }
+ }
+}
+
+__initfunc(void init_IRQ(void))
+{
+ int i;
+
+#ifndef CONFIG_X86_VISWS_APIC
+ init_ISA_irqs();
+#else
+ init_VISWS_APIC_irqs();
+#endif
- /*
- * 16 old-style INTA-cycle interrupt gates:
- */
for (i = 0; i < 16; i++)
set_intr_gate(0x20+i,interrupt[i]);
@@ -983,31 +1074,41 @@ __initfunc(void init_IRQ(void))
*/
/* IPI for rescheduling */
- set_intr_gate(0x30, reschedule_interrupt);
+ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for invalidation */
- set_intr_gate(0x31, invalidate_interrupt);
+ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
/* IPI for CPU halt */
- set_intr_gate(0x40, stop_cpu_interrupt);
+ set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt);
/* self generated IPI for local APIC timer */
- set_intr_gate(0x41, apic_timer_interrupt);
+ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
/* IPI for MTRR control */
- set_intr_gate(0x50, mtrr_interrupt);
+ set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
/* IPI vector for APIC spurious interrupts */
- set_intr_gate(0xff, spurious_interrupt);
+ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
#endif
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
+
+ /*
+ * Set the clock to 100 Hz, we already have a valid
+ * vector now:
+ */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+
+#ifndef CONFIG_VISWS
setup_x86_irq(2, &irq2);
setup_x86_irq(13, &irq13);
+#endif
}
-#ifdef __SMP__
-
+#ifdef CONFIG_X86_IO_APIC
__initfunc(void init_IRQ_SMP(void))
{
int i;
@@ -1015,5 +1116,5 @@ __initfunc(void init_IRQ_SMP(void))
if (IO_APIC_VECTOR(i) > 0)
set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]);
}
-
#endif
+
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 9f0b3e457..982ab101e 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -37,10 +37,31 @@ typedef struct {
unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */
struct hw_interrupt_type *handler; /* handle/enable/disable functions */
struct irqaction *action; /* IRQ action list */
- unsigned int unused[3];
+ unsigned int depth; /* Disable depth for nested irq disables */
} irq_desc_t;
-#define IRQ0_TRAP_VECTOR 0x51
+/*
+ * Special IRQ vectors used by the SMP architecture:
+ *
+ * (some of the following vectors are 'rare', they might be merged
+ * into a single vector to save vector space. TLB, reschedule and
+ * local APIC vectors are performance-critical.)
+ */
+#define RESCHEDULE_VECTOR 0x30
+#define INVALIDATE_TLB_VECTOR 0x31
+#define STOP_CPU_VECTOR 0x40
+#define LOCAL_TIMER_VECTOR 0x41
+#define MTRR_CHANGE_VECTOR 0x50
+
+/*
+ * First vector available to drivers: (vectors 0x51-0xfe)
+ */
+#define IRQ0_TRAP_VECTOR 0x51
+
+/*
+ * This IRQ should never happen, but we print a message nevertheless.
+ */
+#define SPURIOUS_APIC_VECTOR 0xff
extern irq_desc_t irq_desc[NR_IRQS];
extern int irq_vector[NR_IRQS];
@@ -48,6 +69,7 @@ extern int irq_vector[NR_IRQS];
extern void init_IRQ_SMP(void);
extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+extern int setup_x86_irq(unsigned int, struct irqaction *);
/*
* Various low-level irq details needed by irq.c, process.c,
@@ -56,17 +78,21 @@ extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
* Interrupt entry/exit code at both C and assembly level
*/
-void mask_irq(unsigned int irq);
-void unmask_irq(unsigned int irq);
-void disable_8259A_irq(unsigned int irq);
-int i8259A_irq_pending(unsigned int irq);
-void ack_APIC_irq(void);
-void setup_IO_APIC(void);
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-void make_8259A_irq(unsigned int irq);
-void send_IPI(int dest, int vector);
-void init_pic_mode(void);
-void print_IO_APIC(void);
+extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
+extern void mask_irq(unsigned int irq);
+extern void unmask_irq(unsigned int irq);
+extern void disable_8259A_irq(unsigned int irq);
+extern int i8259A_irq_pending(unsigned int irq);
+extern void ack_APIC_irq(void);
+extern void FASTCALL(send_IPI_self(int vector));
+extern void smp_send_mtrr(void);
+extern void init_VISWS_APIC_irqs(void);
+extern void setup_IO_APIC(void);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+extern void make_8259A_irq(unsigned int irq);
+extern void send_IPI(int dest, int vector);
+extern void init_pic_mode(void);
+extern void print_IO_APIC(void);
extern unsigned long long io_apic_irqs;
@@ -81,11 +107,7 @@ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
extern char ioapic_OEM_ID [16];
extern char ioapic_Product_ID [16];
-extern spinlock_t irq_controller_lock; /*
- * Protects both the 8259 and the
- * IO-APIC
- */
-
+extern spinlock_t irq_controller_lock;
#ifdef __SMP__
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 324e8cec7..16c767b4a 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -164,6 +164,9 @@
#include <asm/bitops.h>
#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include "irq.h"
+
#define MTRR_VERSION "1.26 (19981001)"
#define TRUE 1
@@ -612,10 +615,11 @@ static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
/* Send a message to all other CPUs and wait for them to enter the
barrier */
atomic_set (&undone_count, smp_num_cpus - 1);
- smp_message_pass (MSG_ALL_BUT_SELF, MSG_MTRR_CHANGE, 0, 0);
+ smp_send_mtrr();
/* Wait for it to be done */
timeout = jiffies + JIFFIE_TIMEOUT;
- while ( (atomic_read (&undone_count) > 0) && (jiffies < timeout) )
+ while ( (atomic_read (&undone_count) > 0) &&
+ time_before(jiffies, timeout) )
barrier ();
if (atomic_read (&undone_count) > 0)
{
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 00f39d4ed..00f7e0ba2 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -105,19 +105,24 @@ static void hard_idle(void)
*/
static int cpu_idle(void *unused)
{
- unsigned long start_idle = jiffies;
+ int work = 1;
+ unsigned long start_idle = 0;
/* endless idle loop with no priority at all */
+ current->priority = 0;
+ current->counter = -100;
for (;;) {
+ if (work)
+ start_idle = jiffies;
+
if (jiffies - start_idle > HARD_IDLE_TIMEOUT)
hard_idle();
else {
if (boot_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched)
__asm__("hlt");
}
- if (current->need_resched)
- start_idle = jiffies;
- current->policy = SCHED_YIELD;
+
+ work = current->need_resched;
schedule();
check_pgt_cache();
}
@@ -131,14 +136,21 @@ static int cpu_idle(void *unused)
int cpu_idle(void *unused)
{
-
/* endless idle loop with no priority at all */
+ current->priority = 0;
+ current->counter = -100;
while(1) {
- if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched)
+ if (current_cpu_data.hlt_works_ok && !hlt_counter &&
+ !current->need_resched)
__asm__("hlt");
- current->policy = SCHED_YIELD;
- schedule();
- check_pgt_cache();
+ /*
+ * although we are an idle CPU, we do not want to
+ * get into the scheduler unnecessarily.
+ */
+ if (current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ }
}
}
@@ -463,24 +475,27 @@ void free_task_struct(struct task_struct *p)
void release_segments(struct mm_struct *mm)
{
- /* forget local segments */
- __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
- : /* no outputs */
- : "r" (0));
if (mm->segments) {
void * ldt = mm->segments;
-
- /*
- * Get the LDT entry from init_task.
- */
- current->tss.ldt = _LDT(0);
- load_ldt(0);
-
mm->segments = NULL;
vfree(ldt);
}
}
+void forget_segments(void)
+{
+ /* forget local segments */
+ __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs"
+ : /* no outputs */
+ : "r" (0));
+
+ /*
+ * Get the LDT entry from init_task.
+ */
+ current->tss.ldt = _LDT(0);
+ load_ldt(0);
+}
+
/*
* Create a kernel thread
*/
@@ -579,7 +594,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
*childregs = *regs;
childregs->eax = 0;
childregs->esp = esp;
- childregs->eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */
p->tss.esp = (unsigned long) childregs;
p->tss.esp0 = (unsigned long) (childregs+1);
@@ -771,6 +785,21 @@ asmlinkage int sys_clone(struct pt_regs regs)
}
/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(struct pt_regs regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs);
+}
+
+/*
* sys_execve() executes a new program.
*/
asmlinkage int sys_execve(struct pt_regs regs)
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 52a1543c3..b0eca4345 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -367,8 +367,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = 0;
goto out;
}
- if (pid == 1) /* you may not mess with init */
- goto out;
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
@@ -376,6 +374,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (!child)
goto out;
ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
@@ -420,7 +420,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
ret = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (ret >= 0)
ret = put_user(tmp,(unsigned long *) data);
goto out;
@@ -451,7 +453,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
ret = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 490c4db82..c3f34270a 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -38,6 +38,7 @@
#include <asm/system.h>
#include <asm/io.h>
#include <asm/smp.h>
+#include <asm/cobalt.h>
/*
* Machine setup..
@@ -45,7 +46,6 @@
char ignore_irq13 = 0; /* set if exception 16 works */
struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
-static char Cx86_step[8]; /* decoded Cyrix step number */
/*
* Bus types ..
@@ -108,6 +108,133 @@ extern unsigned long cpu_hz;
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
+#ifdef CONFIG_VISWS
+char visws_board_type = -1;
+char visws_board_rev = -1;
+
+#define PIIX_PM_START 0x0F80
+
+#define SIO_GPIO_START 0x0FC0
+
+#define SIO_PM_START 0x0FC8
+
+#define PMBASE PIIX_PM_START
+#define GPIREG0 (PMBASE+0x30)
+#define GPIREG(x) (GPIREG0+((x)/8))
+#define PIIX_GPI_BD_ID1 18
+#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1)
+
+#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8)
+
+#define SIO_INDEX 0x2e
+#define SIO_DATA 0x2f
+
+#define SIO_DEV_SEL 0x7
+#define SIO_DEV_ENB 0x30
+#define SIO_DEV_MSB 0x60
+#define SIO_DEV_LSB 0x61
+
+#define SIO_GP_DEV 0x7
+
+#define SIO_GP_BASE SIO_GPIO_START
+#define SIO_GP_MSB (SIO_GP_BASE>>8)
+#define SIO_GP_LSB (SIO_GP_BASE&0xff)
+
+#define SIO_GP_DATA1 (SIO_GP_BASE+0)
+
+#define SIO_PM_DEV 0x8
+
+#define SIO_PM_BASE SIO_PM_START
+#define SIO_PM_MSB (SIO_PM_BASE>>8)
+#define SIO_PM_LSB (SIO_PM_BASE&0xff)
+#define SIO_PM_INDEX (SIO_PM_BASE+0)
+#define SIO_PM_DATA (SIO_PM_BASE+1)
+
+#define SIO_PM_FER2 0x1
+
+#define SIO_PM_GP_EN 0x80
+
+static void
+visws_get_board_type_and_rev(void)
+{
+ int raw;
+
+ visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
+ >> PIIX_GPI_BD_SHIFT;
+/*
+ * Get Board rev.
+ * First, we have to initialize the 307 part to allow us access
+ * to the GPIO registers. Let's map them at 0x0fc0 which is right
+ * after the PIIX4 PM section.
+ */
+ outb_p(SIO_DEV_SEL, SIO_INDEX);
+ outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
+
+ outb_p(SIO_DEV_MSB, SIO_INDEX);
+ outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */
+
+ outb_p(SIO_DEV_LSB, SIO_INDEX);
+ outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */
+
+ outb_p(SIO_DEV_ENB, SIO_INDEX);
+ outb_p(1, SIO_DATA); /* Enable GPIO registers. */
+
+/*
+ * Now, we have to map the power management section to write
+ * a bit which enables access to the GPIO registers.
+ * What lunatic came up with this shit?
+ */
+ outb_p(SIO_DEV_SEL, SIO_INDEX);
+ outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
+
+ outb_p(SIO_DEV_MSB, SIO_INDEX);
+ outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */
+
+ outb_p(SIO_DEV_LSB, SIO_INDEX);
+ outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */
+
+ outb_p(SIO_DEV_ENB, SIO_INDEX);
+ outb_p(1, SIO_DATA); /* Enable PM registers. */
+
+/*
+ * Now, write the PM register which enables the GPIO registers.
+ */
+ outb_p(SIO_PM_FER2, SIO_PM_INDEX);
+ outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
+
+/*
+ * Now, initialize the GPIO registers.
+ * We want them all to be inputs which is the
+ * power on default, so let's leave them alone.
+ * So, let's just read the board rev!
+ */
+ raw = inb_p(SIO_GP_DATA1);
+ raw &= 0x7f; /* 7 bits of valid board revision ID. */
+
+ if (visws_board_type == VISWS_320) {
+ if (raw < 0x6) {
+ visws_board_rev = 4;
+ } else if (raw < 0xc) {
+ visws_board_rev = 5;
+ } else {
+ visws_board_rev = 6;
+
+ }
+ } else if (visws_board_type == VISWS_540) {
+ visws_board_rev = 2;
+ } else {
+ visws_board_rev = raw;
+ }
+
+ printk("Silicon Graphics %s (rev %d)\n",
+ visws_board_type == VISWS_320 ? "320" :
+ (visws_board_type == VISWS_540 ? "540" :
+ "unknown"),
+ visws_board_rev);
+ }
+#endif
+
+
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char saved_command_line[COMMAND_LINE_SIZE];
@@ -123,6 +250,10 @@ __initfunc(void setup_arch(char **cmdline_p,
return;
smptrap=1;
+#ifdef CONFIG_VISWS
+ visws_get_board_type_and_rev();
+#endif
+
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
@@ -146,12 +277,6 @@ __initfunc(void setup_arch(char **cmdline_p,
}
#endif
-#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */
-#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
-
- if (memory_end > MAXMEM)
- memory_end = MAXMEM;
-
memory_end &= PAGE_MASK;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
@@ -201,10 +326,28 @@ __initfunc(void setup_arch(char **cmdline_p,
}
*to = '\0';
*cmdline_p = command_line;
+
+#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */
+#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
+
+ if (memory_end > MAXMEM)
+ {
+ memory_end = MAXMEM;
+ printk(KERN_WARNING "Warning only %ldMB will be used.\n",
+ MAXMEM>>20);
+ }
+
memory_end += PAGE_OFFSET;
*memory_start_p = memory_start;
*memory_end_p = memory_end;
+#ifdef __SMP__
+ /*
+ * Save possible boot-time SMP configuration:
+ */
+ init_smp_config();
+#endif
+
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE) {
initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
@@ -232,6 +375,10 @@ __initfunc(void setup_arch(char **cmdline_p,
conswitchp = &dummy_con;
#endif
#endif
+ /*
+ * Check the bugs that will bite us before we get booting
+ */
+
}
__initfunc(static int amd_model(struct cpuinfo_x86 *c))
@@ -245,6 +392,7 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c))
cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
if (n < 4)
return 0;
+ cpuid(0x80000001, &dummy, &dummy, &dummy, &(c->x86_capability));
v = (unsigned int *) c->x86_model_id;
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
@@ -254,9 +402,9 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c))
}
/*
- * Use the Cyrix DEVID CPU registers if avail. to get more detailed info.
+ * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/
-__initfunc(static void do_cyrix_devid(struct cpuinfo_x86 *c))
+static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{
unsigned char ccr2, ccr3;
@@ -272,22 +420,28 @@ __initfunc(static void do_cyrix_devid(struct cpuinfo_x86 *c))
getCx86(0xc0); /* dummy */
if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
- c->x86_model = 0xfd;
+ *dir0 = 0xfd;
else { /* Cx486S A step */
setCx86(CX86_CCR2, ccr2);
- c->x86_model = 0xfe;
+ *dir0 = 0xfe;
}
}
else {
setCx86(CX86_CCR3, ccr3); /* restore CCR3 */
/* read DIR0 and DIR1 CPU registers */
- c->x86_model = getCx86(CX86_DIR0);
- c->x86_mask = getCx86(CX86_DIR1);
+ *dir0 = getCx86(CX86_DIR0);
+ *dir1 = getCx86(CX86_DIR1);
}
sti();
}
+/*
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
+ * order to identify the Cyrix CPU model after we're out of setup.c
+ */
+unsigned char Cx86_dir0_msb __initdata = 0;
+
static char Cx86_model[][9] __initdata = {
"Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
"M II ", "Unknown"
@@ -305,27 +459,28 @@ static char Cx486D_name[][4] __initdata = {
static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
static char cyrix_model_mult1[] __initdata = "12??43";
static char cyrix_model_mult2[] __initdata = "12233445";
-static char cyrix_model_oldstep[] __initdata = "A step";
__initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
{
- unsigned char dir0_msn, dir0_lsn, dir1;
+ unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
char *buf = c->x86_model_id;
const char *p = NULL;
- do_cyrix_devid(c);
+ do_cyrix_devid(&dir0, &dir1);
- dir0_msn = c->x86_model >> 4;
- dir0_lsn = c->x86_model & 0xf;
- dir1 = c->x86_mask;
+ Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */
+ dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
- /* common case stepping number -- exceptions handled below */
- sprintf(Cx86_step, "%d.%d", (dir1 >> 4) + 1, dir1 & 0x0f);
+ /* common case step number/rev -- exceptions handled below */
+ c->x86_model = (dir1 >> 4) + 1;
+ c->x86_mask = dir1 & 0xf;
/* Now cook; the original recipe is by Channing Corn, from Cyrix.
* We do the same thing for each generation: we work out
- * the model, multiplier and stepping.
+ * the model, multiplier and stepping. Black magic included,
+ * to make the silicon step/rev numbers match the printed ones.
*/
+
switch (dir0_msn) {
unsigned char tmp;
@@ -349,37 +504,41 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
if (dir1 > 0x21) { /* 686L */
Cx86_cb[0] = 'L';
p = Cx86_cb;
- Cx86_step[0]++;
+ (c->x86_model)++;
} else /* 686 */
p = Cx86_cb+1;
break;
case 4: /* MediaGX/GXm */
+ /*
+ * Life sometimes gets weiiiiiiiird if we use this
+ * on the MediaGX. So we turn it off for now.
+ */
+
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
amd_model(c); /* get CPU marketing name */
+ c->x86_capability&=~X86_FEATURE_TSC;
return;
}
else { /* MediaGX */
Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
p = Cx86_cb+2;
- Cx86_step[0] = (dir1 & 0x20) ? '1' : '2';
+ c->x86_model = (dir1 & 0x20) ? 1 : 2;
+ c->x86_capability&=~X86_FEATURE_TSC;
}
break;
case 5: /* 6x86MX/M II */
- /* the TSC is broken (for now) */
- c->x86_capability &= ~16;
-
if (dir1 > 7) dir0_msn++; /* M II */
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
p = Cx86_cb+tmp;
if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
- Cx86_step[0]++;
+ (c->x86_model)++;
break;
- case 0xf: /* Cyrix 486 without DIR registers */
+ case 0xf: /* Cyrix 486 without DEVID registers */
switch (dir0_lsn) {
case 0xd: /* either a 486SLC or DLC w/o DEVID */
dir0_msn = 0;
@@ -389,11 +548,13 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
case 0xe: /* a 486S A step */
dir0_msn = 0;
p = Cx486S_name[0];
- strcpy(Cx86_step, cyrix_model_oldstep);
- c->x86_mask = 1; /* must != 0 to print */
break;
break;
}
+
+ default: /* unknown (shouldn't happen, we know everyone ;-) */
+ dir0_msn = 7;
+ break;
}
strcpy(buf, Cx86_model[dir0_msn & 7]);
if (p) strcat(buf, p);
@@ -445,15 +606,15 @@ static struct cpu_model_info cpu_models[] __initdata = {
"486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
"Am5x86-WB" }},
{ X86_VENDOR_AMD, 5,
- { "K5/SSA5 (PR75, PR90, PR100)", "K5 (PR120, PR133)",
- "K5 (PR166)", "K5 (PR200)", NULL, NULL,
- "K6 (PR166 - PR266)", "K6 (PR166 - PR300)", "K6-2 (PR233 - PR333)",
- "K6-3 (PR300 - PR450)", NULL, NULL, NULL, NULL, NULL, NULL }},
+ { "K5/SSA5", "K5",
+ "K5", "K5", NULL, NULL,
+ "K6", "K6", "K6-2",
+ "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_UMC, 4,
{ NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_CENTAUR, 5,
- { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, NULL, NULL, NULL,
+ { NULL, NULL, NULL, NULL, "C6", NULL, NULL, NULL, "C6-2", NULL, NULL,
NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_NEXGEN, 5,
{ "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -479,6 +640,9 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
return;
}
+ if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
+ return;
+
for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
if (c->cpuid_level > 1) {
/* supports eax=2 call */
@@ -543,15 +707,39 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
return;
}
- if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
- return;
-
sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
}
+/*
+ * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
+ */
+
+__initfunc(void dodgy_tsc(void))
+{
+ get_cpu_vendor(&boot_cpu_data);
+
+ if(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)
+ {
+ return;
+ }
+ cyrix_model(&boot_cpu_data);
+}
+
+
+#define rdmsr(msr,val1,val2) \
+ __asm__ __volatile__("rdmsr" \
+ : "=a" (val1), "=d" (val2) \
+ : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+ __asm__ __volatile__("wrmsr" \
+ : /* no outputs */ \
+ : "c" (msr), "a" (val1), "d" (val2))
+
static char *cpu_vendor_names[] __initdata = {
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
+
__initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
{
char *vendor = NULL;
@@ -569,11 +757,19 @@ __initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
else
printk("%s", c->x86_model_id);
- if (c->x86_mask) {
- if (c->x86_vendor == X86_VENDOR_CYRIX)
- printk(" stepping %s", Cx86_step);
- else
- printk(" stepping %02x", c->x86_mask);
+ if (c->x86_mask || c->cpuid_level>=0)
+ printk(" stepping %02x", c->x86_mask);
+
+ if(c->x86_vendor == X86_VENDOR_CENTAUR)
+ {
+ u32 hv,lv;
+ rdmsr(0x107, lv, hv);
+ printk("\nCentaur FSR was 0x%X ",lv);
+ lv|=(1<<8);
+ lv|=(1<<7);
+ /* lv|=(1<<6); - may help too if the board can cope */
+ printk("now 0x%X", lv);
+ wrmsr(0x107, lv, hv);
}
printk("\n");
}
@@ -597,7 +793,7 @@ int get_cpuinfo(char * buffer)
for(n=0; n<NR_CPUS; n++, c++) {
#ifdef __SMP__
- if (!(cpu_present_map & (1<<n)))
+ if (!(cpu_online_map & (1<<n)))
continue;
#endif
p += sprintf(p,"processor\t: %d\n"
@@ -611,12 +807,9 @@ int get_cpuinfo(char * buffer)
c->x86_model,
c->x86_model_id[0] ? c->x86_model_id : "unknown");
- if (c->x86_mask) {
- if (c->x86_vendor == X86_VENDOR_CYRIX)
- p += sprintf(p, "stepping\t: %s\n", Cx86_step);
- else
- p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
- } else
+ if (c->x86_mask)
+ p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
+ else
p += sprintf(p, "stepping\t: unknown\n");
if (c->x86_capability & X86_FEATURE_TSC) {
@@ -629,21 +822,21 @@ int get_cpuinfo(char * buffer)
p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size);
/* Modify the capabilities according to chip type */
- if (c->x86_mask) {
- if (c->x86_vendor == X86_VENDOR_CYRIX) {
- x86_cap_flags[24] = "cxmmx";
- } else if (c->x86_vendor == X86_VENDOR_AMD) {
- x86_cap_flags[16] = "fcmov";
- x86_cap_flags[31] = "amd3d";
- } else if (c->x86_vendor == X86_VENDOR_INTEL) {
- x86_cap_flags[6] = "pae";
- x86_cap_flags[9] = "apic";
- x86_cap_flags[12] = "mtrr";
- x86_cap_flags[14] = "mca";
- x86_cap_flags[16] = "pat";
- x86_cap_flags[17] = "pse36";
- x86_cap_flags[24] = "osfxsr";
- }
+ if (c->x86_vendor == X86_VENDOR_CYRIX) {
+ x86_cap_flags[24] = "cxmmx";
+ } else if (c->x86_vendor == X86_VENDOR_AMD) {
+ x86_cap_flags[16] = "fcmov";
+ x86_cap_flags[31] = "3dnow";
+ if (c->x86 == 5 && c->x86_model == 6)
+ x86_cap_flags[10] = "sep";
+ } else if (c->x86_vendor == X86_VENDOR_INTEL) {
+ x86_cap_flags[6] = "pae";
+ x86_cap_flags[9] = "apic";
+ x86_cap_flags[12] = "mtrr";
+ x86_cap_flags[14] = "mca";
+ x86_cap_flags[16] = "pat";
+ x86_cap_flags[17] = "pse36";
+ x86_cap_flags[24] = "osfxsr";
}
sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index a5f1f2de0..2960d521c 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -3,12 +3,14 @@
* hosts.
*
* (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
+ * (c) 1998 Ingo Molnar
+ *
* Supported by Caldera http://www.caldera.com.
* Much of the core SMP work is based on previous work by Thomas Radke, to
* whom a great many thanks are extended.
*
- * Thanks to Intel for making available several different Pentium and
- * Pentium Pro MP machines.
+ * Thanks to Intel for making available several different Pentium,
+ * Pentium Pro and Pentium-II/Xeon MP machines.
*
* This code is released under the GNU public license version 2 or
* later.
@@ -26,34 +28,17 @@
* Ingo Molnar : Added APIC timers, based on code
* from Jose Renau
* Alan Cox : Added EBDA scanning
+ * Ingo Molnar : various cleanups and rewrites
*/
#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
-#include <asm/i82489.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
#include <linux/init.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-#include <asm/smp.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_MTRR
-# include <asm/mtrr.h>
-#endif
-
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
+#include <asm/mtrr.h>
#include "irq.h"
@@ -104,31 +89,24 @@ extern void update_one_process( struct task_struct *p,
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
/*
- * Why isn't this somewhere standard ??
- *
- * Maybe because this procedure is horribly buggy, and does
- * not deserve to live. Think about signedness issues for five
- * seconds to see why. - Linus
+ * function prototypes:
*/
-
-extern __inline int max(int a,int b)
-{
- if (a>b)
- return a;
- return b;
-}
+static void cache_APIC_registers (void);
+static void stop_this_cpu (void);
static int smp_b_stepping = 0; /* Set if we find a B stepping CPU */
static int max_cpus = -1; /* Setup configured maximum number of CPUs to activate */
int smp_found_config=0; /* Have we found an SMP box */
-unsigned long cpu_present_map = 0; /* Bitmask of existing CPUs */
+unsigned long cpu_present_map = 0; /* Bitmask of physically existing CPUs */
+unsigned long cpu_online_map = 0; /* Bitmask of currently online CPUs */
int smp_num_cpus = 1; /* Total count of live CPUs */
int smp_threads_ready=0; /* Set when the idlers are all forked */
volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */
volatile int __cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
+static volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
+static volatile unsigned long cpu_callout_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */
volatile unsigned long kstack_ptr; /* Stack vector for booting CPUs */
struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per CPU bogomips and other parameters */
@@ -137,19 +115,13 @@ unsigned long mp_ioapic_addr = 0xFEC00000; /* Address of the I/O apic (not yet
unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
int apic_version[NR_CPUS]; /* APIC version number */
-static volatile int smp_commenced=0; /* Tripped when we start scheduling */
unsigned long apic_retval; /* Just debugging the assembler.. */
-static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */
-
volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */
volatile unsigned long syscall_count=0; /* Number of times the processor holds the syscall lock */
volatile unsigned long ipi_count; /* Number of IPIs delivered */
-volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
-volatile int smp_process_available=0;
-
const char lk_lockmsg[] = "lock from interrupt context at %p\n";
int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
@@ -159,6 +131,7 @@ extern int mpc_default_type;
int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
int mp_current_pci_id = 0;
unsigned long mp_lapic_addr = 0;
+int skip_ioapic_setup = 0; /* 1 if "noapic" boot option passed */
/* #define SMP_DEBUG */
@@ -169,6 +142,11 @@ unsigned long mp_lapic_addr = 0;
#endif
/*
+ * IA s/w dev Vol 3, Section 7.4
+ */
+#define APIC_DEFAULT_PHYS_BASE 0xfee00000
+
+/*
* Setup routine for controlling SMP activation
*
* Command-line option of "nosmp" or "maxcpus=0" will disable SMP
@@ -199,6 +177,11 @@ void ack_APIC_irq(void)
}
/*
+ * Intel MP BIOS table parsing routines:
+ */
+
+#ifndef CONFIG_X86_VISWS_APIC
+/*
* Checksum an MP configuration block.
*/
@@ -250,7 +233,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
{
- printk("Bad signature [%c%c%c%c].\n",
+ panic("SMP mptable: bad signature [%c%c%c%c]!\n",
mpc->mpc_signature[0],
mpc->mpc_signature[1],
mpc->mpc_signature[2],
@@ -259,7 +242,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
{
- printk("Checksum error.\n");
+ panic("SMP mptable: checksum error!\n");
return 1;
}
if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
@@ -405,7 +388,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
}
if (ioapics > 1)
+ {
printk("Warning: Multiple IO-APICs not yet supported.\n");
+ printk("Warning: switching to non APIC mode.\n");
+ skip_ioapic_setup=1;
+ }
return num_processors;
}
@@ -413,7 +400,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
* Scan the memory blocks for an SMP configuration block.
*/
-int __init smp_scan_config(unsigned long base, unsigned long length)
+static int __init smp_scan_config(unsigned long base, unsigned long length)
{
unsigned long *bp=phys_to_virt(base);
struct intel_mp_floating *mpf;
@@ -447,7 +434,7 @@ int __init smp_scan_config(unsigned long base, unsigned long length)
unsigned long cfg;
/* local APIC has default address */
- mp_lapic_addr = 0xFEE00000;
+ mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
/*
* We need to know what the local
* APIC id of the boot CPU is!
@@ -564,6 +551,76 @@ int __init smp_scan_config(unsigned long base, unsigned long length)
return 0;
}
+void __init init_intel_smp (void)
+{
+ /*
+ * FIXME: Linux assumes you have 640K of base ram..
+ * this continues the error...
+ *
+ * 1) Scan the bottom 1K for a signature
+ * 2) Scan the top 1K of base RAM
+ * 3) Scan the 64K of bios
+ */
+ if (!smp_scan_config(0x0,0x400) &&
+ !smp_scan_config(639*0x400,0x400) &&
+ !smp_scan_config(0xF0000,0x10000)) {
+ /*
+ * If it is an SMP machine we should know now, unless the
+ * configuration is in an EISA/MCA bus machine with an
+ * extended bios data area.
+ *
+ * there is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E, calculate and scan it here.
+ *
+ * NOTE! There are Linux loaders that will corrupt the EBDA
+ * area, and as such this kind of SMP config may be less
+ * trustworthy, simply because the SMP table may have been
+ * stomped on during early boot. These loaders are buggy and
+ * should be fixed.
+ */
+ unsigned int address;
+
+ address = *(unsigned short *)phys_to_virt(0x40E);
+ address<<=4;
+ smp_scan_config(address, 0x1000);
+ if (smp_found_config)
+ printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");
+ }
+}
+
+#else
+
+/*
+ * The Visual Workstation is Intel MP compliant in the hardware
+ * sense, but it doesnt have a BIOS(-configuration table).
+ * No problem for Linux.
+ */
+void __init init_visws_smp(void)
+{
+ smp_found_config = 1;
+
+ cpu_present_map |= 2; /* or in id 1 */
+ apic_version[1] |= 0x10; /* integrated APIC */
+ apic_version[0] |= 0x10;
+
+ mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+}
+
+#endif
+
+/*
+ * - Intel MP Configuration Table
+ * - or SGI Visual Workstation configuration
+ */
+void __init init_smp_config (void)
+{
+#ifndef CONFIG_VISWS
+ init_intel_smp();
+#else
+ init_visws_smp();
+#endif
+}
+
/*
* Trampoline 80x86 program as an array.
*/
@@ -630,13 +687,17 @@ void __init smp_store_cpu_info(int id)
* we use to track CPUs as they power up.
*/
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
void __init smp_commence(void)
{
/*
* Lets the callins below out of their loop.
*/
SMP_PRINTK(("Setting commenced=1, go go go\n"));
- smp_commenced=1;
+
+ wmb();
+ atomic_set(&smp_commenced,1);
}
void __init enable_local_APIC(void)
@@ -653,6 +714,26 @@ void __init enable_local_APIC(void)
value &= ~APIC_TPRI_MASK; /* Set Task Priority to 'accept all' */
apic_write(APIC_TASKPRI,value);
+ /*
+ * Set arbitrarion priority to 0
+ */
+ value = apic_read(APIC_ARBPRI);
+ value &= ~APIC_ARBPRI_MASK;
+ apic_write(APIC_ARBPRI, value);
+
+ /*
+ * Set the logical destination ID to 'all', just to be safe.
+ * also, put the APIC into flat delivery mode.
+ */
+ value = apic_read(APIC_LDR);
+ value &= ~APIC_LDR_MASK;
+ value |= SET_APIC_LOGICAL_ID(0xff);
+ apic_write(APIC_LDR,value);
+
+ value = apic_read(APIC_DFR);
+ value |= SET_APIC_DFR(0xf);
+ apic_write(APIC_DFR, value);
+
udelay(100); /* B safe */
ack_APIC_irq();
udelay(100);
@@ -660,12 +741,11 @@ void __init enable_local_APIC(void)
unsigned long __init init_smp_mappings(unsigned long memory_start)
{
- unsigned long apic_phys, ioapic_phys;
+ unsigned long apic_phys;
memory_start = PAGE_ALIGN(memory_start);
if (smp_found_config) {
apic_phys = mp_lapic_addr;
- ioapic_phys = mp_ioapic_addr;
} else {
/*
* set up a fake all zeroes page to simulate the
@@ -674,30 +754,81 @@ unsigned long __init init_smp_mappings(unsigned long memory_start)
* this way if some buggy code writes to this page ...
*/
apic_phys = __pa(memory_start);
- ioapic_phys = __pa(memory_start+PAGE_SIZE);
- memset((void *)memory_start, 0, 2*PAGE_SIZE);
- memory_start += 2*PAGE_SIZE;
+ memset((void *)memory_start, 0, PAGE_SIZE);
+ memory_start += PAGE_SIZE;
}
-
set_fixmap(FIX_APIC_BASE,apic_phys);
- set_fixmap(FIX_IO_APIC_BASE,ioapic_phys);
-
printk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
- printk("mapped IOAPIC to %08lx (%08lx)\n", fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys);
+
+#ifdef CONFIG_X86_IO_APIC
+ {
+ unsigned long ioapic_phys;
+
+ if (smp_found_config) {
+ ioapic_phys = mp_ioapic_addr;
+ } else {
+ ioapic_phys = __pa(memory_start);
+ memset((void *)memory_start, 0, PAGE_SIZE);
+ memory_start += PAGE_SIZE;
+ }
+ set_fixmap(FIX_IO_APIC_BASE,ioapic_phys);
+ printk("mapped IOAPIC to %08lx (%08lx)\n",
+ fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys);
+ }
+#endif
return memory_start;
}
+extern void calibrate_delay(void);
+
void __init smp_callin(void)
{
- extern void calibrate_delay(void);
- int cpuid=GET_APIC_ID(apic_read(APIC_ID));
+ int cpuid;
+ unsigned long timeout;
+
+ /*
+ * (This works even if the APIC is not enabled.)
+ */
+ cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+ SMP_PRINTK(("CPU#%d waiting for CALLOUT\n", cpuid));
+
+ /*
+ * STARTUP IPIs are fragile beasts as they might sometimes
+ * trigger some glue motherboard logic. Complete APIC bus
+ * silence for 1 second, this overestimates the time the
+ * boot CPU is spending to send the up to 2 STARTUP IPIs
+ * by a factor of two. This should be enough.
+ */
+
+ /*
+ * Waiting 2s total for startup (udelay is not yet working)
+ */
+ timeout = jiffies + 2*HZ;
+ while (time_before(jiffies,timeout))
+ {
+ /*
+ * Has the boot CPU finished it's STARTUP sequence?
+ */
+ if (test_bit(cpuid, (unsigned long *)&cpu_callout_map[0]))
+ break;
+ }
+
+ while (!time_before(jiffies,timeout)) {
+ printk("BUG: CPU%d started up but did not get a callout!\n",
+ cpuid);
+ stop_this_cpu();
+ }
/*
- * Activate our APIC
+ * the boot CPU has finished the init stage and is spinning
+ * on callin_map until we finish. We are free to set up this
+ * CPU, first the APIC. (this is probably redundant on most
+ * boards)
*/
- SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
+ SMP_PRINTK(("CALLIN, before enable_local_APIC().\n"));
enable_local_APIC();
/*
@@ -705,7 +836,12 @@ void __init smp_callin(void)
*/
setup_APIC_clock();
- sti();
+ __sti();
+
+#ifdef CONFIG_MTRR
+ /* Must be done before calibration delay is computed */
+ mtrr_init_secondary_cpu ();
+#endif
/*
* Get our bogomips.
*/
@@ -732,13 +868,14 @@ extern int cpu_idle(void * unused);
*/
int __init start_secondary(void *unused)
{
-#ifdef CONFIG_MTRR
- /* Must be done before calibration delay is computed */
- mtrr_init_secondary_cpu ();
-#endif
+ /*
+ * Dont put anything before smp_callin(), SMP
+ * booting is too fragile that we want to limit the
+ * things done here to the most necessary things.
+ */
smp_callin();
- while (!smp_commenced)
- barrier();
+ while (!atomic_read(&smp_commenced))
+ /* nothing */ ;
return cpu_idle(NULL);
}
@@ -761,11 +898,7 @@ void __init initialize_secondary(void)
/*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
- *
- * Get the scheduler lock, because we're going
- * to release it as part of the "reschedule" return.
*/
- spin_lock(&scheduler_lock);
asm volatile(
"movl %0,%%esp\n\t"
@@ -859,8 +992,7 @@ static void __init do_boot_cpu(int i)
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+ cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
apic_write(APIC_ICR, cfg); /* Send IPI */
udelay(200);
@@ -871,8 +1003,7 @@ static void __init do_boot_cpu(int i)
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
- | APIC_DEST_DM_INIT);
+ cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT);
apic_write(APIC_ICR, cfg); /* Send IPI */
/*
@@ -908,19 +1039,23 @@ static void __init do_boot_cpu(int i)
apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
cfg=apic_read(APIC_ICR);
cfg&=~0xCDFFF; /* Clear bits */
- cfg |= (APIC_DEST_FIELD
- | APIC_DEST_DM_STARTUP
- | (start_eip >> 12)); /* Boot on the stack */
+ cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12)); /* Boot on the stack */
SMP_PRINTK(("Before start apic_write.\n"));
apic_write(APIC_ICR, cfg); /* Kick the second */
SMP_PRINTK(("Startup point 1.\n"));
+
timeout = 0;
+ SMP_PRINTK(("Waiting for send to finish...\n"));
do {
- SMP_PRINTK(("Sleeping.\n")); mdelay(1000);
- udelay(10);
- } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
- && (timeout++ < 1000));
+ SMP_PRINTK(("+"));
+ udelay(100);
+ send_status = apic_read(APIC_ICR) & 0x1000;
+ } while (send_status && (timeout++ < 1000));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
udelay(200);
accept_status = (apic_read(APIC_ESR) & 0xEF);
}
@@ -933,6 +1068,13 @@ static void __init do_boot_cpu(int i)
if ( !(send_status || accept_status) )
{
+ /*
+ * allow APs to start initializing.
+ */
+ SMP_PRINTK(("Before Callout %d.\n", i));
+ set_bit(i, (unsigned long *)&cpu_callout_map[0]);
+ SMP_PRINTK(("After Callout %d.\n", i));
+
for(timeout=0;timeout<50000;timeout++)
{
if (cpu_callin_map[0]&(1<<i))
@@ -973,6 +1115,43 @@ static void __init do_boot_cpu(int i)
*((volatile unsigned long *)phys_to_virt(8192)) = 0;
}
+cycles_t cacheflush_time;
+extern unsigned long cpu_hz;
+
+static void smp_tune_scheduling (void)
+{
+ unsigned long cachesize;
+ /*
+ * 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.
+ *
+ * (For a P5 this pretty much means we will choose another idle
+ * CPU almost always at wakeup time (this is due to the small
+ * L1 cache), on PIIs it's around 50-100 usecs, depending on
+ * the cache size)
+ */
+
+ if (!cpu_hz) {
+ /*
+ * this basically disables processor-affinity
+ * scheduling on SMP without a TSC.
+ */
+ cacheflush_time = 0;
+ return;
+ } else {
+ cachesize = boot_cpu_data.x86_cache_size;
+ if (cachesize == -1)
+ cachesize = 8; /* Pentiums */
+
+ cacheflush_time = cpu_hz/1024*cachesize/5000;
+ }
+
+ printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
+ (long)cacheflush_time/(cpu_hz/1000000),
+ ((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
+}
+
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
@@ -983,7 +1162,6 @@ unsigned int prof_counter[NR_CPUS];
void __init smp_boot_cpus(void)
{
int i;
- unsigned long cfg;
#ifdef CONFIG_MTRR
/* Must be done before other processors booted */
@@ -1005,21 +1183,31 @@ void __init smp_boot_cpus(void)
*/
smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
+ smp_tune_scheduling();
printk("CPU%d: ", boot_cpu_id);
print_cpu_info(&cpu_data[boot_cpu_id]);
+ /*
+ * not necessary because the MP table should list the boot
+ * CPU too, but we do it for the sake of robustness anyway.
+ * (and for the case when a non-SMP board boots an SMP kernel)
+ */
cpu_present_map |= (1 << hard_smp_processor_id());
+
cpu_number_map[boot_cpu_id] = 0;
/*
- * If we don't conform to the Intel MPS standard, get out
- * of here now!
+ * If we couldnt find an SMP configuration at boot time,
+ * get out of here now!
*/
if (!smp_found_config)
{
printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n");
+#ifndef CONFIG_VISWS
io_apic_irqs = 0;
+#endif
+ cpu_online_map = cpu_present_map;
goto smp_done;
}
@@ -1082,6 +1270,14 @@ void __init smp_boot_cpus(void)
* Now scan the CPU present map and fire up the other CPUs.
*/
+ /*
+ * Add all detected CPUs. (later on we can down individual
+ * CPUs which will change cpu_online_map but not necessarily
+ * cpu_present_map. We are pretty much ready for hot-swap CPUs.)
+ */
+ cpu_online_map = cpu_present_map;
+ mb();
+
SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
for(i=0;i<NR_CPUS;i++)
@@ -1092,7 +1288,7 @@ void __init smp_boot_cpus(void)
if (i == boot_cpu_id)
continue;
- if ((cpu_present_map & (1 << i))
+ if ((cpu_online_map & (1 << i))
&& (max_cpus < 0 || max_cpus > cpucount+1))
{
do_boot_cpu(i);
@@ -1102,9 +1298,9 @@ void __init smp_boot_cpus(void)
* Make sure we unmap all failed CPUs
*/
- if (cpu_number_map[i] == -1 && (cpu_present_map & (1 << i))) {
- printk("CPU #%d not responding. Removing from cpu_present_map.\n",i);
- cpu_present_map &= ~(1 << i);
+ if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) {
+ printk("CPU #%d not responding. Removing from cpu_online_map.\n",i);
+ cpu_online_map &= ~(1 << i);
}
}
@@ -1112,29 +1308,34 @@ void __init smp_boot_cpus(void)
* Cleanup possible dangling ends...
*/
- /*
- * Install writable page 0 entry.
- */
-
- cfg = pg0[0];
- pg0[0] = 3; /* writeable, present, addr 0 */
- local_flush_tlb();
+#ifndef CONFIG_VISWS
+ {
+ unsigned long cfg;
- /*
- * Paranoid: Set warm reset code and vector here back
- * to default values.
- */
+ /*
+ * Install writable page 0 entry.
+ */
+ cfg = pg0[0];
+ pg0[0] = 3; /* writeable, present, addr 0 */
+ local_flush_tlb();
+
+ /*
+ * Paranoid: Set warm reset code and vector here back
+ * to default values.
+ */
- CMOS_WRITE(0, 0xf);
+ CMOS_WRITE(0, 0xf);
- *((volatile long *) phys_to_virt(0x467)) = 0;
+ *((volatile long *) phys_to_virt(0x467)) = 0;
- /*
- * Restore old page 0 entry.
- */
+ /*
+ * Restore old page 0 entry.
+ */
- pg0[0] = cfg;
- local_flush_tlb();
+ pg0[0] = cfg;
+ local_flush_tlb();
+ }
+#endif
/*
* Allow the user to impress friends.
@@ -1144,14 +1345,14 @@ void __init smp_boot_cpus(void)
if (cpucount==0)
{
printk(KERN_ERR "Error: only one processor found.\n");
- cpu_present_map=(1<<hard_smp_processor_id());
+ cpu_online_map = (1<<hard_smp_processor_id());
}
else
{
unsigned long bogosum=0;
for(i=0;i<32;i++)
{
- if (cpu_present_map&(1<<i))
+ if (cpu_online_map&(1<<i))
bogosum+=cpu_data[i].loops_per_sec;
}
printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -1166,267 +1367,289 @@ void __init smp_boot_cpus(void)
printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
SMP_PRINTK(("Boot done.\n"));
+ cache_APIC_registers();
+#ifndef CONFIG_VISWS
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
*/
- setup_IO_APIC();
+ if (!skip_ioapic_setup)
+ setup_IO_APIC();
+#endif
smp_done:
}
-void send_IPI(int dest, int vector)
-{
- unsigned long cfg;
- unsigned long flags;
-
- __save_flags(flags);
- __cli();
+/*
+ * the following functions deal with sending IPIs between CPUs.
+ *
+ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
+ */
- /*
- * prepare target chip field
- */
- cfg = apic_read(APIC_ICR2) & 0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(dest));
+/*
+ * Silly serialization to work around CPU bug in P5s.
+ * We can safely turn it off on a 686.
+ */
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_APIC_SERIALIZATION 0
+#else
+# define FORCE_APIC_SERIALIZATION 1
+#endif
- cfg = apic_read(APIC_ICR);
- cfg &= ~0xFDFFF;
- cfg |= APIC_DEST_FIELD|APIC_DEST_DM_FIXED|vector;
- cfg |= dest;
-
- /*
- * Send the IPI. The write to APIC_ICR fires this off.
- */
-
- apic_write(APIC_ICR, cfg);
- __restore_flags(flags);
-}
+static unsigned int cached_APIC_ICR;
+static unsigned int cached_APIC_ICR2;
/*
- * A non wait message cannot pass data or CPU source info. This current setup
- * is only safe because the kernel lock owner is the only person who can send
- * a message.
- *
- * Wrapping this whole block in a spinlock is not the safe answer either. A
- * processor may get stuck with IRQs off waiting to send a message and thus
- * not replying to the person spinning for a reply.
+ * Caches reserved bits, APIC reads are (mildly) expensive
+ * and force otherwise unnecessary CPU synchronization.
*
- * In the end flush tlb ought to be the NMI and a very short function
- * (to avoid the old IDE disk problems), and other messages sent with IRQs
- * enabled in a civilised fashion. That will also boost performance.
+ * (We could cache other APIC registers too, but these are the
+ * main ones used in RL.)
*/
+#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF)
+#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF)
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+void cache_APIC_registers (void)
{
- unsigned long cfg;
- unsigned long dest = 0;
- unsigned long target_map;
- int p=smp_processor_id();
- int irq;
- int ct=0;
+ cached_APIC_ICR = slow_ICR;
+ cached_APIC_ICR2 = slow_ICR2;
+ mb();
+}
+static inline unsigned int __get_ICR (void)
+{
+#if FORCE_APIC_SERIALIZATION
/*
- * During boot up send no messages
+ * Wait for the APIC to become ready - this should never occur. It's
+ * a debugging check really.
*/
-
- if (!smp_activated || !smp_commenced)
- return;
+ int count = 0;
+ unsigned int cfg;
+ while (count < 1000)
+ {
+ cfg = slow_ICR;
+ if (!(cfg&(1<<12))) {
+ if (count)
+ atomic_add(count, (atomic_t*)&ipi_count);
+ return cfg;
+ }
+ count++;
+ udelay(10);
+ }
+ printk("CPU #%d: previous IPI still not cleared after 10mS\n",
+ smp_processor_id());
+ return cfg;
+#else
+ return cached_APIC_ICR;
+#endif
+}
- /*
- * Skip the reschedule if we are waiting to clear a
- * message at this time. The reschedule cannot wait
- * but is not critical.
- */
+static inline unsigned int __get_ICR2 (void)
+{
+#if FORCE_APIC_SERIALIZATION
+ return slow_ICR2;
+#else
+ return cached_APIC_ICR2;
+#endif
+}
- switch (msg) {
- case MSG_RESCHEDULE:
- irq = 0x30;
- if (smp_cpu_in_msg[p])
- return;
- break;
+static inline int __prepare_ICR (unsigned int shortcut, int vector)
+{
+ unsigned int cfg;
- case MSG_INVALIDATE_TLB:
- /* make this a NMI some day */
- irq = 0x31;
- break;
+ cfg = __get_ICR();
+ cfg |= APIC_DEST_DM_FIXED|shortcut|vector;
- case MSG_STOP_CPU:
- irq = 0x40;
- break;
+ return cfg;
+}
- case MSG_MTRR_CHANGE:
- irq = 0x50;
- break;
+static inline int __prepare_ICR2 (unsigned int dest)
+{
+ unsigned int cfg;
- default:
- printk("Unknown SMP message %d\n", msg);
- return;
- }
+ cfg = __get_ICR2();
+ cfg |= SET_APIC_DEST_FIELD(dest);
- /*
- * Sanity check we don't re-enter this across CPUs. Only the kernel
- * lock holder may send messages. For a STOP_CPU we are bringing the
- * entire box to the fastest halt we can. A reschedule carries
- * no data and can occur during a flush. Guess what panic
- * I got to notice this bug.
- */
-
- /*
- * We are busy.
- */
-
- smp_cpu_in_msg[p]++;
+ return cfg;
+}
-/* printk("SMP message pass #%d to %d of %d\n",
- p, msg, target);*/
+static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
+{
+ unsigned int cfg;
+/*
+ * Subtle. In the case of the 'never do double writes' workaround we
+ * have to lock out interrupts to be safe. Otherwise it's just one
+ * single atomic write to the APIC, no need for cli/sti.
+ */
+#if FORCE_APIC_SERIALIZATION
+ unsigned long flags;
- /*
- * Wait for the APIC to become ready - this should never occur. It's
- * a debugging check really.
- */
-
- while (ct<1000)
- {
- cfg=apic_read(APIC_ICR);
- if (!(cfg&(1<<12)))
- break;
- ct++;
- udelay(10);
- }
+ __save_flags(flags);
+ __cli();
+#endif
/*
- * Just pray... there is nothing more we can do
+ * No need to touch the target chip field
*/
-
- if (ct==1000)
- printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
+
+ cfg = __prepare_ICR(shortcut, vector);
/*
- * Set the target requirement
+ * Send the IPI. The write to APIC_ICR fires this off.
*/
-
- if (target==MSG_ALL_BUT_SELF)
- {
- dest=APIC_DEST_ALLBUT;
- target_map=cpu_present_map;
- cpu_callin_map[0]=(1<<p);
- }
- else if (target==MSG_ALL)
- {
- dest=APIC_DEST_ALLINC;
- target_map=cpu_present_map;
- cpu_callin_map[0]=0;
- }
- else
- {
- dest=0;
- target_map=(1<<target);
- cpu_callin_map[0]=0;
- }
+ apic_write(APIC_ICR, cfg);
+#if FORCE_APIC_SERIALIZATION
+ __restore_flags(flags);
+#endif
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+ __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+ __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+}
+
+void send_IPI_self(int vector)
+{
+ __send_IPI_shortcut(APIC_DEST_SELF, vector);
+}
+
+static inline void send_IPI_single(int dest, int vector)
+{
+ unsigned long cfg;
+#if FORCE_APIC_SERIALIZATION
+ unsigned long flags;
+
+ __save_flags(flags);
+ __cli();
+#endif
/*
- * Program the APIC to deliver the IPI
+ * prepare target chip field
*/
- send_IPI(dest,irq);
+ cfg = __prepare_ICR2(dest);
+ apic_write(APIC_ICR2, cfg);
/*
- * Spin waiting for completion
+ * program the ICR
*/
+ cfg = __prepare_ICR(0, vector);
- switch(wait)
- {
- int stuck;
- case 1:
- stuck = 50000000;
- while(cpu_callin_map[0]!=target_map) {
- --stuck;
- if (!stuck) {
- printk("stuck on target_map IPI wait\n");
- break;
- }
- }
- break;
- case 2:
- stuck = 50000000;
- /* Wait for invalidate map to clear */
- while (smp_invalidate_needed) {
- /* Take care of "crossing" invalidates */
- if (test_bit(p, &smp_invalidate_needed))
- clear_bit(p, &smp_invalidate_needed);
- --stuck;
- if (!stuck) {
- printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p);
- break;
- }
- }
- break;
- }
-
/*
- * Record our completion
+ * Send the IPI. The write to APIC_ICR fires this off.
*/
-
- smp_cpu_in_msg[p]--;
+ apic_write(APIC_ICR, cfg);
+#if FORCE_APIC_SERIALIZATION
+ __restore_flags(flags);
+#endif
}
/*
- * This is fraught with deadlocks. Linus does a flush tlb at a whim
- * even with IRQs off. We have to avoid a pair of crossing flushes
- * or we are doomed. See the notes about smp_message_pass.
+ * This is fraught with deadlocks. Probably the situation is not that
+ * bad as in the early days of SMP, so we might ease some of the
+ * paranoia here.
*/
void smp_flush_tlb(void)
{
+ int cpu = smp_processor_id();
+ int stuck;
unsigned long flags;
-/* printk("SMI-");*/
-
/*
- * The assignment is safe because it's volatile so the compiler cannot reorder it,
- * because the i586 has strict memory ordering and because only the kernel lock holder
- * may issue a tlb flush. If you break any one of those three change this to an atomic
- * bus locked or.
+ * it's important that we do not generate any APIC traffic
+ * until the AP CPUs have booted up!
*/
+ if (cpu_online_map) {
+ /*
+ * The assignment is safe because it's volatile so the
+ * compiler cannot reorder it, because the i586 has
+ * strict memory ordering and because only the kernel
+ * lock holder may issue a tlb flush. If you break any
+ * one of those three change this to an atomic bus
+ * locked or.
+ */
- smp_invalidate_needed=cpu_present_map;
+ smp_invalidate_needed = cpu_online_map;
- /*
- * Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
- * ensure they don't do a spurious flush tlb or miss one.
- */
+ /*
+ * Processors spinning on some lock with IRQs disabled
+ * will see this IRQ late. The smp_invalidate_needed
+ * map will ensure they don't do a spurious flush tlb
+ * or miss one.
+ */
- __save_flags(flags);
- __cli();
- smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
+ __save_flags(flags);
+ __cli();
+
+ send_IPI_allbutself(INVALIDATE_TLB_VECTOR);
+
+ /*
+ * Spin waiting for completion
+ */
+
+ stuck = 50000000;
+ while (smp_invalidate_needed) {
+ /*
+ * Take care of "crossing" invalidates
+ */
+ if (test_bit(cpu, &smp_invalidate_needed))
+ clear_bit(cpu, &smp_invalidate_needed);
+ --stuck;
+ if (!stuck) {
+ printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
+ break;
+ }
+ }
+ __restore_flags(flags);
+ }
/*
* Flush the local TLB
*/
-
local_flush_tlb();
- __restore_flags(flags);
-
- /*
- * Completed.
- */
-
-/* printk("SMID\n");*/
}
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+
void smp_send_reschedule(int cpu)
{
- unsigned long flags;
+ send_IPI_single(cpu, RESCHEDULE_VECTOR);
+}
- __save_flags(flags);
- __cli();
- smp_message_pass(cpu, MSG_RESCHEDULE, 0L, 0);
- __restore_flags(flags);
+/*
+ * this function sends a 'stop' IPI to all other CPUs in the system.
+ * it goes straight through.
+ */
+
+void smp_send_stop(void)
+{
+ send_IPI_allbutself(STOP_CPU_VECTOR);
+}
+
+/*
+ * this function sends an 'reload MTRR state' IPI to all other CPUs
+ * in the system. it goes straight through, completion processing
+ * is done on the mttr.c level.
+ */
+
+void smp_send_mtrr(void)
+{
+ send_IPI_allbutself(MTRR_CHANGE_VECTOR);
}
/*
@@ -1546,14 +1769,24 @@ asmlinkage void smp_invalidate_interrupt(void)
ack_APIC_irq();
}
+static void stop_this_cpu (void)
+{
+ /*
+ * Remove this CPU:
+ */
+ clear_bit(smp_processor_id(), &cpu_online_map);
+
+ if (cpu_data[smp_processor_id()].hlt_works_ok)
+ for(;;) __asm__("hlt");
+ for (;;);
+}
+
/*
* CPU halt call-back
*/
asmlinkage void smp_stop_cpu_interrupt(void)
{
- if (cpu_data[smp_processor_id()].hlt_works_ok)
- for(;;) __asm__("hlt");
- for (;;) ;
+ stop_this_cpu();
}
void (*mtrr_hook) (void) = NULL;
@@ -1627,12 +1860,9 @@ void setup_APIC_timer(unsigned int clocks)
* Unfortunately the local APIC timer cannot be set up into NMI
* mode. With the IO APIC we can re-route the external timer
* interrupt and broadcast it as an NMI to all CPUs, so no pain.
- *
- * NOTE: this trap vector (0x41) and the gate in
- * BUILD_SMP_TIMER_INTERRUPT should be the same ;)
*/
tmp_value = apic_read(APIC_LVTT);
- lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41;
+ lvtt1_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
apic_write(APIC_LVTT , lvtt1_value);
/*
@@ -1741,7 +1971,7 @@ int __init calibrate_APIC_clock(void)
((long)(t2-t1)/LOOPS)/(1000000/HZ),
((long)(t2-t1)/LOOPS)%(1000000/HZ) );
- printk("..... APIC bus clock speed is %ld.%04ld MHz.\n",
+ printk("..... system bus clock speed is %ld.%04ld MHz.\n",
calibration_result/(1000000/HZ),
calibration_result%(1000000/HZ) );
#undef LOOPS
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index d95d64069..f7987718b 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -108,108 +108,94 @@ asmlinkage int old_select(struct sel_arg_struct *arg)
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int sys_ipc (uint call, int first, int second,
+ int third, void *ptr, long fifth)
{
int version, ret;
- lock_kernel();
version = call >> 16; /* hack for backward compatibility */
call &= 0xffff;
if (call <= SEMCTL)
switch (call) {
case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
+ return sys_semop (first, (struct sembuf *)ptr, second);
case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
+ return sys_semget (first, second, third);
case SEMCTL: {
union semun fourth;
- ret = -EINVAL;
if (!ptr)
- goto out;
- ret = -EFAULT;
+ return -EINVAL;
if (get_user(fourth.__pad, (void **) ptr))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
}
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
+
if (call <= MSGCTL)
switch (call) {
case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
second, third);
- goto out;
case MSGRCV:
switch (version) {
case 0: {
struct ipc_kludge tmp;
- ret = -EINVAL;
if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
+ return -EINVAL;
+
+ if (copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp, second,
+ tmp.msgtyp, third);
}
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ default:
+ return sys_msgrcv (first,
+ (struct msgbuf *) ptr,
+ second, fifth, third);
}
case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
+ return sys_msgget ((key_t) first, second);
case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
+ return sys_msgctl (first, second,
+ (struct msqid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (call <= SHMCTL)
switch (call) {
case SHMAT:
switch (version) {
- case 0: default: {
+ default: {
ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ ret = sys_shmat (first, (char *) ptr,
+ second, &raddr);
if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ return ret;
+ return put_user (raddr, (ulong *) third);
}
case 1: /* iBCS2 emulator entry point */
- ret = -EINVAL;
if (!segment_eq(get_fs(), get_ds()))
- goto out;
- ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
- goto out;
+ return -EINVAL;
+ return sys_shmat (first, (char *) ptr,
+ second, (ulong *) third);
}
case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
+ return sys_shmdt ((char *)ptr);
case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
+ return sys_shmget (first, second, third);
case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- else
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
+
+ return -EINVAL;
}
/*
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index dbd6e1942..ec2ea5d60 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -12,6 +12,8 @@
* precision CMOS clock update
* 1996-05-03 Ingo Molnar
* fixed time warps in do_[slow|fast]_gettimeoffset()
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
* 1998-09-05 (Various)
* More robust do_fast_gettimeoffset() algorithm implemented
* (works with APM, Cyrix 6x86MX and Centaur C6),
@@ -20,6 +22,12 @@
* (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
* Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
* ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
+ * 1998-12-16 Andrea Arcangeli
+ * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
+ * because was not accounting lost_ticks.
+ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli
+ * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
+ * serialize accesses to xtime/lost_ticks).
*/
/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
@@ -57,12 +65,14 @@
#include <linux/timex.h>
#include <linux/config.h>
+#include <asm/fixmap.h>
+#include <asm/cobalt.h>
+
/*
* for x86_do_profile()
*/
#include "irq.h"
-extern int setup_x86_irq(int, struct irqaction *);
unsigned long cpu_hz; /* Detected as we calibrate the TSC */
@@ -78,7 +88,9 @@ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
*/
static unsigned long fast_gettimeoffset_quotient=0;
-static unsigned long do_fast_gettimeoffset(void)
+extern rwlock_t xtime_lock;
+
+static inline unsigned long do_fast_gettimeoffset(void)
{
register unsigned long eax asm("ax");
register unsigned long edx asm("dx");
@@ -88,13 +100,12 @@ static unsigned long do_fast_gettimeoffset(void)
:"=a" (eax), "=d" (edx));
/* .. relative to previous jiffy (32 bits is enough) */
- edx = 0;
eax -= last_tsc_low; /* tsc_low delta */
/*
- * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient.
- * = (tsc_low delta) / (clocks_per_usec)
- * = (tsc_low delta) / (clocks_per_jiffy / usecs_per_jiffy)
+ * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
+ * = (tsc_low delta) * (usecs_per_clock)
+ * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
*
* Using a mull instead of a divl saves up to 31 clock cycles
* in the critical path.
@@ -102,13 +113,17 @@ static unsigned long do_fast_gettimeoffset(void)
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
- :"r" (fast_gettimeoffset_quotient),
- "0" (eax), "1" (edx));
+ :"g" (fast_gettimeoffset_quotient),
+ "0" (eax));
/* our adjusted time offset in microseconds */
- return edx + delay_at_last_interrupt;
+ return delay_at_last_interrupt + edx;
}
+#define TICK_SIZE tick
+
+#ifndef CONFIG_X86_TSC
+
/* This function must be called with interrupts disabled
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
*
@@ -141,8 +156,6 @@ static unsigned long do_fast_gettimeoffset(void)
* comp.protocols.time.ntp!
*/
-#define TICK_SIZE tick
-
static unsigned long do_slow_gettimeoffset(void)
{
int count;
@@ -224,28 +237,45 @@ static unsigned long do_slow_gettimeoffset(void)
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+#else
+
+#define do_gettimeoffset() do_fast_gettimeoffset()
+
+#endif
+
/*
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
*/
void do_gettimeofday(struct timeval *tv)
{
+ extern volatile unsigned long lost_ticks;
unsigned long flags;
+ unsigned long usec, sec;
+
+ read_lock_irqsave(&xtime_lock, flags);
+ usec = do_gettimeoffset();
+ {
+ unsigned long lost = lost_ticks;
+ if (lost)
+ usec += lost * (1000000 / HZ);
+ }
+ sec = xtime.tv_sec;
+ usec += xtime.tv_usec;
+ read_unlock_irqrestore(&xtime_lock, flags);
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
}
- restore_flags(flags);
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
- cli();
+ write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
@@ -254,16 +284,18 @@ void do_settimeofday(struct timeval *tv)
*/
tv->tv_usec -= do_gettimeoffset();
- if (tv->tv_usec < 0) {
+ while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = MAXPHASE;
- time_esterror = MAXPHASE;
- sti();
+ 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;
+ write_unlock_irq(&xtime_lock);
}
/*
@@ -338,8 +370,12 @@ static long last_rtc_update = 0;
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+#ifdef CONFIG_VISWS
+ /* Clear the interrupt */
+ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
+#endif
do_timer(regs);
/*
* In the SMP case we use the local APIC timer interrupt to do the
@@ -359,21 +395,15 @@ static inline void timer_interrupt(int irq, void *dev_id, 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 && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1)) {
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
-#if 0
- /* As we return to user mode fire off the other CPU schedulers.. this is
- basically because we don't yet share IRQ's around. This message is
- rigged to be safe on the 386 - basically it's a hack, so don't look
- closely for now.. */
- smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
-#endif
#ifdef CONFIG_MCA
if( MCA_bus ) {
@@ -392,36 +422,56 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
}
+static int use_tsc = 0;
+
/*
* This is the same as the above, except we _also_ save the current
* Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
*/
-static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int count, flags;
+ int count;
- /* It is important that these two operations happen almost at the
- * same time. We do the RDTSC stuff first, since it's faster. To
- * avoid any inconsistencies, we disable interrupts locally.
- */
+ /*
+ * Here we are in the timer irq handler. We just have irqs locally
+ * disabled but we don't know if the timer_bh is running on the other
+ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+ * the irq version of write_lock because as just said we have irq
+ * locally disabled. -arca
+ */
+ write_lock(&xtime_lock);
+
+ if (use_tsc)
+ {
+ /*
+ * It is important that these two operations happen almost at
+ * the same time. We do the RDTSC stuff first, since it's
+ * faster. To avoid any inconsistencies, we need interrupts
+ * disabled locally.
+ */
+
+ /*
+ * Interrupts are just disabled locally since the timer irq
+ * has the SA_INTERRUPT flag set. -arca
+ */
- __save_flags(flags);
- __cli();
- /* read Pentium cycle counter */
- __asm__("rdtsc"
- :"=a" (last_tsc_low):: "eax", "edx");
+ /* read Pentium cycle counter */
+ __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
- outb_p(0x00, 0x43); /* latch the count ASAP */
+ outb_p(0x00, 0x43); /* latch the count ASAP */
- count = inb_p(0x40); /* read the latched count */
- count |= inb(0x40) << 8;
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+ }
+
+ do_timer_interrupt(irq, NULL, regs);
+
+ write_unlock(&xtime_lock);
- count = ((LATCH-1) - count) * TICK_SIZE;
- delay_at_last_interrupt = (count + LATCH/2) / LATCH;
- __restore_flags(flags);
-
- timer_interrupt(irq, NULL, regs);
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -591,10 +641,25 @@ __initfunc(void time_init(void))
* to disk; this won't break the kernel, though, 'cuz we're
* smart. See arch/i386/kernel/apm.c.
*/
+ /*
+ * Firstly we have to do a CPU check for chips with
+ * a potentially buggy TSC. At this point we haven't run
+ * the ident/bugs checks so we must run this hook as it
+ * may turn off the TSC flag.
+ *
+ * NOTE: this doesnt yet handle SMP 486 machines where only
+ * some CPU's have a TSC. Thats never worked and nobody has
+ * moaned if you have the only one in the world - you fix it!
+ */
+
+ dodgy_tsc();
+
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+#ifndef do_gettimeoffset
do_gettimeoffset = do_fast_gettimeoffset;
+#endif
do_get_fast_time = do_gettimeofday;
- irq0.handler = pentium_timer_interrupt;
+ use_tsc = 1;
fast_gettimeoffset_quotient = calibrate_tsc();
/* report CPU clock rate in Hz.
@@ -609,5 +674,22 @@ __initfunc(void time_init(void))
printk("Detected %ld Hz processor.\n", cpu_hz);
}
}
+
+#ifdef CONFIG_VISWS
+ printk("Starting Cobalt Timer system clock\n");
+
+ /* Set the countdown value */
+ co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
+
+ /* Start the timer */
+ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
+
+ /* Enable (unmask) the timer interrupt */
+ co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
+
+ /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
+ setup_x86_irq(CO_IRQ_TIMER, &irq0);
+#else
setup_x86_irq(0, &irq0);
+#endif
}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 6e9a95423..f0dc06092 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -34,6 +34,14 @@
#include <asm/debugreg.h>
#include <asm/desc.h>
+#include <asm/smp.h>
+
+#ifdef CONFIG_X86_VISWS_APIC
+#include <asm/fixmap.h>
+#include <asm/cobalt.h>
+#include <asm/lithium.h>
+#endif
+
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
@@ -499,15 +507,18 @@ __initfunc(void trap_init_f00f_bug(void))
}
#define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
- "movw %2,%%dx\n\t" \
+do { \
+ int __d0, __d1; \
+ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+ "movw %4,%%dx\n\t" \
"movl %%eax,%0\n\t" \
"movl %%edx,%1" \
:"=m" (*((long *) (gate_addr))), \
- "=m" (*(1+(long *) (gate_addr))) \
+ "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
- "d" ((char *) (addr)),"a" (__KERNEL_CS << 16) \
- :"ax","dx")
+ "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
/*
* This needs to use 'idt_table' rather than 'idt', and
@@ -566,9 +577,100 @@ void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
_set_tssldt_desc(gdt_table+FIRST_LDT_ENTRY+(n<<1), (int)addr, ((size << 3) - 1), 0x82);
}
+#ifdef CONFIG_X86_VISWS_APIC
+
+/*
+ * On Rev 005 motherboards legacy device interrupt lines are wired directly
+ * to Lithium from the 307. But the PROM leaves the interrupt type of each
+ * 307 logical device set appropriate for the 8259. Later we'll actually use
+ * the 8259, but for now we have to flip the interrupt types to
+ * level triggered, active lo as required by Lithium.
+ */
+
+#define REG 0x2e /* The register to read/write */
+#define DEV 0x07 /* Register: Logical device select */
+#define VAL 0x2f /* The value to read/write */
+
+static void
+superio_outb(int dev, int reg, int val)
+{
+ outb(DEV, REG);
+ outb(dev, VAL);
+ outb(reg, REG);
+ outb(val, VAL);
+}
+
+static int __attribute__ ((unused))
+superio_inb(int dev, int reg)
+{
+ outb(DEV, REG);
+ outb(dev, VAL);
+ outb(reg, REG);
+ return inb(VAL);
+}
+
+#define FLOP 3 /* floppy logical device */
+#define PPORT 4 /* parallel logical device */
+#define UART5 5 /* uart2 logical device (not wired up) */
+#define UART6 6 /* uart1 logical device (THIS is the serial port!) */
+#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */
+#define ITYPE 0x71 /* interrupt type register */
+
+/* interrupt type bits */
+#define LEVEL 0x01 /* bit 0, 0 == edge triggered */
+#define ACTHI 0x02 /* bit 1, 0 == active lo */
+
+static void
+superio_init(void)
+{
+ if (visws_board_type == VISWS_320 && visws_board_rev == 5) {
+ superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */
+ printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n");
+ }
+}
+
+static void
+lithium_init(void)
+{
+ set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
+ printk("Lithium PCI Bridge A, Bus Number: %d\n",
+ li_pcia_read16(LI_PCI_BUSNUM) & 0xff);
+ set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
+ printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n",
+ li_pcib_read16(LI_PCI_BUSNUM) & 0xff);
+
+ /* XXX blindly enables all interrupts */
+ li_pcia_write16(LI_PCI_INTEN, 0xffff);
+ li_pcib_write16(LI_PCI_INTEN, 0xffff);
+}
+
+static void
+cobalt_init(void)
+{
+ /*
+ * On normal SMP PC this is used only with SMP, but we have to
+ * use it and set it up here to start the Cobalt clock
+ */
+ set_fixmap(FIX_APIC_BASE, APIC_PHYS_BASE);
+ printk("Local APIC ID %lx\n", apic_read(APIC_ID));
+ printk("Local APIC Version %lx\n", apic_read(APIC_VERSION));
+
+ set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
+ printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));
+
+ set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
+ printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID));
+
+ /* Enable Cobalt APIC being careful to NOT change the ID! */
+ co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE);
+
+ printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
+}
+#endif
void __init trap_init(void)
{
- int i;
+ /* Initially up all of the IDT to jump to unexpected */
+ init_unexpected_irq();
if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
@@ -591,8 +693,6 @@ void __init trap_init(void)
set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);
- for (i=18;i<48;i++)
- set_trap_gate(i,&reserved);
set_system_gate(0x80,&system_call);
/* set up GDT task & ldt entries */
@@ -603,4 +703,9 @@ void __init trap_init(void)
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
load_TR(0);
load_ldt(0);
+#ifdef CONFIG_X86_VISWS_APIC
+ superio_init();
+ lithium_init();
+ cobalt_init();
+#endif
}
diff --git a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c
new file mode 100644
index 000000000..f7dabc15d
--- /dev/null
+++ b/arch/i386/kernel/visws_apic.c
@@ -0,0 +1,407 @@
+/*
+ * linux/arch/i386/kernel/visws_apic.c
+ *
+ * Copyright (C) 1999 Bent Hagemark, Ingo Molnar
+ *
+ * SGI Visual Workstation interrupt controller
+ *
+ * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
+ * which serves as the main interrupt controller in the system. Non-legacy
+ * hardware in the system uses this controller directly. Legacy devices
+ * are connected to the PIIX4 which in turn has its 8259(s) connected to
+ * a of the Cobalt APIC entry.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/tasks.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/smp.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+
+#include <asm/cobalt.h>
+
+#include "irq.h"
+
+/*
+ * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
+ * -- not the manner expected by the normal 8259 code in irq.c.
+ *
+ * there is a 'master' physical interrupt source that gets sent to
+ * the CPU. But in the chipset there are various 'virtual' interrupts
+ * waiting to be handled. We represent this to Linux through a 'master'
+ * interrupt controller type, and through a special virtual interrupt-
+ * controller. Device drivers only see the virtual interrupt sources.
+ */
+
+#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */
+
+static void startup_piix4_master_irq(unsigned int irq);
+static void shutdown_piix4_master_irq(unsigned int irq);
+static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs);
+#define enable_piix4_master_irq startup_piix4_master_irq
+#define disable_piix4_master_irq shutdown_piix4_master_irq
+
+static struct hw_interrupt_type piix4_master_irq_type = {
+ "PIIX4-master",
+ startup_piix4_master_irq,
+ shutdown_piix4_master_irq,
+ do_piix4_master_IRQ,
+ enable_piix4_master_irq,
+ disable_piix4_master_irq
+};
+
+static void enable_piix4_virtual_irq(unsigned int irq);
+static void disable_piix4_virtual_irq(unsigned int irq);
+#define startup_piix4_virtual_irq enable_piix4_virtual_irq
+#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq
+
+static struct hw_interrupt_type piix4_virtual_irq_type = {
+ "PIIX4-virtual",
+ startup_piix4_virtual_irq,
+ shutdown_piix4_virtual_irq,
+ 0, /* no handler, it's never called physically */
+ enable_piix4_virtual_irq,
+ disable_piix4_virtual_irq
+};
+
+/*
+ * This is the SGI Cobalt (IO-)APIC:
+ */
+
+static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs);
+static void enable_cobalt_irq(unsigned int irq);
+static void disable_cobalt_irq(unsigned int irq);
+static void startup_cobalt_irq(unsigned int irq);
+#define shutdown_cobalt_irq disable_cobalt_irq
+
+static struct hw_interrupt_type cobalt_irq_type = {
+ "Cobalt-APIC",
+ startup_cobalt_irq,
+ shutdown_cobalt_irq,
+ do_cobalt_IRQ,
+ enable_cobalt_irq,
+ disable_cobalt_irq
+};
+
+
+/*
+ * Not an initfunc, needed by the reboot code
+ */
+void init_pic_mode(void)
+{
+ /* Nop on Cobalt */
+}
+
+/*
+ * Cobalt (IO)-APIC functions to handle PCI devices.
+ */
+
+static void disable_cobalt_irq(unsigned int irq)
+{
+ /* XXX undo the APIC entry here? */
+
+ /*
+ * definitely, we do not want to have IRQ storms from
+ * unused devices --mingo
+ */
+}
+
+static void enable_cobalt_irq(unsigned int irq)
+{
+}
+
+/*
+ * Set the given Cobalt APIC Redirection Table entry to point
+ * to the given IDT vector/index.
+ */
+static void co_apic_set(int entry, int idtvec)
+{
+ co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec));
+ co_apic_write(CO_APIC_HI(entry), 0);
+
+ printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec);
+}
+
+/*
+ * "irq" really just serves to identify the device. Here is where we
+ * map this to the Cobalt APIC entry where it's physically wired.
+ * This is called via request_irq -> setup_x86_irq -> irq_desc->startup()
+ */
+static void startup_cobalt_irq(unsigned int irq)
+{
+ /*
+ * These "irq"'s are wired to the same Cobalt APIC entries
+ * for all (known) motherboard types/revs
+ */
+ switch (irq) {
+ case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER);
+ return;
+
+ case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET);
+ return;
+
+ case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */
+
+ case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259);
+ return;
+
+ case CO_IRQ_IDE:
+ switch (visws_board_type) {
+ case VISWS_320:
+ switch (visws_board_rev) {
+ case 5:
+ co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE);
+ co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE);
+ return;
+ case 6:
+ co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE);
+ co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE);
+ return;
+ }
+ case VISWS_540:
+ switch (visws_board_rev) {
+ case 2:
+ co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE);
+ return;
+ }
+ }
+ break;
+ default:
+ panic("huh?");
+ }
+}
+
+/*
+ * This is the handle() op in do_IRQ()
+ */
+static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs)
+{
+ struct irqaction * action;
+ irq_desc_t *desc = irq_desc + irq;
+
+ spin_lock(&irq_controller_lock);
+ {
+ unsigned int status;
+ /* XXX APIC EOI? */
+ status = desc->status & ~IRQ_REPLAY;
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ action = desc->action;
+ desc->status = status | IRQ_INPROGRESS;
+ }
+ spin_unlock(&irq_controller_lock);
+
+ /* Exit early if we had no action or it was disabled */
+ if (!action)
+ return;
+
+ handle_IRQ_event(irq, regs, action);
+
+ (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */
+ apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */
+
+ spin_lock(&irq_controller_lock);
+ {
+ unsigned int status = desc->status & ~IRQ_INPROGRESS;
+ desc->status = status;
+ if (!(status & IRQ_DISABLED))
+ enable_cobalt_irq(irq);
+ }
+ spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * PIIX4-8259 master/virtual functions to handle:
+ *
+ * floppy
+ * parallel
+ * serial
+ * audio (?)
+ *
+ * None of these get Cobalt APIC entries, neither do they have IDT
+ * entries. These interrupts are purely virtual and distributed from
+ * the 'master' interrupt source: CO_IRQ_8259.
+ *
+ * When the 8259 interrupts its handler figures out which of these
+ * devices is interrupting and dispatches to it's handler.
+ *
+ * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
+ * enable_irq gets the right irq. This 'master' irq is never directly
+ * manipulated by any driver.
+ */
+
+static void startup_piix4_master_irq(unsigned int irq)
+{
+ /* ICW1 */
+ outb(0x11, 0x20);
+ outb(0x11, 0xa0);
+
+ /* ICW2 */
+ outb(0x08, 0x21);
+ outb(0x70, 0xa1);
+
+ /* ICW3 */
+ outb(0x04, 0x21);
+ outb(0x02, 0xa1);
+
+ /* ICW4 */
+ outb(0x01, 0x21);
+ outb(0x01, 0xa1);
+
+ /* OCW1 - disable all interrupts in both 8259's */
+ outb(0xff, 0x21);
+ outb(0xff, 0xa1);
+
+ startup_cobalt_irq(irq);
+}
+
+static void shutdown_piix4_master_irq(unsigned int irq)
+{
+ /*
+ * [we skip the 8259 magic here, not strictly necessary]
+ */
+
+ shutdown_cobalt_irq(irq);
+}
+
+static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs)
+{
+ int realirq, mask;
+
+ /* Find out what's interrupting in the PIIX4 8259 */
+
+ spin_lock(&irq_controller_lock);
+ outb(0x0c, 0x20); /* OCW3 Poll command */
+ realirq = inb(0x20);
+
+ if (!(realirq & 0x80)) {
+ /*
+ * Bit 7 == 0 means invalid/spurious
+ */
+ goto out_unlock;
+ }
+ realirq &= 0x7f;
+
+ /*
+ * mask and ack the 8259
+ */
+ mask = inb(0x21);
+ if ((mask >> realirq) & 0x01)
+ /*
+ * This IRQ is masked... ignore
+ */
+ goto out_unlock;
+
+ outb(mask | (1<<realirq), 0x21);
+ /*
+ * OCW2 - non-specific EOI
+ */
+ outb(0x20, 0x20);
+
+ spin_unlock(&irq_controller_lock);
+
+ /*
+ * handle this 'virtual interrupt' as a Cobalt one now.
+ */
+ kstat.irqs[smp_processor_id()][irq]++;
+ do_cobalt_IRQ(realirq, regs);
+
+ spin_lock(&irq_controller_lock);
+ {
+ irq_desc_t *desc = irq_desc + realirq;
+
+ if (!(desc->status & IRQ_DISABLED))
+ enable_piix4_virtual_irq(realirq);
+ }
+ spin_unlock(&irq_controller_lock);
+ return;
+
+out_unlock:
+ spin_unlock(&irq_controller_lock);
+ return;
+}
+
+static void enable_piix4_virtual_irq(unsigned int irq)
+{
+ /*
+ * assumes this irq is one of the legacy devices
+ */
+
+ unsigned int mask = inb(0x21);
+ mask &= ~(1 << irq);
+ outb(mask, 0x21);
+ enable_cobalt_irq(irq);
+}
+
+/*
+ * assumes this irq is one of the legacy devices
+ */
+static void disable_piix4_virtual_irq(unsigned int irq)
+{
+ unsigned int mask;
+
+ disable_cobalt_irq(irq);
+
+ mask = inb(0x21);
+ mask &= ~(1 << irq);
+ outb(mask, 0x21);
+}
+
+static struct irqaction master_action =
+ { no_action, 0, 0, "PIIX4-8259", NULL, NULL };
+
+void init_VISWS_APIC_irqs(void)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 0;
+
+ /*
+ * Cobalt IRQs are mapped to standard ISA
+ * interrupt vectors:
+ */
+ switch (i) {
+ /*
+ * Only CO_IRQ_8259 will be raised
+ * externally.
+ */
+ case CO_IRQ_8259:
+ irq_desc[i].handler = &piix4_master_irq_type;
+ break;
+ case CO_IRQ_FLOPPY:
+ case CO_IRQ_PARLL:
+ irq_desc[i].handler = &piix4_virtual_irq_type;
+ break;
+ default:
+ irq_desc[i].handler = &cobalt_irq_type;
+ break;
+ }
+ }
+
+ /*
+ * The master interrupt is always present:
+ */
+ setup_x86_irq(CO_IRQ_8259, &master_action);
+}
+
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 6490984b1..c2cb3e5a6 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -6,6 +6,7 @@
$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = lib.a
-L_OBJS = checksum.o semaphore.o delay.o usercopy.o getuser.o putuser.o
+L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \
+ usercopy.o getuser.o putuser.o
include $(TOPDIR)/Rules.make
diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
new file mode 100644
index 000000000..46527a85d
--- /dev/null
+++ b/arch/i386/lib/checksum.S
@@ -0,0 +1,447 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+.text
+.align 4
+.globl csum_partial
+
+#if CPU!=686
+
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: unsigned char *buff
+ testl $2, %esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%esi), %bx
+ addl $2, %esi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, %edx
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+1: movl (%esi), %ebx
+ adcl %ebx, %eax
+ movl 4(%esi), %ebx
+ adcl %ebx, %eax
+ movl 8(%esi), %ebx
+ adcl %ebx, %eax
+ movl 12(%esi), %ebx
+ adcl %ebx, %eax
+ movl 16(%esi), %ebx
+ adcl %ebx, %eax
+ movl 20(%esi), %ebx
+ adcl %ebx, %eax
+ movl 24(%esi), %ebx
+ adcl %ebx, %eax
+ movl 28(%esi), %ebx
+ adcl %ebx, %eax
+ lea 32(%esi), %esi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+3: adcl (%esi), %eax
+ lea 4(%esi), %esi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+ movw (%esi),%cx
+ leal 2(%esi),%esi
+ je 6f
+ shll $16,%ecx
+5: movb (%esi),%cl
+6: addl %ecx,%eax
+ adcl $0, %eax
+7:
+ popl %ebx
+ popl %esi
+ ret
+
+#else /* CPU==686 */
+
+csum_partial:
+ movl 12(%esp),%eax # Function arg: unsigned int sum
+ movl 8(%esp),%ecx # Function arg: int len
+ movl 4(%esp),%esi # Function arg: const unsigned char *buf
+
+ testl $2, %esi
+ jnz 30f
+10:
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ andl $0x7c, %ebx
+ shrl $7, %ecx
+ addl %ebx,%esi
+ shrl $2, %ebx
+ negl %ebx
+ lea 45f(%ebx,%ebx,2), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%esi), %ax
+ lea 2(%esi), %esi
+ adcl $0, %eax
+ jmp 10b
+
+30: subl $2, %ecx
+ ja 20b
+ je 32f
+ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
+ addl %ebx, %eax
+ adcl $0, %eax
+ jmp 80f
+32:
+ addw (%esi), %ax # csumming 2 bytes, 2-aligned
+ adcl $0, %eax
+ jmp 80f
+
+40:
+ addl -128(%esi), %eax
+ adcl -124(%esi), %eax
+ adcl -120(%esi), %eax
+ adcl -116(%esi), %eax
+ adcl -112(%esi), %eax
+ adcl -108(%esi), %eax
+ adcl -104(%esi), %eax
+ adcl -100(%esi), %eax
+ adcl -96(%esi), %eax
+ adcl -92(%esi), %eax
+ adcl -88(%esi), %eax
+ adcl -84(%esi), %eax
+ adcl -80(%esi), %eax
+ adcl -76(%esi), %eax
+ adcl -72(%esi), %eax
+ adcl -68(%esi), %eax
+ adcl -64(%esi), %eax
+ adcl -60(%esi), %eax
+ adcl -56(%esi), %eax
+ adcl -52(%esi), %eax
+ adcl -48(%esi), %eax
+ adcl -44(%esi), %eax
+ adcl -40(%esi), %eax
+ adcl -36(%esi), %eax
+ adcl -32(%esi), %eax
+ adcl -28(%esi), %eax
+ adcl -24(%esi), %eax
+ adcl -20(%esi), %eax
+ adcl -16(%esi), %eax
+ adcl -12(%esi), %eax
+ adcl -8(%esi), %eax
+ adcl -4(%esi), %eax
+45:
+ lea 128(%esi), %esi
+ adcl $0, %eax
+ dec %ecx
+ jge 40b
+ movl %edx, %ecx
+50: andl $3, %ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%ebx # by the shll and shrl instructions
+ shll $3,%ecx
+ shrl %cl,%ebx
+ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
+ addl %ebx,%eax
+ adcl $0,%eax
+80:
+ ret
+
+#endif /* CPU==686 */
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ * DST definitions? It's damn hard to trigger all cases. I hope I got
+ * them all but there's no guarantee.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+.align 4
+.globl csum_partial_copy_generic
+
+#if CPU!=686
+
+#define ARGBASE 16
+#define FP 12
+
+csum_partial_copy_generic:
+ subl $4,%esp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ movl ARGBASE+16(%esp),%eax # sum
+ movl ARGBASE+12(%esp),%ecx # len
+ movl ARGBASE+4(%esp),%esi # src
+ movl ARGBASE+8(%esp),%edi # dst
+
+ testl $2, %edi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+SRC(1: movw (%esi), %bx )
+ addl $2, %esi
+DST( movw %bx, (%edi) )
+ addl $2, %edi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, FP(%esp)
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+SRC(1: movl (%esi), %ebx )
+SRC( movl 4(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 4(%edi) )
+
+SRC( movl 8(%esi), %ebx )
+SRC( movl 12(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 8(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 12(%edi) )
+
+SRC( movl 16(%esi), %ebx )
+SRC( movl 20(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 16(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 20(%edi) )
+
+SRC( movl 24(%esi), %ebx )
+SRC( movl 28(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 24(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 28(%edi) )
+
+ lea 32(%esi), %esi
+ lea 32(%edi), %edi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl FP(%esp), %edx
+ movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+SRC(3: movl (%esi), %ebx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ lea 4(%esi), %esi
+ lea 4(%edi), %edi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+SRC( movw (%esi), %cx )
+ leal 2(%esi), %esi
+DST( movw %cx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%ecx
+SRC(5: movb (%esi), %cl )
+DST( movb %cl, (%edi) )
+6: addl %ecx, %eax
+ adcl $0, %eax
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"
+
+6001:
+ movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+
+ # zero the complete destination - computing the rest
+ # is too much work
+ movl ARGBASE+8(%esp), %edi # dst
+ movl ARGBASE+12(%esp), %ecx # len
+ xorl %eax,%eax
+ rep ; stosb
+
+ jmp 5000b
+
+6002:
+ movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT,(%ebx)
+ jmp 5000b
+
+.previous
+
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ecx # equivalent to addl $4,%esp
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+#define ROUND1(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ addl %ebx, %eax\n ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ROUND(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ adcl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ARGBASE 12
+
+csum_partial_copy_generic:
+ pushl %ebx
+ pushl %edi
+ pushl %esi
+ movl ARGBASE+4(%esp),%esi #src
+ movl ARGBASE+8(%esp),%edi #dst
+ movl ARGBASE+12(%esp),%ecx #len
+ movl ARGBASE+16(%esp),%eax #sum
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ shrl $6, %ecx
+ andl $0x3c, %ebx
+ negl %ebx
+ subl %ebx, %esi
+ subl %ebx, %edi
+ lea 3f(%ebx,%ebx), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+1: addl $64,%esi
+ addl $64,%edi
+ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
+3: adcl $0,%eax
+ dec %ecx
+ jge 1b
+4: andl $3, %edx
+ jz 7f
+ cmpl $2, %edx
+ jb 5f
+SRC( movw (%esi), %dx )
+ leal 2(%esi), %esi
+DST( movw %dx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%edx
+5:
+SRC( movb (%esi), %dl )
+DST( movb %dl, (%edi) )
+6: addl %edx, %eax
+ adcl $0, %eax
+7:
+.section .fixup, "ax"
+6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+ # zero the complete destination (computing the rest is too much work)
+ movl ARGBASE+8(%esp),%edi # dst
+ movl ARGBASE+12(%esp),%ecx # len
+ xorl %eax,%eax
+ rep; stosb
+ jmp 7b
+6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT, (%ebx)
+ jmp 7b
+.previous
+
+ popl %esi
+ popl %edi
+ popl %ebx
+ ret
+
+#undef ROUND
+#undef ROUND1
+
+#endif /* CPU==i686 */
diff --git a/arch/i386/lib/checksum.c b/arch/i386/lib/checksum.c
deleted file mode 100644
index 51a9219db..000000000
--- a/arch/i386/lib/checksum.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * IP/TCP/UDP checksumming routines
- *
- * Authors: Jorge Cwik, <jorge@laser.satlink.net>
- * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- * Tom May, <ftom@netcom.com>
- * Pentium Pro/II routines:
- * Alexander Kjeldaas <astor@guardian.no>
- * Finn Arne Gangstad <finnag@guardian.no>
- * Lots of code moved from tcp.c and ip.c; see those files
- * for more names.
- *
- * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
- * handling.
- * Andi Kleen, add zeroing on error, fix constraints.
- *
- * To fix:
- * Convert to pure asm, because this file is too hard
- * for gcc's register allocator and it is not clear if the
- * contraints are correct.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <net/checksum.h>
-
-/*
- * computes a partial checksum, e.g. for TCP/UDP fragments
- */
-
-#if CPU!=686
-
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
- /*
- * Experiments with Ethernet and SLIP connections show that buff
- * is aligned on either a 2-byte or 4-byte boundary. We get at
- * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
- * Fortunately, it is easy to convert 2-byte alignment to 4-byte
- * alignment for the unrolled loop.
- */
- __asm__("
- testl $2, %%esi # Check alignment.
- jz 2f # Jump if alignment is ok.
- subl $2, %%ecx # Alignment uses up two bytes.
- jae 1f # Jump if we had at least two bytes.
- addl $2, %%ecx # ecx was < 2. Deal with it.
- jmp 4f
-1: movw (%%esi), %%bx
- addl $2, %%esi
- addw %%bx, %%ax
- adcl $0, %%eax
-2:
- movl %%ecx, %%edx
- shrl $5, %%ecx
- jz 2f
- testl %%esi, %%esi
-1: movl (%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 4(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 8(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 12(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 16(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 20(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 24(%%esi), %%ebx
- adcl %%ebx, %%eax
- movl 28(%%esi), %%ebx
- adcl %%ebx, %%eax
- lea 32(%%esi), %%esi
- dec %%ecx
- jne 1b
- adcl $0, %%eax
-2: movl %%edx, %%ecx
- andl $0x1c, %%edx
- je 4f
- shrl $2, %%edx # This clears CF
-3: adcl (%%esi), %%eax
- lea 4(%%esi), %%esi
- dec %%edx
- jne 3b
- adcl $0, %%eax
-4: andl $3, %%ecx
- jz 7f
- cmpl $2, %%ecx
- jb 5f
- movw (%%esi),%%cx
- leal 2(%%esi),%%esi
- je 6f
- shll $16,%%ecx
-5: movb (%%esi),%%cl
-6: addl %%ecx,%%eax
- adcl $0, %%eax
-7: "
- : "=a"(sum)
- : "0"(sum), "c"(len), "S"(buff)
- : "bx", "dx", "si", "cx", "memory");
- return(sum);
-}
-
-#else /* 686 */
-
-unsigned int csum_partial(const unsigned char * buf, int len, unsigned int sum) {
- __asm__ ("
- testl $2, %%esi
- jnz 30f
-10:
- movl %%ecx, %%edx
- movl %%ecx, %%ebx
- andl $0x7c, %%ebx
- shrl $7, %%ecx
- addl %%ebx,%%esi
- shrl $2, %%ebx
- negl %%ebx
- lea 45f(%%ebx,%%ebx,2), %%ebx
- testl %%esi, %%esi
- jmp *%%ebx
-
- # Handle 2-byte-aligned regions
-20: addw (%%esi), %%ax
- lea 2(%%esi), %%esi
- adcl $0, %%eax
- jmp 10b
-
-30: subl $2, %%ecx
- ja 20b
- je 32f
- movzbl (%%esi),%%ebx # csumming 1 byte, 2-aligned
- addl %%ebx, %%eax
- adcl $0, %%eax
- jmp 80f
-32:
- addw (%%esi), %%ax # csumming 2 bytes, 2-aligned
- adcl $0, %%eax
- jmp 80f
-
-40:
- addl -128(%%esi), %%eax
- adcl -124(%%esi), %%eax
- adcl -120(%%esi), %%eax
- adcl -116(%%esi), %%eax
- adcl -112(%%esi), %%eax
- adcl -108(%%esi), %%eax
- adcl -104(%%esi), %%eax
- adcl -100(%%esi), %%eax
- adcl -96(%%esi), %%eax
- adcl -92(%%esi), %%eax
- adcl -88(%%esi), %%eax
- adcl -84(%%esi), %%eax
- adcl -80(%%esi), %%eax
- adcl -76(%%esi), %%eax
- adcl -72(%%esi), %%eax
- adcl -68(%%esi), %%eax
- adcl -64(%%esi), %%eax
- adcl -60(%%esi), %%eax
- adcl -56(%%esi), %%eax
- adcl -52(%%esi), %%eax
- adcl -48(%%esi), %%eax
- adcl -44(%%esi), %%eax
- adcl -40(%%esi), %%eax
- adcl -36(%%esi), %%eax
- adcl -32(%%esi), %%eax
- adcl -28(%%esi), %%eax
- adcl -24(%%esi), %%eax
- adcl -20(%%esi), %%eax
- adcl -16(%%esi), %%eax
- adcl -12(%%esi), %%eax
- adcl -8(%%esi), %%eax
- adcl -4(%%esi), %%eax
-45:
- lea 128(%%esi), %%esi
- adcl $0, %%eax
- dec %%ecx
- jge 40b
- movl %%edx, %%ecx
-50: andl $3, %%ecx
- jz 80f
-
- # Handle the last 1-3 bytes without jumping
- notl %%ecx # 1->2, 2->1, 3->0, higher bits are masked
- movl $0xffffff,%%ebx # by the shll and shrl instructions
- shll $3,%%ecx
- shrl %%cl,%%ebx
- andl -128(%%esi),%%ebx # esi is 4-aligned so should be ok
- addl %%ebx,%%eax
- adcl $0,%%eax
-80: "
- : "=a"(sum)
- : "0"(sum), "c"(len), "S"(buf)
- : "bx", "dx", "cx", "si", "memory");
- return(sum);
-}
-
-#endif
-
-/*
- * Copy from ds while checksumming, otherwise like csum_partial
- *
- * The macros SRC and DST specify the type of access for the instruction.
- * thus we can call a custom exception handler for all access types.
- *
- * FIXME: could someone double-check whether I haven't mixed up some SRC and
- * DST definitions? It's damn hard to trigger all cases. I hope I got
- * them all but there's no guarantee.
- */
-
-#define SRC(y...) \
-" 9999: "#y"; \n \
- .section __ex_table, \"a\"; \n \
- .long 9999b, 6001f \n \
- .previous\n"
-
-#define DST(y...) \
-" 9999: "#y"; \n \
- .section __ex_table, \"a\"; \n \
- .long 9999b, 6002f \n \
- .previous\n"
-
-#if CPU!=686
-
-unsigned int csum_partial_copy_generic (const char *src, char *dst,
- int len, int sum, int *src_err_ptr, int *dst_err_ptr)
-{
- __u32 tmp_var;
-
- __asm__ __volatile__ ( "
- movl %6,%%edi
- testl $2, %%edi # Check alignment.
- jz 2f # Jump if alignment is ok.
- subl $2, %%ecx # Alignment uses up two bytes.
- jae 1f # Jump if we had at least two bytes.
- addl $2, %%ecx # ecx was < 2. Deal with it.
- jmp 4f
-"SRC( 1: movw (%%esi), %%bx )"
- addl $2, %%esi
-"DST( movw %%bx, (%%edi) )"
- addl $2, %%edi
- addw %%bx, %%ax
- adcl $0, %%eax
- 2:
- movl %%ecx, %8
- shrl $5, %%ecx
- jz 2f
- testl %%esi, %%esi
-"SRC( 1: movl (%%esi), %%ebx )"
-"SRC( movl 4(%%esi), %%edx )"
- adcl %%ebx, %%eax
-"DST( movl %%ebx, (%%edi) )"
- adcl %%edx, %%eax
-"DST( movl %%edx, 4(%%edi) )"
-
-"SRC( movl 8(%%esi), %%ebx )"
-"SRC( movl 12(%%esi), %%edx )"
- adcl %%ebx, %%eax
-"DST( movl %%ebx, 8(%%edi) )"
- adcl %%edx, %%eax
-"DST( movl %%edx, 12(%%edi) )"
-
-"SRC( movl 16(%%esi), %%ebx )"
-"SRC( movl 20(%%esi), %%edx )"
- adcl %%ebx, %%eax
-"DST( movl %%ebx, 16(%%edi) )"
- adcl %%edx, %%eax
-"DST( movl %%edx, 20(%%edi) )"
-
-"SRC( movl 24(%%esi), %%ebx )"
-"SRC( movl 28(%%esi), %%edx )"
- adcl %%ebx, %%eax
-"DST( movl %%ebx, 24(%%edi) )"
- adcl %%edx, %%eax
-"DST( movl %%edx, 28(%%edi) )"
-
-"SRC( lea 32(%%esi), %%esi )"
-"DST( lea 32(%%edi), %%edi )"
- dec %%ecx
- jne 1b
- adcl $0, %%eax
- 2: movl %8, %%edx
- movl %%edx, %%ecx
- andl $0x1c, %%edx
- je 4f
- shrl $2, %%edx # This clears CF
-"SRC( 3: movl (%%esi), %%ebx )"
- adcl %%ebx, %%eax
-"DST( movl %%ebx, (%%edi) )"
-"SRC( lea 4(%%esi), %%esi )"
-"DST( lea 4(%%edi), %%edi )"
- dec %%edx
- jne 3b
- adcl $0, %%eax
- 4: andl $3, %%ecx
- jz 7f
- cmpl $2, %%ecx
- jb 5f
-"SRC( movw (%%esi), %%cx )"
-"SRC( leal 2(%%esi), %%esi )"
-"DST( movw %%cx, (%%edi) )"
-"DST( leal 2(%%edi), %%edi )"
- je 6f
- shll $16,%%ecx
-"SRC( 5: movb (%%esi), %%cl )"
-"DST( movb %%cl, (%%edi) )"
- 6: addl %%ecx, %%eax
- adcl $0, %%eax
- 7:
-
-5000:
-
-# Exception handler:
-################################################
- #
-.section .fixup, \"ax\" #
- #
-6000: #
- #
- movl %7, (%%ebx) #
- #
-# zero the complete destination - computing the rest
-# is too much work
- movl %6, %%edi
- movl %9, %%ecx
- xorl %%eax,%%eax
- rep ; stosb
- #
- jmp 5000b #
- #
-6001: #
- movl %1, %%ebx #
- jmp 6000b #
- #
-6002: #
- movl %2, %%ebx #
- jmp 6000b #
- #
-.previous #
- #
-################################################
-
-"
- : "=a" (sum)
- : "m" (src_err_ptr), "m" (dst_err_ptr),
- "0" (sum), "c" (len), "S" (src), "m" (dst),
- "i" (-EFAULT), "m"(tmp_var),
- "m" (len)
- : "bx", "dx", "si", "di", "cx", "memory" );
-
- return(sum);
-}
-
-#else /* CPU == 686 */
-
-#define ROUND1(x) \
- SRC(movl x(%%esi), %%ebx ) \
- "addl %%ebx, %%eax\n" \
- DST(movl %%ebx, x(%%edi) )
-
-#define ROUND(x) \
- SRC(movl x(%%esi), %%ebx ) \
- "adcl %%ebx, %%eax\n" \
- DST(movl %%ebx, x(%%edi) )
-
-unsigned int csum_partial_copy_generic (const char *src, char *dst,
- int len, int sum, int *src_err_ptr, int *dst_err_ptr)
-{
- __asm__ __volatile__ ("
- movl %4,%%ecx
- movl %%ecx, %%edx
- movl %%ecx, %%ebx
- shrl $6, %%ecx
- andl $0x3c, %%ebx
- negl %%ebx
- subl %%ebx, %%esi
- subl %%ebx, %%edi
- lea 3f(%%ebx,%%ebx), %%ebx
- testl %%esi, %%esi
- jmp *%%ebx
-1: addl $64,%%esi
- addl $64,%%edi\n"
-ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
-ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
-ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
-ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
-"3: adcl $0,%%eax
- dec %%ecx
- jge 1b
-4: andl $3, %%edx
- jz 7f
- cmpl $2, %%edx
- jb 5f
- " SRC(movw (%%esi), %%dx )"
- leal 2(%%esi), %%esi
- " DST(movw %%dx, (%%edi) )"
- leal 2(%%edi), %%edi
- je 6f
- shll $16,%%edx
-5:" SRC(movb (%%esi), %%dl )"
- " DST(movb %%dl, (%%edi) )"
-6: addl %%edx, %%eax
- adcl $0, %%eax
-7:
-.section .fixup, \"ax\"
-6000: movl %7, (%%ebx)
-# zero the complete destination (computing the rest is too much work)
- movl %8,%%edi
- movl %4,%%ecx
- xorl %%eax,%%eax
- rep ; stosb
- jmp 7b
-6001: movl %1, %%ebx
- jmp 6000b
-6002: movl %2, %%ebx
- jmp 6000b
-.previous
- "
- : "=a"(sum)
- : "m"(src_err_ptr), "m"(dst_err_ptr),
- "0"(sum), "m"(len), "S"(src), "D" (dst),
- "i" (-EFAULT),
- "m" (dst)
- : "bx", "cx", "si", "di", "dx", "memory" );
- return(sum);
-}
-
-#undef ROUND
-#undef ROUND1
-
-#endif
-
-
-#undef SRC
-#undef DST
-
-/*
- * FIXME: old compatibility stuff, will be removed soon.
- */
-
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
-{
- int src_err=0, dst_err=0;
-
- sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
-
- if (src_err || dst_err)
- printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
-
- return sum;
-}
-
-
diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c
index ae8aec636..6918451a6 100644
--- a/arch/i386/lib/delay.c
+++ b/arch/i386/lib/delay.c
@@ -19,23 +19,23 @@
void __delay(unsigned long loops)
{
+ int d0;
__asm__ __volatile__(
"\tjmp 1f\n"
".align 16\n"
"1:\tjmp 2f\n"
".align 16\n"
"2:\tdecl %0\n\tjns 2b"
- :/* no outputs */
- :"a" (loops)
- :"ax");
+ :"=&a" (d0)
+ :"0" (loops));
}
inline void __const_udelay(unsigned long xloops)
{
+ int d0;
__asm__("mull %0"
- :"=d" (xloops)
- :"a" (xloops),"0" (current_cpu_data.loops_per_sec)
- :"ax");
+ :"=d" (xloops), "=&a" (d0)
+ :"1" (xloops),"0" (current_cpu_data.loops_per_sec));
__delay(xloops);
}
diff --git a/arch/i386/lib/old-checksum.c b/arch/i386/lib/old-checksum.c
new file mode 100644
index 000000000..ae3a38043
--- /dev/null
+++ b/arch/i386/lib/old-checksum.c
@@ -0,0 +1,19 @@
+/*
+ * FIXME: old compatibility stuff, will be removed soon.
+ */
+
+#include <net/checksum.h>
+
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
+{
+ int src_err=0, dst_err=0;
+
+ sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
+
+ if (src_err || dst_err)
+ printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
+
+ return sum;
+}
+
+
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index d5b052c20..f43be511f 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -29,6 +29,8 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
*/
#define __do_strncpy_from_user(dst,src,count,res) \
+do { \
+ int __d0, __d1, __d2; \
__asm__ __volatile__( \
" testl %1,%1\n" \
" jz 2f\n" \
@@ -41,16 +43,18 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
"1: subl %1,%0\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
- "3: movl %2,%0\n" \
+ "3: movl %5,%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 0b,3b\n" \
".previous" \
- : "=d"(res), "=c"(count) \
- : "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \
- : "si", "di", "ax", "memory")
+ : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
+ "=&D" (__d2) \
+ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
+ : "memory"); \
+} while (0)
long
__strncpy_from_user(char *dst, const char *src, long count)
@@ -74,14 +78,16 @@ strncpy_from_user(char *dst, const char *src, long count)
* Zero Userspace
*/
-#define __do_clear_user(addr,size) \
- __asm__ __volatile__( \
+#define __do_clear_user(addr,size) \
+do { \
+ int __d0; \
+ __asm__ __volatile__( \
"0: rep; stosl\n" \
- " movl %1,%0\n" \
+ " movl %2,%0\n" \
"1: rep; stosb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
- "3: lea 0(%1,%0,4),%0\n" \
+ "3: lea 0(%2,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
@@ -89,9 +95,9 @@ strncpy_from_user(char *dst, const char *src, long count)
" .long 0b,3b\n" \
" .long 1b,2b\n" \
".previous" \
- : "=&c"(size) \
- : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \
- : "di")
+ : "=&c"(size), "=&D" (__d0) \
+ : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
+} while (0)
unsigned long
clear_user(void *to, unsigned long n)
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 693072b1a..dc96ad4bb 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -119,24 +119,28 @@ int do_check_pgt_cache(int low, int high)
pte_t * __bad_pagetable(void)
{
extern char empty_bad_page_table[PAGE_SIZE];
-
- __asm__ __volatile__("cld ; rep ; stosl":
- :"a" (pte_val(BAD_PAGE)),
- "D" ((long) empty_bad_page_table),
- "c" (PAGE_SIZE/4)
- :"di","cx");
+ int d0, d1;
+
+ __asm__ __volatile__("cld ; rep ; stosl"
+ : "=&D" (d0), "=&c" (d1)
+ : "a" (pte_val(BAD_PAGE)),
+ "0" ((long) empty_bad_page_table),
+ "1" (PAGE_SIZE/4)
+ : "memory");
return (pte_t *) empty_bad_page_table;
}
pte_t __bad_page(void)
{
extern char empty_bad_page[PAGE_SIZE];
-
- __asm__ __volatile__("cld ; rep ; stosl":
- :"a" (0),
- "D" ((long) empty_bad_page),
- "c" (PAGE_SIZE/4)
- :"di","cx");
+ int d0, d1;
+
+ __asm__ __volatile__("cld ; rep ; stosl"
+ : "=&D" (d0), "=&c" (d1)
+ : "a" (0),
+ "0" ((long) empty_bad_page),
+ "1" (PAGE_SIZE/4)
+ : "memory");
return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
}
@@ -275,38 +279,6 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
* kernel.
* It may also hold the MP configuration table when we are booting SMP.
*/
-#ifdef __SMP__
- /*
- * FIXME: Linux assumes you have 640K of base ram..
- * this continues the error...
- *
- * 1) Scan the bottom 1K for a signature
- * 2) Scan the top 1K of base RAM
- * 3) Scan the 64K of bios
- */
- if (!smp_scan_config(0x0,0x400) &&
- !smp_scan_config(639*0x400,0x400) &&
- !smp_scan_config(0xF0000,0x10000)) {
- /*
- * If it is an SMP machine we should know now, unless the
- * configuration is in an EISA/MCA bus machine with an
- * extended bios data area.
- *
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E, calculate and scan it here.
- *
- * NOTE! There are Linux loaders that will corrupt the EBDA
- * area, and as such this kind of SMP config may be less
- * trustworthy, simply because the SMP table may have been
- * stomped on during early boot.
- */
- address = *(unsigned short *)phys_to_virt(0x40E);
- address<<=4;
- smp_scan_config(address, 0x1000);
- if (smp_found_config)
- printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n");
- }
-#endif
start_mem = PAGE_ALIGN(start_mem);
address = PAGE_OFFSET;
pg_dir = swapper_pg_dir;
@@ -403,7 +375,7 @@ __initfunc(void test_wp_bit(void))
if (boot_cpu_data.wp_works_ok < 0) {
boot_cpu_data.wp_works_ok = 0;
printk("No.\n");
-#ifndef CONFIG_M386
+#ifdef CONFIG_X86_WP_WORKS_OK
panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
#endif
} else
diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds
index c23007bc8..203b9a927 100644
--- a/arch/i386/vmlinux.lds
+++ b/arch/i386/vmlinux.lds
@@ -45,9 +45,13 @@ SECTIONS
. = ALIGN(4096);
__init_end = .;
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
+
__bss_start = .; /* BSS */
.bss : {
*(.bss)
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 9cd2d1838..cb60ea268 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -29,14 +29,21 @@ LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
-ifdef CONFIG_OPTIMIZE_040
+# enable processor switch if compiled only for a single cpu
+ifndef CONFIG_M68020
+ifndef CONFIG_M68030
+
+ifndef CONFIG_M68060
CFLAGS := $(CFLAGS) -m68040
endif
-ifdef CONFIG_OPTIMIZE_060
+ifndef CONFIG_M68040
CFLAGS := $(CFLAGS) -m68060
endif
+endif
+endif
+
ifdef CONFIG_KGDB
# If configured for kgdb support, include debugging infos and keep the
# frame pointer
@@ -116,6 +123,7 @@ endif
archclean:
rm -f vmlinux.gz
+ rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d
archmrproper:
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index 25955213e..4fb886456 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -15,7 +15,7 @@
* - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
* they're executed irq level is set to the previous
* one, but handlers don't need to be reentrant, if
- * reentrance occured, slow handlers will be just
+ * reentrance occurred, slow handlers will be just
* called again.
* The whole interrupt handling for CIAs is moved to cia.c
* /Roman Zippel
@@ -367,7 +367,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
for (;;) {
for (; node; node = node->next)
node->handler(irq, node->dev_id, fp);
- /* if reentrance occured, serve slow handlers again */
+ /* if reentrance occurred, serve slow handlers again */
custom.intena = ami_intena_vals[irq];
if (!server->reentrance) {
server->count--;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 63cb5265c..37b5bde3c 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -52,7 +52,6 @@ static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *));
/* amiga specific keyboard functions */
extern int amiga_keyb_init(void);
extern int amiga_kbdrate (struct kbd_repeat *);
-extern void amiga_kbd_reset_setup(char*, int);
/* amiga specific irq functions */
extern void amiga_init_IRQ (void);
extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
@@ -343,7 +342,6 @@ __initfunc(void config_amiga(void))
mach_sched_init = amiga_sched_init;
mach_keyb_init = amiga_keyb_init;
mach_kbdrate = amiga_kbdrate;
- kbd_reset_setup = amiga_kbd_reset_setup;
mach_init_IRQ = amiga_init_IRQ;
mach_default_handler = &amiga_default_handler;
mach_request_irq = amiga_request_irq;
diff --git a/arch/m68k/amiga/pcmcia.c b/arch/m68k/amiga/pcmcia.c
index 3faac7eda..e1b29387a 100644
--- a/arch/m68k/amiga/pcmcia.c
+++ b/arch/m68k/amiga/pcmcia.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/timer.h>
#include <asm/amigayle.h>
#include <asm/amipcmcia.h>
@@ -26,7 +27,7 @@ void pcmcia_reset(void)
unsigned char b;
gayle_reset = 0x00;
- while (jiffies - reset_start_time < 1*HZ/100);
+ while (time_before(jiffies, reset_start_time + 1*HZ/100));
b = gayle_reset;
}
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index c4cffcdf9..18e29814e 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -30,7 +30,7 @@ void dn_process_int(int irq, struct pt_regs *fp) {
dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
}
else {
- printk("spurious irq %d occured\n",irq);
+ printk("spurious irq %d occurred\n",irq);
}
#if 0
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index e6535f6ff..79ef5f9fd 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -825,7 +825,7 @@ __initfunc(int atari_keyb_init(void))
/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
* self-test is finished */
self_test_last_rcv = jiffies;
- while( jiffies < self_test_last_rcv + HZ/4 )
+ while (time_before(jiffies, self_test_last_rcv + HZ/4))
barrier();
/* if not incremented: no 0xf1 received */
if (ikbd_self_test == 1)
@@ -861,8 +861,3 @@ int atari_kbdrate( struct kbd_repeat *k )
return( 0 );
}
-
-/* for "kbd-reset" cmdline param */
-__initfunc(void atari_kbd_reset_setup(char *str, int *ints))
-{
-}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 8db027ab4..5be79acaf 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -60,7 +60,6 @@ static int atari_get_hardware_list(char *buffer);
extern int atari_keyb_init(void);
extern int atari_kbdrate (struct kbd_repeat *);
extern void atari_kbd_leds (unsigned int);
-extern void atari_kbd_reset_setup(char*, int);
/* atari specific irq functions */
extern void atari_init_IRQ (void);
extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -251,7 +250,6 @@ __initfunc(void config_atari(void))
mach_keyb_init = atari_keyb_init;
mach_kbdrate = atari_kbdrate;
mach_kbd_leds = atari_kbd_leds;
- kbd_reset_setup = atari_kbd_reset_setup;
mach_init_IRQ = atari_init_IRQ;
mach_request_irq = atari_request_irq;
mach_free_irq = atari_free_irq;
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
index a79f5555d..04633375f 100644
--- a/arch/m68k/bvme6000/bvmeints.c
+++ b/arch/m68k/bvme6000/bvmeints.c
@@ -119,9 +119,12 @@ void bvme6000_free_irq(unsigned int irq, void *dev_id)
void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
{
if (vec > 255)
- panic ("bvme6000_process_int: Illegal vector %ld", vec);
- irq_tab[vec].count++;
- irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+ printk ("bvme6000_process_int: Illegal vector %ld", vec);
+ else
+ {
+ irq_tab[vec].count++;
+ irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+ }
}
int bvme6000_get_irq_list (char *buf)
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 74d15e995..543b04c74 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -91,8 +91,7 @@ void bvme6000_reset()
static void bvme6000_get_model(char *model)
{
- /* XXX Need to detect if BVME4000 or BVME6000 */
- sprintf(model, "BVME6000");
+ sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4);
}
@@ -152,13 +151,17 @@ __initfunc(void config_bvme6000(void))
pit->pbddr = 0xf3; /* Mostly outputs */
pit->pcdr = 0x01; /* PA transceiver disabled */
pit->pcddr = 0x03; /* WDOG disable */
+
+ /* Disable snooping for Ethernet and VME accesses */
+
+ bvme_acr_addrctl = 0;
}
void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
{
unsigned long *new = (unsigned long *)vectors;
- unsigned long *old = (unsigned long *)0xf8000000;;
+ unsigned long *old = (unsigned long *)0xf8000000;
/* Wait for button release */
while (*config_reg_ptr & BVME_ABORT_STATUS)
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index 8fe84aecd..a67227d60 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -44,6 +44,7 @@ bool 'HP9000/300 support' CONFIG_HP300
if [ "$CONFIG_HP300" = "y" ]; then
bool 'DIO bus support' CONFIG_DIO
fi
+define_bool CONFIG_SUN3 n
if [ "$CONFIG_PCI" = "y" ]; then
bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
fi
@@ -53,22 +54,11 @@ bool '68020 support' CONFIG_M68020
bool '68030 support' CONFIG_M68030
bool '68040 support' CONFIG_M68040
bool '68060 support' CONFIG_M68060
-if [ "$CONFIG_M68020" = "n" -a "$CONFIG_M68030" = "n" ]; then
- if [ "$CONFIG_M68040" = "y" -a "$CONFIG_M68060" = "n" ]; then
- bool 'Use 68040 specific optimizations' CONFIG_OPTIMIZE_040
- fi
- if [ "$CONFIG_M68040" = "n" -a "$CONFIG_M68060" = "y" ]; then
- bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060
- fi
-fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_M68060" = "y" ]; then
- define_bool CONFIG_060_WRITETHROUGH y
-fi
bool 'Advanced configuration options' CONFIG_ADVANCED
if [ "$CONFIG_ADVANCED" = "y" ]; then
bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK
- if [ "$CONFIG_M68060" = "y" -a "$CONFIG_VME" = "n" ]; then
+ if [ "$CONFIG_M68060" = "y" ]; then
bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
fi
fi
@@ -140,19 +130,19 @@ mainmenu_option next_comment
comment 'SCSI low-level drivers'
if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI
+ dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
fi
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI
- tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI
- bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI
- bool 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI
- bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI
- bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI
- bool 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI
+ dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+ dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+ dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'A4091 SCSI support' CONFIG_A4091_SCSI
bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
@@ -173,7 +163,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI
- bool 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP
+ dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
fi
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
@@ -226,14 +216,14 @@ if [ "$CONFIG_APOLLO" = "y" ] ; then
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
- bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE
- bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC
+# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
+ bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
- bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET
+ tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
- bool 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
+ tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
fi
if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari Lance support' CONFIG_ATARILANCE
@@ -367,8 +357,6 @@ if [ "$CONFIG_VME" = "n" ]; then
endmenu
fi
-source fs/nls/Config.in
-
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index 5a9f39e52..ab9152f5d 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -28,8 +28,6 @@ CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
# CONFIG_M68060 is not set
-# CONFIG_OPTIMIZE_040 is not set
-# CONFIG_OPTIMIZE_060 is not set
# CONFIG_ADVANCED is not set
# CONFIG_SINGLE_MEMORY_CHUNK is not set
# CONFIG_RMW_INSNS is not set
@@ -77,21 +75,26 @@ CONFIG_BLK_DEV_INITRD=y
#
# Networking options
#
+CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
#
# (it is safe to leave these untouched)
#
-# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
-CONFIG_PATH_MTU_DISCOVERY=y
CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
@@ -101,8 +104,20 @@ CONFIG_IP_NOSR=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
#
# SCSI support
@@ -115,12 +130,15 @@ CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
# CONFIG_CHR_DEV_SG is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
#
# SCSI low-level drivers
@@ -149,6 +167,7 @@ CONFIG_NETDEVICES=y
# CONFIG_SLIP is not set
# CONFIG_PPP is not set
# CONFIG_ARIADNE is not set
+# CONFIG_ARIADNE2 is not set
# CONFIG_A2065 is not set
# CONFIG_HYDRA is not set
# CONFIG_APNE is not set
@@ -186,7 +205,10 @@ CONFIG_FB_AMIGA_OCS=y
CONFIG_FB_AMIGA_ECS=y
CONFIG_FB_AMIGA_AGA=y
# CONFIG_FB_CYBER is not set
+# CONFIG_FB_VIRGE is not set
+# CONFIG_FB_CVPPC is not set
# CONFIG_FB_RETINAZ3 is not set
+# CONFIG_FB_CLGEN is not set
# CONFIG_FB_ATARI is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 1e4d0cf72..06d22b7b7 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -40,6 +40,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
+#include "../kernel/m68k_defs.h"
|SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package
@@ -375,12 +376,12 @@ fpsp_fmt_error:
.global fpsp_done
fpsp_done:
btst #0x5,%sp@ | supervisor bit set in saved SR?
- beq Lnotkern
+ beq .Lnotkern
rte
-Lnotkern:
+.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(ret_from_exception) | deliver signals,
| reschedule etc..
RESTORE_ALL
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index 97fb6e480..6808de799 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -55,11 +55,6 @@ static void hp300_kbd_leds(unsigned int leds)
{
}
-/* for "kbd-reset" cmdline param */
-__initfunc(void hp300_kbd_reset_setup(char *str, int i))
-{
-}
-
static void hp300_get_model(char *model)
{
strcpy(model, "HP9000/300");
@@ -74,7 +69,6 @@ __initfunc(void config_hp300(void))
mach_init_IRQ = hp300_init_IRQ;
mach_request_irq = hp300_request_irq;
mach_free_irq = hp300_free_irq;
- kbd_reset_setup = hp300_kbd_reset_setup;
mach_get_model = hp300_get_model;
mach_get_irq_list = hp300_get_irq_list;
mach_gettimeoffset = hp300_gettimeoffset;
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index cde14e120..859ba3dd3 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -36,6 +36,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
+#include "../kernel/m68k_defs.h"
|################################
@@ -69,12 +70,12 @@
.global _060_isp_done
_060_isp_done:
btst #0x5,%sp@ | supervisor bit set in saved SR?
- beq Lnotkern
+ beq .Lnotkern
rte
-Lnotkern:
+.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(ret_from_exception) | deliver signals,
| reschedule etc..
RESTORE_ALL
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 977120c1e..280a5b450 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -26,10 +26,13 @@ endif
head.o: head.S m68k_defs.h
-m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h
- $(CC) ${CFLAGS} -S m68k_defs.c
+m68k_defs.h: m68k_defs.c m68k_defs.head
+ rm -f m68k_defs.d
+ SUNPRO_DEPENDENCIES="m68k_defs.d m68k_defs.h" \
+ $(CC) $(filter-out -MD,$(CFLAGS)) -S m68k_defs.c
cp m68k_defs.head m68k_defs.h
- sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p'
+ grep '^#define' m68k_defs.s >> m68k_defs.h
rm m68k_defs.s
+-include m68k_defs.d
include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index b3e15387c..e21e4b21c 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -34,8 +34,10 @@
#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/entry.h>
+#include <asm/errno.h>
#include <asm/setup.h>
#include <asm/segment.h>
+#include <asm/traps.h>
#include "m68k_defs.h"
@@ -43,7 +45,7 @@
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
.globl SYMBOL_NAME(ret_from_signal)
.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
-.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone)
+.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork)
.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt)
.text
@@ -65,24 +67,24 @@ ENTRY(trap)
ENTRY(reschedule)
| save top of frame
- movel %sp,%curptr@(TS_ESP0)
+ movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
pea SYMBOL_NAME(ret_from_exception)
jmp SYMBOL_NAME(schedule)
badsys:
- movel #-LENOSYS,LPT_OFF_D0(%sp)
+ movel #-ENOSYS,PT_D0(%sp)
jra SYMBOL_NAME(ret_from_exception)
do_trace:
- movel #-LENOSYS,LPT_OFF_D0(%sp) | needed for strace
+ movel #-ENOSYS,PT_D0(%sp) | needed for strace
subql #4,%sp
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
RESTORE_SWITCH_STACK
addql #4,%sp
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LPT_OFF_D0) | save the return value
+ movel %d0,%sp@(PT_D0) | save the return value
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
@@ -98,34 +100,34 @@ ENTRY(system_call)
GET_CURRENT(%d0)
| save top of frame
- movel %sp,%curptr@(TS_ESP0)
+ movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
cmpl #NR_syscalls,%d2
jcc badsys
- btst #LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF)
+ btst #PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF)
jne do_trace
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LPT_OFF_D0) | save the return value
+ movel %d0,%sp@(PT_D0) | save the return value
SYMBOL_NAME_LABEL(ret_from_exception)
- btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel
+ btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 2f | if so, skip resched, signals
| only allow interrupts when we are really the last one on the
| kernel stack, otherwise stack overflow can occur during
| heavy interupt load
andw #ALLOWINT,%sr
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(reschedule)
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
| check for delayed trace
- bclr #LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF)
+ bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
jne do_delayed_trace
5:
- tstl %curptr@(LTASK_STATE) | state
+ tstl %curptr@(TASK_STATE) | state
jne SYMBOL_NAME(reschedule)
- tstl %curptr@(LTASK_SIGPENDING)
+ tstl %curptr@(TASK_SIGPENDING)
jne Lsignal_return
2: RESTORE_ALL
@@ -141,7 +143,7 @@ Lsignal_return:
RESTORE_ALL
do_delayed_trace:
- bclr #7,%sp@(LPT_OFF_SR) | clear trace bit in SR
+ bclr #7,%sp@(PT_SR) | clear trace bit in SR
pea 1 | send SIGTRAP
movel %curptr,%sp@-
pea LSIGTRAP
@@ -158,7 +160,7 @@ SYMBOL_NAME_LABEL(inthandler)
GET_CURRENT(%d0)
addql #1,SYMBOL_NAME(local_irq_count)
| put exception # in d0
- bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0
+ bfextu %sp@(PT_VECTOR){#4,#10},%d0
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
@@ -172,7 +174,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
RESTORE_ALL
1:
#if 1
- bfextu %sp@(LPT_OFF_SR){#5,#3},%d0 | Check for nested interrupt.
+ bfextu %sp@(PT_SR){#5,#3},%d0 | Check for nested interrupt.
#if MAX_NOINT_IPL > 0
cmpiw #MAX_NOINT_IPL,%d0
#endif
@@ -210,6 +212,14 @@ ENTRY(sys_clone)
RESTORE_SWITCH_STACK
rts
+ENTRY(sys_vfork)
+ SAVE_SWITCH_STACK
+ pea %sp@(SWITCH_STACK_SIZE)
+ jbsr SYMBOL_NAME(m68k_vfork)
+ addql #4,%sp
+ RESTORE_SWITCH_STACK
+ rts
+
ENTRY(sys_sigsuspend)
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
@@ -240,37 +250,31 @@ ENTRY(sys_rt_sigreturn)
SYMBOL_NAME_LABEL(resume)
/*
- * Beware - when entering resume, offset of tss is in d1,
- * prev (the current task) is in a0, next (the new task)
- * is in a1 and d2.b is non-zero if the mm structure is
- * shared between the tasks, so don't change these
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1,so don't change these
* registers until their contents are no longer needed.
*/
- /* offset of tss struct (processor state) from beginning
- of task struct */
- addl %d1,%a0
-
/* save sr */
- movew %sr,%a0@(LTSS_SR)
+ movew %sr,%a0@(TASK_TSS+TSS_SR)
/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
movec %sfc,%d0
- movew %d0,%a0@(LTSS_FS)
+ movew %d0,%a0@(TASK_TSS+TSS_FS)
/* save usp */
/* it is better to use a movel here instead of a movew 8*) */
movec %usp,%d0
- movel %d0,%a0@(LTSS_USP)
+ movel %d0,%a0@(TASK_TSS+TSS_USP)
/* save non-scratch registers on stack */
SAVE_SWITCH_STACK
/* save current kernel stack pointer */
- movel %sp,%a0@(LTSS_KSP)
+ movel %sp,%a0@(TASK_TSS+TSS_KSP)
/* save floating point context */
- fsave %a0@(LTSS_FPCTXT+27*4)
+ fsave %a0@(TASK_TSS+TSS_FPSTATE)
#if defined(CONFIG_M68060)
#if !defined(CPU_M68060_ONLY)
@@ -278,27 +282,27 @@ SYMBOL_NAME_LABEL(resume)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a0@(LTSS_FPCTXT+27*4+2)
+ tstb %a0@(TASK_TSS+TSS_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a0@(LTSS_FPCTXT+27*4)
+1: tstb %a0@(TASK_TSS+TSS_FPSTATE)
jeq 3f
#endif
-2: fmovemx %fp0-%fp7,%a0@(LTSS_FPCTXT)
- fmoveml %fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4)
+2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
+ fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
3:
- /* get pointer to tss struct (a1 contains new task) */
+ /* switch to new task (a1 contains new task) */
movel %a1,%curptr
- addl %d1,%a1
/* Skip address space switching if they are the same. */
- tstb %d2
- jne 4f
+ movel %a0@(TASK_MM),%d0
+ cmpl %a1@(TASK_MM),%d0
+ jeq 4f
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
/* 68040 or 68060 ? */
@@ -316,7 +320,7 @@ SYMBOL_NAME_LABEL(resume)
movec %d0,%cacr
/* switch the root pointer */
- pmove %a1@(LTSS_CRP),%crp
+ pmove %a1@(TASK_TSS+TSS_CRP),%crp
#endif
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
@@ -333,7 +337,7 @@ SYMBOL_NAME_LABEL(resume)
pflushan
/* switch the root pointer */
- movel %a1@(LTSS_CRP+4),%d0
+ movel %a1@(TASK_TSS+TSS_CRP+4),%d0
movec %d0,%urp
#if defined (CONFIG_M68060)
@@ -359,37 +363,37 @@ SYMBOL_NAME_LABEL(resume)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a1@(LTSS_FPCTXT+27*4+2)
+ tstb %a1@(TASK_TSS+TSS_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a1@(LTSS_FPCTXT+27*4)
+1: tstb %a1@(TASK_TSS+TSS_FPSTATE)
jeq 3f
#endif
-2: fmovemx %a1@(LTSS_FPCTXT),%fp0-%fp7
- fmoveml %a1@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar
-3: frestore %a1@(LTSS_FPCTXT+27*4)
+2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7
+ fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar
+3: frestore %a1@(TASK_TSS+TSS_FPSTATE)
/* restore the kernel stack pointer */
- movel %a1@(LTSS_KSP),%sp
+ movel %a1@(TASK_TSS+TSS_KSP),%sp
/* restore non-scratch registers */
RESTORE_SWITCH_STACK
/* restore user stack pointer */
- movel %a1@(LTSS_USP),%a0
+ movel %a1@(TASK_TSS+TSS_USP),%a0
movel %a0,%usp
/* restore fs (sfc,%dfc) */
- movew %a1@(LTSS_FS),%a0
+ movew %a1@(TASK_TSS+TSS_FS),%a0
movec %a0,%sfc
movec %a0,%dfc
/* restore status register */
- movew %a1@(LTSS_SR),%sr
+ movew %a1@(TASK_TSS+TSS_SR),%sr
rts
@@ -586,6 +590,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_vfork) /* 190 */
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index e98f39fa8..482c15f50 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -7,9 +7,12 @@
**
** 68040 fixes by Michael Rausch
** 68060 fixes by Roman Hodek
+** MMU cleanup by Randy Thelen
+** Final MMU cleanup by Roman Zippel
**
** Atari support by Andreas Schwab, using ideas of Robert de Vries
** and Bjoern Brauel
+** VME Support by Richard Hirst
**
** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
@@ -18,6 +21,8 @@
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
** 98/04/25 Phil Blundell: added HP300 support
+** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
+** for linux-2.1.115
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
@@ -34,69 +39,275 @@
* Put us in supervisor state.
*
* The kernel setup code takes the following steps:
- * Raise interrupt level
- * Set up initial kernel memory mapping.
- * This sets up a mapping of the 4M of memory the kernel
- * is located in. It also does a mapping of any initial
- * machine specific areas.
- * Note that the kernel is located at virtual address 0x1000 == _start
- * Enable cache memories
- * Jump to kernel startup
- *
- * Register d6 contains the CPU flags and d4 the machine type
- * from the boot_info information for most of this file.
- * The upper word of d6 contains a bit for '040 or '060, since these two
- * are quite similar for initial mm setup. Another bit in d6 allows
- * distinction of the '060. The lower word of d6 contains the cache mode
- * that should be applied to pages containing descriptors. This mode is
- * non-cached/non-serialized for the '040 and cacheable/write-through for
- * the '060.
- *
- * General register usage:
- * a6 - start of unused memory
- * new pages can be allocated from here
- * a5 - mmu root table
- * a4 - mmu pointer table
- * a3 - mmu page tables
- * a2 - points to the page table entry for a6
- * cache status can be changed (used for '0[46]0)
- * you must increase a2 if alloc a new page
- * d7 - used for debug output and some macros
- * d6 - cpu type and cache mode
- * d5 - physical start address of kernel
- * d4 - machine type
+ * . Raise interrupt level
+ * . Set up initial kernel memory mapping.
+ * . This sets up a mapping of the 4M of memory the kernel is located in.
+ * . It also does a mapping of any initial machine specific areas.
+ * . Enable the MMU
+ * . Enable cache memories
+ * . Jump to kernel startup
+ *
+ * Much of the file restructuring was to accomplish:
+ * 1) Remove register dependency through-out the file.
+ * 2) Increase use of subroutines to perform functions
+ * 3) Increase readability of the code
+ *
+ * Of course, readability is a subjective issue, so it will never be
+ * argued that that goal was accomplished. It was merely a goal.
+ * A key way to help make code more readable is to give good
+ * documentation. So, the first thing you will find is exaustive
+ * write-ups on the structure of the file, and the features of the
+ * functional subroutines.
+ *
+ * General Structure:
+ * ------------------
+ * Without a doubt the single largest chunk of head.S is spent
+ * mapping the kernel and I/O physical space into the logical range
+ * for the kernel.
+ * There are new subroutines and data structures to make MMU
+ * support cleaner and easier to understand.
+ * First, you will find a routine call "mmu_map" which maps
+ * a logical to a physical region for some length given a cache
+ * type on behalf of the caller. This routine makes writing the
+ * actual per-machine specific code very simple.
+ * A central part of the code, but not a subroutine in itself,
+ * is the mmu_init code which is broken down into mapping the kernel
+ * (the same for all machines) and mapping machine-specific I/O
+ * regions.
+ * Also, there will be a description of engaging the MMU and
+ * caches.
+ * You will notice that there is a chunk of code which
+ * can emit the entire MMU mapping of the machine. This is present
+ * only in debug modes and can be very helpful.
+ * Further, there is a new console driver in head.S that is
+ * also only engaged in debug mode. Currently, it's only supported
+ * on the Macintosh class of machines. However, it is hoped that
+ * others will plug-in support for specific machines.
+ *
+ * ######################################################################
+ *
+ * mmu_map
+ * -------
+ * mmu_map was written for two key reasons. First, it was clear
+ * that it was very difficult to read the previous code for mapping
+ * regions of memory. Second, the Macintosh required such extensive
+ * memory allocations that it didn't make sense to propogate the
+ * existing code any further.
+ * mmu_map requires some parameters:
+ *
+ * mmu_map (logical, physical, length, cache_type)
+ *
+ * While this essentially describes the function in the abstract, you'll
+ * find more indepth description of other parameters at the implementation site.
+ *
+ * mmu_get_root_table_entry
+ * ------------------------
+ * mmu_get_ptr_table_entry
+ * -----------------------
+ * mmu_get_page_table_entry
+ * ------------------------
+ *
+ * These routines are used by other mmu routines to get a pointer into
+ * a table, if necessary a new table is allocated. These routines are working
+ * basically like pmd_alloc() and pte_alloc() in <asm/pgtable.h>. The root
+ * table needs of course only to be allocated once in mmu_get_root_table_entry,
+ * so that here also some mmu specific initialization is done. The second page
+ * at the start of the kernel (the first page is unmapped later) is used for
+ * the kernel_pg_dir. It must be at a position known at link time (as it's used
+ * to initialize the init task struct) and since it needs special cache
+ * settings, it's the easiest to use this page, the rest of the page is used
+ * for further pointer tables.
+ * mmu_get_page_table_entry allocates always a whole page for page tables, this
+ * means 1024 pages and so 4MB of memory can be mapped. It doesn't make sense
+ * to manage page tables in smaller pieces as nearly all mappings have that
+ * size.
+ *
+ * ######################################################################
+ *
+ *
+ * ######################################################################
+ *
+ * mmu_engage
+ * ----------
+ * Thanks to a small helping routine enabling the mmu got quiet simple
+ * and there is only one way left. mmu_engage makes a complete a new mapping
+ * that only includes the absolute necessary to be able to jump to the final
+ * postion and to restore the original mapping.
+ * As this code doesn't need a transparent translation register anymore this
+ * means all registers are free to be used by machines that needs them for
+ * other purposes.
+ *
+ * ######################################################################
+ *
+ * mmu_print
+ * ---------
+ * This algorithm will print out the page tables of the system as
+ * appropriate for an 030 or an 040. This is useful for debugging purposes
+ * and as such is enclosed in #ifdef MMU_PRINT/#endif clauses.
+ *
+ * ######################################################################
+ *
+ * console_init
+ * ------------
+ * The console is also able to be turned off. The console in head.S
+ * is specifically for debugging and can be very useful. It is surrounded by
+ * #ifdef CONSOLE/#endif clauses so it doesn't have to ship in known-good
+ * kernels. It's basic algorithm is to determine the size of the screen
+ * (in height/width and bit depth) and then use that information for
+ * displaying an 8x8 font or an 8x16 (widthxheight). I prefer the 8x8 for
+ * debugging so I can see more good data. But it was trivial to add support
+ * for both fonts, so I included it.
+ * Also, the algorithm for plotting pixels is abstracted so that in
+ * theory other platforms could add support for different kinds of frame
+ * buffers. This could be very useful.
+ *
+ * console_put_penguin
+ * -------------------
+ * An important part of any Linux bring up is the penguin and there's
+ * nothing like getting the Penguin on the screen! This algorithm will work
+ * on any machine for which there is a console_plot_pixel.
+ *
+ * console_scroll
+ * --------------
+ * My hope is that the scroll algorithm does the right thing on the
+ * various platforms, but it wouldn't be hard to add the test conditions
+ * and new code if it doesn't.
+ *
+ * console_putc
+ * -------------
+ *
+ * ######################################################################
+ *
+ * Register usage has greatly simplified within head.S. Every subroutine
+ * saves and restores all registers that it modifies (except it returns a
+ * value in there of course). So the only register that needs to be initialized
+ * is the stack pointer.
+ * All other init code and data is now placed in the init section, so it will
+ * be automatically freed at the end of the kernel initialization.
+ *
+ * ######################################################################
+ *
+ * options
+ * -------
+ * There are many options availble in a build of this file. I've
+ * taken the time to describe them here to save you the time of searching
+ * for them and trying to understand what they mean.
+ *
+ * CONFIG_xxx: These are the obvious machine configuration defines created
+ * during configuration. These are defined in include/linux/autoconf.h.
+ *
+ * CONSOLE: There is support for head.S console in this file. This
+ * console can talk to a Mac frame buffer, but could easily be extrapolated
+ * to extend it to support other platforms.
+ *
+ * TEST_MMU: This is a test harness for running on any given machine but
+ * getting an MMU dump for another class of machine. The classes of machines
+ * that can be tested are any of the makes (Atari, Amiga, Mac, VME, etc.)
+ * and any of the models (030, 040, 060, etc.).
+ *
+ * NOTE: TEST_MMU is NOT permanent! It is scheduled to be removed
+ * When head.S boots on Atari, Amiga, Macintosh, and VME
+ * machines. At that point the underlying logic will be
+ * believed to be solid enough to be trusted, and TEST_MMU
+ * can be dropped. Do note that that will clean up the
+ * head.S code significantly as large blocks of #if/#else
+ * clauses can be removed.
+ *
+ * MMU_NOCACHE_KERNEL: On the Macintosh platform there was an inquiry into
+ * determing why devices don't appear to work. A test case was to remove
+ * the cacheability of the kernel bits.
+ *
+ * MMU_PRINT: There is a routine built into head.S that can display the
+ * MMU data structures. It outputs its result through the serial_putc
+ * interface. So where ever that winds up driving data, that's where the
+ * mmu struct will appear. On the Macintosh that's typically the console.
+ *
+ * SERIAL_DEBUG: There are a series of putc() macro statements
+ * scattered through out the code to give progress of status to the
+ * person sitting at the console. This constant determines whether those
+ * are used.
+ *
+ * DEBUG: This is the standard DEBUG flag that can be set for building
+ * the kernel. It has the effect adding additional tests into
+ * the code.
+ *
+ * FONT_6x11:
+ * FONT_8x8:
+ * FONT_8x16:
+ * In theory these could be determined at run time or handed
+ * over by the booter. But, let's be real, it's a fine hard
+ * coded value. (But, you will notice the code is run-time
+ * flexible!) A pointer to the font's struct fbcon_font_desc
+ * is kept locally in Lconsole_font. It is used to determine
+ * font size information dynamically.
+ *
+ * Atari constants:
+ * USE_PRINTER: Use the printer port for serial debug.
+ * USE_SCC_B: Use the SCC port A (Serial2) for serial debug.
+ * USE_SCC_A: Use the SCC port B (Modem2) for serial debug.
+ * USE_MFP: Use the ST-MFP port (Modem1) for serial debug.
+ *
+ * Macintosh constants:
+ * MAC_SERIAL_DEBUG: Turns on serial debug output for the Macintosh.
+ * MAC_USE_SCC_A: Use the SCC port A (modem) for serial debug.
+ * MAC_USE_SCC_B: Use the SCC port B (printer) for serial debug (default).
*/
#include <linux/config.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
+#include "m68k_defs.h"
-.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem)
-.globl SYMBOL_NAME(m68k_pgtable_cachemode)
-.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+#ifdef CONFIG_MAC
-#if defined(CONFIG_MVME16x)
-.globl SYMBOL_NAME(mvme_bdid_ptr)
-#endif
+#include <asm/machw.h>
/*
- * Added m68k_supervisor_cachemode for 68060 boards where some drivers
- * need writethrough caching for supervisor accesses. Drivers known to
- * be effected are 53c7xx.c and apricot.c (when used on VME boards).
- * Richard Hirst.
+ * Macintosh console support
*/
-#ifdef CONFIG_060_WRITETHROUGH
+#define CONSOLE
+
+/*
+ * Macintosh serial debug support; outputs boot info to the printer
+ * and/or modem serial ports
+ */
+#undef MAC_SERIAL_DEBUG
+
+/*
+ * Macintosh serial debug port selection; define one or both;
+ * requires MAC_SERIAL_DEBUG to be defined
+ */
+#define MAC_USE_SCC_A /* Macintosh modem serial port */
+#define MAC_USE_SCC_B /* Macintosh printer serial port */
+
+#endif /* CONFIG_MAC */
+
+#undef MMU_PRINT
+#undef MMU_NOCACHE_KERNEL
+#define SERIAL_DEBUG
+#undef DEBUG
+
+/*
+ * For the head.S console, there are three supported fonts, 6x11, 8x16 and 8x8.
+ * The 8x8 font is harder to read but fits more on the screen.
+ */
+#define FONT_8x8 /* default */
+/* #define FONT_8x16 */ /* 2nd choice */
+/* #define FONT_6x11 */ /* 3rd choice */
+
+.globl SYMBOL_NAME(kernel_pg_dir)
+.globl SYMBOL_NAME(availmem)
+.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(m68k_supervisor_cachemode)
-#endif
-D6B_0460 = 16 /* indicates 680[46]0 in d6 */
-D6B_060 = 17 /* indicates 68060 in d6 */
-D6F_040 = 1<<D6B_0460
-D6F_060 = (1<<D6B_0460)+(1<<D6B_060)
+CPUTYPE_040 = 1 /* indicates an 040 */
+CPUTYPE_060 = 2 /* indicates an 060 */
+CPUTYPE_0460 = 3 /* if either above are set, this is set */
+CPUTYPE_020 = 4 /* indicates an 020 */
/* Translation control register */
TC_ENABLE = 0x8000
@@ -144,6 +355,7 @@ CC3_ENABLE_I = 0x00000001 /* enable instruction cache (68030) */
/* Miscellaneous definitions */
PAGESIZE = 4096
+PAGESHIFT = 12
ROOT_TABLE_SIZE = 128
PTR_TABLE_SIZE = 128
@@ -152,32 +364,182 @@ ROOT_INDEX_SHIFT = 25
PTR_INDEX_SHIFT = 18
PAGE_INDEX_SHIFT = 12
-TABLENR_4MB = 16 /* # of page tables needed to page 4 MB */
-TABLENR_16MB = 64 /* same for 16 MB */
+#ifdef DEBUG
+/* When debugging use readable names for labels */
+#ifdef __STDC__
+#define L(name) .head.S.##name
+#else
+#define L(name) .head.S./**/name
+#endif
+#else
+#ifdef __STDC__
+#define L(name) .L##name
+#else
+#define L(name) .L/**/name
+#endif
+#endif
-#define putc(ch) moveq &ch,%d7; jbsr Lserial_putc
-#define putr() putc(13); putc(10)
-#define putn(nr) movel nr,%d7; jbsr Lserial_putnum
+/* Several macros to make the writing of subroutines easier:
+ * - func_start marks the beginning of the routine which setups the frame
+ * register and saves the registers, it also defines another macro
+ * to automatically restore the registers again.
+ * - func_return marks the end of the routine and simply calls the prepared
+ * macro to restore registers and jump back to the caller.
+ * - func_define generates another macro to automatically put arguments
+ * onto the stack call the subroutine and cleanup the stack again.
+ */
-#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
-#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
-#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
-#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
-#define is_not_hp300(lab) moveq &MACH_HP300,%d7 ; cmpl %d4,%d7; jne lab
+/* Within subroutines these macros can be used to access the arguments
+ * on the stack. With STACK some allocated memory on the stack can be
+ * accessed and ARG0 points to the return address (used by mmu_engage).
+ */
+#define STACK %a6@(stackstart)
+#define ARG0 %a6@(4)
+#define ARG1 %a6@(8)
+#define ARG2 %a6@(12)
+#define ARG3 %a6@(16)
+#define ARG4 %a6@(20)
+
+.macro func_start name,saveregs,stack=0
+L(\name):
+ linkw %a6,#-\stack
+ moveml \saveregs,%sp@-
+.set stackstart,-\stack
+
+.macro func_return_\name
+ moveml %sp@+,\saveregs
+ unlk %a6
+ rts
+.endm
+.endm
+
+.macro func_return name
+ func_return_\name
+.endm
+
+.macro func_call name
+ jbsr L(\name)
+.endm
+
+.macro move_stack nr,arg1,arg2,arg3,arg4
+.if \nr
+ move_stack "(\nr-1)",\arg2,\arg3,\arg4
+ movel \arg1,%sp@-
+.endif
+.endm
+
+.macro func_define name,nr=0
+.macro \name arg1,arg2,arg3,arg4
+ move_stack \nr,\arg1,\arg2,\arg3,\arg4
+ func_call \name
+.if \nr
+ lea %sp@(\nr*4),%sp
+.endif
+.endm
+.endm
+
+func_define mmu_map,4
+func_define mmu_map_tt,4
+func_define mmu_fixup_page_mmu_cache,1
+func_define mmu_temp_map,2
+func_define mmu_engage
+func_define mmu_get_root_table_entry,1
+func_define mmu_get_ptr_table_entry,2
+func_define mmu_get_page_table_entry,2
+func_define mmu_print
+func_define get_new_page
+#ifdef CONFIG_HP300
+func_define set_leds
+#endif
+
+.macro mmu_map_eq arg1,arg2,arg3
+ mmu_map \arg1,\arg1,\arg2,\arg3
+.endm
+
+.macro get_bi_record record
+ pea \record
+ func_call get_bi_record
+ addql #4,%sp
+.endm
+
+func_define serial_putc,1
+func_define console_putc,1
+
+.macro putc ch
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ pea \ch
+#endif
+#ifdef CONSOLE
+ func_call console_putc
+#endif
+#ifdef SERIAL_DEBUG
+ func_call serial_putc
+#endif
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ addql #4,%sp
+#endif
+.endm
+
+.macro dputc ch
+#ifdef DEBUG
+ putc \ch
+#endif
+.endm
+
+func_define putn,1
+
+.macro dputn nr
+#ifdef DEBUG
+ putn \nr
+#endif
+.endm
+
+.macro puts string
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ __INITDATA
+.Lstr\@:
+ .string "\string"
+ __FINIT
+ pea %pc@(.Lstr\@)
+ func_call puts
+ addql #4,%sp
+#endif
+.endm
+
+.macro dputs string
+#ifdef DEBUG
+ puts "\string"
+#endif
+.endm
-#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
-#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
-#define is_060(lab) btst &D6B_060,%d6; jne lab
-#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+
+#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
+#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
+#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
+#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
+#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+
+#define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
+#define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
+#define is_040(lab) btst &CPUTYPE_040,%pc@(L(cputype)+3); jne lab
+#define is_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jne lab
+#define is_not_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jeq lab
+#define is_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jne lab
+#define is_not_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jeq lab
/* On the HP300 we use the on-board LEDs for debug output before
the console is running. Writing a 1 bit turns the corresponding LED
_off_ - on the 340 bit 7 is towards the back panel of the machine. */
+.macro leds mask
#ifdef CONFIG_HP300
-#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
-#else
-#define leds(x)
+ is_not_hp300(.Lled\@)
+ pea \mask
+ func_call set_leds
+ addql #4,%sp
+.Lled\@:
#endif
+.endm
.text
ENTRY(_stext)
@@ -192,81 +554,193 @@ ENTRY(_stext)
.long MACH_ATARI, ATARI_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
.long MACH_BVME6000, BVME6000_BOOTI_VERSION
+ .long MACH_MAC, MAC_BOOTI_VERSION
.long 0
-1: jra SYMBOL_NAME(_start)
+1: jra SYMBOL_NAME(__start)
-.equ SYMBOL_NAME(kernel_pmd_table),SYMBOL_NAME(_stext)
-.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table)
-.equ SYMBOL_NAME(swapper_pg_dir),SYMBOL_NAME(kernel_pg_dir)+(ROOT_TABLE_SIZE<<2)
-.equ Lavail_pmd_table,SYMBOL_NAME(swapper_pg_dir)+(ROOT_TABLE_SIZE<<2)
+.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(_stext)
.equ .,SYMBOL_NAME(_stext)+PAGESIZE
ENTRY(_start)
+ jra SYMBOL_NAME(__start)
+__INIT
+ENTRY(__start)
/*
* Setup initial stack pointer
*/
- lea %pc@(SYMBOL_NAME(_stext):w),%sp
+ lea %pc@(SYMBOL_NAME(_stext)),%sp
/*
* Record the CPU and machine type.
*/
- movew #BI_MACHTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d4
- lea %pc@(SYMBOL_NAME(m68k_machtype)),%a0
- movel %d4,%a0@
- movew #BI_FPUTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_fputype)),%a0
- movel %d0,%a0@
- movew #BI_MMUTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a0
- movel %d0,%a0@
- movew #BI_CPUTYPE,%d0
- jbsr Lget_bi_record
+ get_bi_record BI_MACHTYPE
+ lea %pc@(SYMBOL_NAME(m68k_machtype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_FPUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_fputype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MMUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_CPUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_cputype)),%a1
+ movel %a0@,%a1@
+
+#ifdef CONFIG_MAC
+/*
+ * For Macintosh, we need to determine the display parameters early (at least
+ * while debugging it).
+ */
+
+ is_not_mac(L(test_notmac))
+
+ get_bi_record BI_MAC_VADDR
+ lea %pc@(L(mac_videobase)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VDEPTH
+ lea %pc@(L(mac_videodepth)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VDIM
+ lea %pc@(L(mac_dimensions)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VROW
+ lea %pc@(L(mac_rowbytes)),%a1
+ movel %a0@,%a1@
+
+#ifdef MAC_SERIAL_DEBUG
+ get_bi_record BI_MAC_SCCBASE
+ lea %pc@(L(mac_sccbase)),%a1
+ movel %a0@,%a1@
+#endif /* MAC_SERIAL_DEBUG */
+
+#if 0
+ /*
+ * Clear the screen
+ */
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d1
+ swap %d1 /* #rows is high bytes */
+ andl #0xFFFF,%d1 /* rows */
+ subl #10,%d1
+ lea %pc@(L(mac_rowbytes)),%a0
+loopy2:
movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_cputype)),%a0
- movel %d0,%a0@
+ subql #1,%d0
+loopx2:
+ moveb #0x55, %a1@+
+ dbra %d0,loopx2
+ dbra %d1,loopy2
+#endif
+
+L(test_notmac):
+#endif /* CONFIG_MAC */
+
+/*
+ * There are ultimately two pieces of information we want for all kinds of
+ * processors CpuType and CacheBits. The CPUTYPE was passed in from booter
+ * and is converted here from a booter type definition to a separate bit
+ * number which allows for the standard is_0x0 macro tests.
+ */
+ movel %pc@(SYMBOL_NAME(m68k_cputype)),%d0
+ /*
+ * Assume it's an 030
+ */
+ clrl %d1
+
+ /*
+ * Test the BootInfo cputype for 060
+ */
btst #CPUB_68060,%d0
jeq 1f
- /* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
- movel #D6F_060+_PAGE_CACHE040W,%d6
- jra 2f
-1: btst #CPUB_68040,%d0
- jeq 1f
- /* '040: d6 := BIT0460, cache mode 0x00 (write-through) */
- movel #D6F_040+_PAGE_CACHE040W,%d6
- jra 2f
-1: /* '020 or '030: d6 := no CPU bit, cache mode unused */
- moveq #0,%d6
+ bset #CPUTYPE_060,%d1
+ bset #CPUTYPE_0460,%d1
+ jra 3f
+1:
+ /*
+ * Test the BootInfo cputype for 040
+ */
+ btst #CPUB_68040,%d0
+ jeq 2f
+ bset #CPUTYPE_040,%d1
+ bset #CPUTYPE_0460,%d1
+ jra 3f
+2:
+ /*
+ * Test the BootInfo cputype for 020
+ */
+ btst #CPUB_68020,%d0
+ jeq 3f
+ bset #CPUTYPE_020,%d1
+ jra 3f
+3:
+ /*
+ * Record the cpu type
+ */
+ lea %pc@(L(cputype)),%a0
+ movel %d1,%a0@
-2: lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
- moveq #0,%d0
- movew %d6,%d0
- movel %d0,%a0@ /* save cache mode for page tables */
+ /*
+ * NOTE:
+ *
+ * Now the macros are valid:
+ * is_040_or_060
+ * is_not_040_or_060
+ * is_040
+ * is_060
+ * is_not_060
+ */
+
+ /*
+ * Determine the cache mode for pages holding MMU tables
+ * and for supervisor mode, unused for '020 and '030
+ */
+ clrl %d0
+ clrl %d1
+ is_not_040_or_060(L(save_cachetype))
+
+ /*
+ * '040 or '060
+ * d1 := cacheable write-through
+ * NOTE: The 68040 manual strongly recommends non-cached for MMU tables,
+ * but we have been using write-through since at least 2.0.29 so I
+ * guess it is OK.
+ */
+#ifdef CONFIG_060_WRITETHROUGH
/*
* If this is a 68060 board using drivers with cache coherency
* problems, then supervisor memory accesses need to be write-through
- * also; otherwise, we want copyback.
+ * also; otherwise, we want copyback.
*/
-#if defined(CONFIG_060_WRITETHROUGH)
- is_not_060(Lset_norm)
- jra 1f
-Lset_norm:
- move.w #_PAGE_CACHE040,%d0
+ is_not_060(1f)
+ movel #_PAGE_CACHE040W,%d0
+ jra L(save_cachetype)
+#endif /* CONFIG_060_WRITETHROUGH */
1:
- lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+ movew #_PAGE_CACHE040,%d0
+
+ movel #_PAGE_CACHE040W,%d1
+
+L(save_cachetype):
+ /* Save cache mode for supervisor mode and page tables
+ */
+ lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
movel %d0,%a0@
-#endif
+ lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
+ movel %d1,%a0@
/*
* raise interrupt level
@@ -293,288 +767,120 @@ Lset_norm:
*/
#ifdef CONFIG_ATARI
- is_not_atari(Lnotypetest)
+ is_not_atari(L(notypetest))
/* get special machine type (Medusa/Hades/AB40) */
moveq #0,%d3 /* default if tag doesn't exist */
- movew #BI_ATARI_MCH_TYPE,%d0
- jbsr Lget_bi_record
+ get_bi_record BI_ATARI_MCH_TYPE
tstl %d0
jbmi 1f
movel %a0@,%d3
-1:
- /* %d3 is not clobbered until Atari page tables are set up,
- * where it is used again. */
-
+ lea %pc@(SYMBOL_NAME(atari_mch_type)),%a0
+ movel %d3,%a0@
+1:
/* On the Hades, the iobase must be set up before opening the
* serial port. There are no I/O regs at 0x00ffxxxx at all. */
moveq #0,%d0
cmpl #ATARI_MACH_HADES,%d3
jbne 1f
movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */
-1: lea %pc@(Liobase),%a0
+1: lea %pc@(L(iobase)),%a0
movel %d0,%a0@
-Lnotypetest:
+
+L(notypetest):
#endif
/*
* Initialize serial port
*/
-
- jbsr Lserial_init
-
- putr()
- putc('A')
+ jbsr L(serial_init)
/*
- * Get address at end of bootinfo and mask off at a page boundary.
+ * Initialize console
*/
- moveq #0,%d0
- jbsr Lget_bi_record
- addw #PAGESIZE-1,%a0
- movel %a0,%d0
- andl #-PAGESIZE,%d0
- movel %d0,%a6
-
- putc('B')
+#ifdef CONFIG_MAC
+ is_not_mac(L(nocon))
+#ifdef CONSOLE
+ jbsr L(console_init)
+#ifdef CONSOLE_PENGUIN
+ jbsr L(console_put_penguin)
+#endif /* CONSOLE_PENGUIN */
+ jbsr L(console_put_stats)
+#endif /* CONSOLE */
+L(nocon):
+#endif /* CONFIG_MAC */
+
+
+ putc '\n'
+ putc 'A'
+ dputn %pc@(L(cputype))
+ dputn %pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
+ dputn %pc@(SYMBOL_NAME(m68k_pgtable_cachemode))
+ dputc '\n'
/*
* Save physical start address of kernel
*/
- lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
- movel %a0,%d5
-
-/*
- * initialize the kernel root table.
- */
- lea %pc@(SYMBOL_NAME(kernel_pg_dir):w),%a5
- movel %a5,%a0
- moveq #ROOT_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
-
- /*
- * Initialize root table descriptor pointing to the kernel pointer
- * table.
- */
- lea %pc@(Lavail_pmd_table:w),%a4
- moveq #_PAGE_TABLE,%d0
- addl %a4,%d0
- movel %d0,%a5@
-
- putc('C')
-
-/*
- * Initialize the pointer tables referred to above. They either point
- * to page tables in the case of the 680[46]0 or contain early
- * termination page descriptors in the case of the 68851 or 68030.
- *
- * Each pointer table entry points to a 64 entry page table. 16 of these
- * page tables are grouped to form a single 1024 entry page table which
- * fits in a single 4096 byte page.
- *
- * Some register usages:
- * a0 -> pointer table descriptor address
- * a1 -> pointer table descriptor
- * d1 -> counter
- * d2 -> pointer table descriptor increment (varies according to CPU)
- */
-
- /* clear the kernel pointer table */
- movel %a4,%a0
- moveq #PTR_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
+ lea %pc@(L(phys_kernel_start)),%a0
+ lea %pc@(SYMBOL_NAME(_stext)),%a1
+ subl #SYMBOL_NAME(_stext),%a1
+ movel %a1,%a0@
- movel %a4,%a0
- moveq #15,%d1
+ putc 'B'
- /*
- * base value of pointer table descriptor is either
- * the address of the first page table (680[46]0)
- * or the base address of physical memory (68030).
- */
- is_040_or_060(1f)
-
- /* 680[23]0 */
- movel %d5,%a1 /* base address */
- addql #_PAGE_PRESENT,%a1 /* descriptor type */
- movel #PAGE_TABLE_SIZE*PAGESIZE,%d2 /* increment */
- jra 2f
-
-1: /* 680[46]0 */
- movel %a6,%a3 /* base address */
- addw #PAGESIZE,%a6 /* allocate page for 16 page tables */
- lea %pc@(SYMBOL_NAME(kpt)),%a1
- movel %a3,%a1@ /* save address of page table */
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* descriptor type */
- movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */
-
-2: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,2b
-
- putc('D')
+ leds 0x4
/*
- * If we are running on a 680[46]0, we have a kernel page table and
- * must initialize it. Make the entries point to the first
- * 4M of physical memory (the memory we are residing in).
- * Set the cache mode bits to Cacheable, Copyback. Set the Global bits
- * in the descriptors also.
+ * mmu_init
+ *
+ * This block of code does what's necessary to map in the various kinds
+ * of machines for execution of Linux.
+ * First map the first 4 MB of kernel code & data
*/
- is_not_040_or_060(Lnot040)
- putc('F')
-
- movel %a3,%a0
- movel %d5,%a1
-#if defined(CONFIG_060_WRITETHROUGH)
- addw #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- addl m68k_supervisor_cachemode,%a1
-#else
- addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-#endif
- movew #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
- movel #PAGESIZE,%d2
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /*
- * on the 68040, pages used to hold mmu tables should
- * be initialized as noncachable; the '060 allows write-through.
- * Do this for the root table page (which also contains
- * all pointer tables utilized thus far) and the
- * kernel page table.
- */
- movel %a5,%d0
- subl %d5,%d0
- moveq #PAGE_INDEX_SHIFT,%d2
- lsrl %d2,%d0
- lea %a3@(%d0:l:4),%a2
- movel %a2@,%d1
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@
+ mmu_map #0,%pc@(L(phys_kernel_start)),#4*1024*1024,\
+ %pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
- movel %a3,%d0
- subl %d5,%d0
- lsrl %d2,%d0
- lea %a3@(%d0:l:4),%a2
- movel %a2@,%d1
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- /*
- * %a2 points now to the page table entry for available pages at %a6,
- * hence caching modes for new pages can easily set unless increasing
- * of %a2 are forgotten.
- */
-Lnot040:
+ putc 'C'
- leds(0x4)
-
-/*
- * Do any machine specific page table initializations.
- */
#ifdef CONFIG_AMIGA
- is_not_amiga(Lnotami)
+L(mmu_init_amiga):
+
+ is_not_amiga(L(mmu_init_not_amiga))
/*
- * Setup a mapping of the first 16M of physical address space at virtual
- * address 0x80000000, using early termination page descriptors for the
- * 68030, and proper page tables for the 680[46]0. Set this area as
- * non-cacheable.
+ * mmu_init_amiga
*/
- putc('H')
+ putc 'D'
- is_040_or_060(Lspami68040)
+ is_not_040_or_060(1f)
/*
- * for the 68030, just setup a translation to map in the first
- * 32M of physical address space at virtual address 0x80000000
- * using an early termination page descriptor.
+ * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
*/
+ mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
- putc('I')
-
- movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
- movel %d0,%a5@(0x40<<2)
-
- jra Lmapphys
-
-Lspami68040:
-
- /*
- * for the 680[46]0, use another pointer table, and allocate 4 more
- * page tables. Initialize the pointer table to point to the
- * page tables. Then initialize the page tables to point to
- * the first 16M of memory, with no caching (noncachable/serialized).
- */
-
- /* clear the amiga pointer table */
- lea %a4@(PTR_TABLE_SIZE<<2),%a4
- moveq #PTR_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
-
- /* allocate 4 pages for 64 page tables */
- movel %a6,%a3
- addw #4*PAGESIZE,%a6
-
- /* initialize the pointer table */
- movel %a4,%a0
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* base descriptor */
- movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */
- moveq #TABLENR_16MB-1,%d1
-
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /* ensure that the root table points to the pointer table */
- movel %a4,%a0
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
- movel %a0,%a5@(0x40<<2)
+ jbra L(mmu_init_done)
+1:
/*
- * initialize the page tables
- * descriptor bits include noncachable/serialized and global bits.
+ * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000
*/
- movel %a3,%a0
- movew #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- movel #PAGESIZE,%d2
- movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
+ mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
+ jbra L(mmu_init_done)
- /*
- * Finally, since we just allocated 4 page tables, make sure that
- * the virtual mapping of the 4 page tables indicates
- * noncachable/serialized.
- */
- moveq #3,%d0
-1: movel %a2@,%d1 /* a2 already points to root table offset */
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- dbra %d0,1b
-
- jra Lmapphys
-
-Lnotami:
+L(mmu_init_not_amiga):
#endif
#ifdef CONFIG_ATARI
- is_not_atari(Lnotatari)
- move.w #PAGESIZE,%sp
+L(mmu_init_atari):
+
+ is_not_atari(L(mmu_init_not_atari))
+
+ putc 'E'
/* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping
the last 16 MB of virtual address space to the first 16 MB (i.e.
@@ -591,103 +897,57 @@ Lnotami:
/* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
moveq #0,%d0
+ movel %pc@(SYMBOL_NAME(atari_mch_type)),%d3
cmpl #ATARI_MACH_MEDUSA,%d3
jbeq 2f
cmpl #ATARI_MACH_HADES,%d3
jbne 1f
2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
1: movel %d0,%d3
-
- /* Let the root table point to the new pointer table */
- lea %a4@(PTR_TABLE_SIZE<<2),%a4
- movel %a4,%a0
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
- movel %a0,%a5@(0x7f<<2) /* 0xFE000000 - 0xFFFFFFFF */
-
- /* clear lower half of the pointer table (0xfexxxxxx) */
- movel %a4,%a0
- movel #(PTR_TABLE_SIZE/2)-1,%d2
-1: clrl %a0@+
- dbra %d2,1b
-
- is_040_or_060(Lspata68040)
-
-/* Mapping of the last 16M of virtual address space to the first 16M
- for efficient addressing of hardware registers */
- movel #PAGE_TABLE_SIZE*PAGESIZE,%d1
- movel #(PTR_TABLE_SIZE/2)-1,%d2
- movel %d3,%d0
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d0
-1: movel %d0,%a0@+
- addl %d1,%d0
- dbra %d2,1b
- moveq #_PAGE_NOCACHE030,%d0 /* make non-cachable */
- addl %d0,%a4@(0x7f<<2) /* 0xFFFC0000-0xFFFFFFFF (I/O space) */
-/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */
- addl %d0,%a4@(0x7c<<2)
-
- jra Lmapphys
-
-Lspata68040:
- /* allocate 4 page tables */
- movel %a6,%a3
- addw #4*PAGESIZE,%a6
-
- /* Initialize the upper half of the pointer table (a0 is still valid) */
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1
- movel #PAGE_TABLE_SIZE<<2,%d2
- moveq #TABLENR_16MB-1,%d1
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /* Initialize the page tables as noncacheable/serialized! */
- movel %a3,%a0
- movel %d3,%a1
- addw #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- movel #PAGESIZE,%d2
- movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
- /*
- * Finally, since we just allocated 4 page tables, make sure that
- * the virtual mapping of the 4 page tables indicates
- * noncachable or write-through.
- */
- moveq #3,%d0
-1: movel %a2@,%d1 /* a2 already points to root table offset */
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- dbra %d0,1b
+ is_040_or_060(L(spata68040))
+
+ /* Map everything non-cacheable, though not all parts really
+ * need to disable caches (crucial only for 0xff8000..0xffffff
+ * (standard I/O) and 0xf00000..0xf3ffff (IDE)). The remainder
+ * isn't really used, except for sometimes peeking into the
+ * ROMs (mirror at phys. 0x0), so caching isn't necessary for
+ * this. */
+ mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE030
+
+ jbra L(mmu_init_done)
+
+L(spata68040):
+
+ mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE_S
+
+ jbra L(mmu_init_done)
-Lnotatari:
+L(mmu_init_not_atari):
#endif
#ifdef CONFIG_HP300
- is_not_hp300(Lnothp300)
+ is_not_hp300(L(nothp300))
/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
- by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
- termination page descriptor. The ROM mapping is needed because the LEDs
+ by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
+ termination page descriptor. The ROM mapping is needed because the LEDs
are mapped there too. */
- movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
- movel %d0,%a5@(0x78<<2)
+ mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030
+
+L(nothp300):
-Lnothp300:
-
#endif
-#if defined(CONFIG_MVME16x)
- is_not_mvme16x(Lnot16x)
+#ifdef CONFIG_MVME16x
+
+ is_not_mvme16x(L(not16x))
/* Get pointer to board ID data */
movel %d2,%sp@-
- .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */
+ trap #15
+ .word 0x70 /* trap 0x70 - .BRD_ID */
movel %sp@+,%d2
lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0
movel %d2,%a0@
@@ -696,392 +956,330 @@ Lnothp300:
* On MVME16x we have already created kernel page tables for
* 4MB of RAM at address 0, so now need to do a transparent
* mapping of the top of memory space. Make it 0.5GByte for now.
+ * Supervisor only access, so transparent mapping doesn't
+ * clash with User code virtual address space.
+ * this covers IO devices, PROM and SRAM. The PROM and SRAM
+ * mapping is needed to allow 167Bug to run.
+ * IO is in the range 0xfff00000 to 0xfffeffff.
+ * PROM is 0xff800000->0xffbfffff and SRAM is
+ * 0xffe00000->0xffe1ffff.
*/
- movel #0xe01f0000,%d2 /* logical address base */
- orw #0xa040,%d2 /* add in magic bits */
- .long 0x4e7b2005 /* movec d2,ittr1 */
- .long 0x4e7b2007 /* movec d2,dttr1 */
+ mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
-Lnot16x:
-#endif
+ jbra L(mmu_init_done)
+
+L(not16x):
+#endif /* CONFIG_MVME162 | CONFIG_MVME167 */
+
+#ifdef CONFIG_BVME6000
-#if defined(CONFIG_BVME6000)
- is_not_bvme6000(Lnotbvm)
+ is_not_bvme6000(L(not6000))
/*
* On BVME6000 we have already created kernel page tables for
* 4MB of RAM at address 0, so now need to do a transparent
- * mapping of the top of memory space. Make it 0.5GByte for now.
+ * mapping of the top of memory space. Make it 0.5GByte for now,
+ * so we can access on-board i/o areas.
+ * Supervisor only access, so transparent mapping doesn't
+ * clash with User code virtual address space.
*/
- movel #0xe01f0000,%d2 /* logical address base */
- orw #0xa040,%d2 /* add in magic bits */
- .long 0x4e7b2005 /* movec d2,ittr1 */
- .long 0x4e7b2007 /* movec d2,dttr1 */
- .long 0x4e7b2004 /* movec d2,ittr0 */
- .long 0x4e7b2006 /* movec d2,dttr0 */
+ mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
-Lnotbvm:
-#endif
+ jbra L(mmu_init_done)
+
+L(not6000):
+#endif /* CONFIG_BVME6000 */
/*
- * Setup a transparent mapping of the physical memory we are executing in.
+ * mmu_init_mac
+ *
+ * The Macintosh mappings are less clear.
*
- * Only do this if the physical memory is not in the first 16M Meg, or not on
- * an Amiga since the first 16M is already identity mapped on the Amiga.
+ * Even as of this writing, it is unclear how the
+ * Macintosh mappings will be done. However, as
+ * the first author of this code I'm proposing the
+ * following model:
+ *
+ * Map the kernel (that's already done),
+ * Map the I/O (on most machines that's the
+ * 0x5000.0000 ... 0x5200.0000 range,
+ * Map the video frame buffer using as few pages
+ * as absolutely (this requirement mostly stems from
+ * the fact that when the frame buffer is at
+ * 0x0000.0000 then we know there is valid RAM just
+ * above the screen that we don't want to waste!).
+ *
+ * By the way, if the frame buffer is at 0x0000.0000
+ * then the Macintosh is known as an RBV based Mac.
+ *
+ * By the way 2, the code currently maps in a bunch of
+ * regions. But I'd like to cut that out. (And move most
+ * of the mappings up into the kernel proper ... or only
+ * map what's necessary.)
*/
-Lmapphys:
- putc('J')
- leds(0x8)
-#ifdef CONFIG_AMIGA
- is_not_amiga(Lmapphysnotamiga)
+#ifdef CONFIG_MAC
-/*
- * The virtual address of the start of the kernel is 0x1000. We transparently
- * translate the memory where we running in and can enable then the MMU. Hence
- * we have now two locations of the kernel in memory and can jump to the final
- * place. Except if the physical location is in the first 16MB, translation
- * will overlap later virtual location, but as we already mapped the first
- * 16MB to 0x80000000, we can jump there after translation and MMU is enabled
- * and then we can switch off translation and go to the final place.
- * On 020/030 we must emulate transparant translation, since 020 doesn't know
- * it, but due to early termination pointer this is easy to do.
- * When MMU is enabled, stack pointer and Lcustom will become again valid and
- * stack points to the unused first page.
- */
+L(mmu_init_mac):
-/*
- * Setup Supervisor Root Pointer register to point to page directory,
- * setup translation register contents and enable translation.
- */
- putc('K')
+ is_not_mac(L(mmu_init_not_mac))
- movew #PAGESIZE,%sp
+ putc 'F'
- /* fixup the Amiga custom register location before printing */
- lea %pc@(Lcustom),%a0
- movel #0x80000000,%a0@
+ lea %pc@(L(mac_videobase)),%a0
+ lea %pc@(L(console_video_virtual)),%a1
+ movel %a0@,%a1@
- is_040_or_060(Lamimmu68040)
+ is_not_040_or_060(1f)
- moveq #ROOT_INDEX_SHIFT,%d2
- movel %d5,%d0
- lsrl %d2,%d0
- movel %d0,%d1
- lsll %d2,%d1
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1
- lsll #2,%d0
- movel %a5@(%d0:w),%d2
- movel %d1,%a5@(%d0:w)
- lea %pc@(Lmmu),%a3
- /* no limit, 4byte descriptors */
- movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
+ moveq #_PAGE_NOCACHE_S,%d3
+ jbra 2f
+1:
+ moveq #_PAGE_NOCACHE030,%d3
+2:
/*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
+ * Mac Note: screen address of logical 0xF000.0000 -> <screen physical>
+ * we simply map the 4MB that contains the videomem
*/
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- tstl %d0
- jne 1f
- jmp %pc@(2f+0x80000000)
-1: jmp 2f:w
-2: movel %d2,%a5@(%d0:w)
- pflusha
- jmp LdoneMMUenable:w
-Lamimmu68040:
+ movel #VIDEOMEMMASK,%d0
+ andl L(mac_videobase),%d0
- .chip 68040
- lea 2f:w,%a0
- movel %d5,%d0
- andl #0xff000000,%d0
- jne 1f
- lea %pc@(2f+0x80000000),%a0
-1: orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
- movec %d0,%itt0
- movec %a5,%urp
- movec %a5,%srp
- pflusha
- movel #TC_ENABLE+TC_PAGE4K,%d0
- /*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
- */
- movec %d0,%tc /* enable the MMU */
- jmp %a0@
-2: moveq #0,%d0
- movec %d0,%itt0
- jmp LdoneMMUenable:w
- .chip 68k
+ mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
+ mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */
+ mmu_map_eq #0x50000000,#0x02000000,%d3
+ mmu_map_eq #0x60000000,#0x00400000,%d3
+ mmu_map_eq #0x9c000000,#0x00400000,%d3
+ mmu_map_tt 1,#0xf8000000,#0x08000000,%d3
-Lmapphysnotamiga:
+ jbra L(mmu_init_done)
+
+L(mmu_init_not_mac):
#endif
-#ifdef CONFIG_ATARI
- is_not_atari(Lmapphysnotatari)
+L(mmu_init_done):
+
+ putc 'G'
+ leds 0x8
/*
- * If the kernel physical address is different from its virtual address, we
- * will temporarily set up an identity mapping of the 16MB chunk with
- * transparent translation where the kernel is executing.
+ * mmu_fixup
+ *
+ * On the 040 class machines, all pages that are used for the
+ * mmu have to be fixed up. According to Motorola, pages holding mmu
+ * tables should be non-cacheable on a '040 and write-through on a
+ * '060. But analysis of the reasons for this, and practical
+ * experience, showed that write-through also works on a '040.
+ *
+ * Allocated memory so far goes from kernel_end to memory_start that
+ * is used for all kind of tables, for that the cache attributes
+ * are now fixed.
*/
- putc('L')
-
- /* fixup the Atari iobase register location before printing */
- lea %pc@(Liobase),%a0
- movel #0xff000000,%a0@
+L(mmu_fixup):
- is_040_or_060(Latarimmu68040)
+ is_not_040_or_060(L(mmu_fixup_done))
- .chip 68030
- lea %pc@(Lmmu),%a3
- movel %d5,%d0
- jne 1f
- lea LdoneMMUenable:w,%a0
- jra 3f
-1: lea 4f:w,%a0
- andl #0xff000000,%d0 /* logical address base */
- jeq 2f
- orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
- movel %d0,%a3@
- pmove %a3@,%tt0
- jra 3f
- /* tt0 doesn't work if physical and virtual address of kernel is in
- * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
- * Transparent translation through kernel pointer table
- * Requires that this code until after MMU enabling lies in
- * the 256K page around %d5
- */
-2: movel %a5@,%d1
- andw #0xfff0,%d1
- movel %d1,%a1
- movel %d5,%d1
- moveq #PTR_INDEX_SHIFT,%d0
- lsrl %d0,%d1
- lea %a1@(%d1:l:4),%a1
- movel %d5,%d1
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1
- movel %a1@,%d2
- movel %d1,%a1@
- lea 5f:w,%a0
- /* no limit, 4byte descriptors */
-3: movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
- /*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
- */
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- jmp %a0@
-4: clrl %a3@
- pmove %a3@,%tt0
- jra LdoneMMUenable
-5: movel %d2,%a1@
- jra LdoneMMUenable
- .chip 68k
-
-Latarimmu68040:
- .chip 68040
- movel %d5,%d0
- jne 1f
- lea LdoneMMUenable:w,%a0
- jra 2f
-1: lea 3f:w,%a0
- andl #0xff000000,%d0 /* logical address base */
- orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
- movec %d0,%itt0
-2: nop
- pflusha
- movec %a5,%srp
- movec %a5,%urp
- movel #TC_ENABLE+TC_PAGE4K,%d0
- /*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
- */
- movec %d0,%tc /* enable the MMU */
- jmp %a0@
-3: moveq #0,%d0
- movec %d0,%itt0
- jra LdoneMMUenable
- .chip 68k
-
-Lmapphysnotatari:
+#ifdef MMU_NOCACHE_KERNEL
+ jbra L(mmu_fixup_done)
#endif
-#if defined(CONFIG_MVME16x)
- is_not_mvme16x(Lmapphysnot16x)
- /*
- * save physaddr of phys mem in register a3
+ /* first fix the page at the start of the kernel, that
+ * contains also kernel_pg_dir.
*/
- moveq #'L',%d7
- jbsr Lserial_putc
-
- .word 0xf4d8 /* CINVA I/D */
- .word 0xf518 /* pflusha */
- .long 0x4e7bd807 /* movec a5,srp */
- .long 0x4e7bd806 /* movec a5,urp */
- movel #(TC_ENABLE+TC_PAGE4K),%d0
- .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
- jra LdoneMMUenable /* branch to continuation of startup */
+ movel %pc@(L(phys_kernel_start)),%d0
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ subl %d0,%a0
+ mmu_fixup_page_mmu_cache %a0
+
+ movel %pc@(L(kernel_end)),%a0
+ subl %d0,%a0
+ movel %pc@(L(memory_start)),%a1
+ subl %d0,%a1
+ bra 2f
+1:
+ mmu_fixup_page_mmu_cache %a0
+ addw #PAGESIZE,%a0
+2:
+ cmpl %a0,%a1
+ jgt 1b
-Lmapphysnot16x:
+L(mmu_fixup_done):
+#ifdef MMU_PRINT
+ mmu_print
#endif
-#if defined(CONFIG_HP300)
- is_not_hp300(Lmapphysnothp300)
-
/*
- * Physical RAM is at 0xff000000. We want to map the kernel at 0x00000000.
- * In order to avoid disaster when we enable the MMU we need to make a
- * transparent mapping of the RAM we're executing out of as well.
+ * mmu_engage
+ *
+ * This chunk of code performs the gruesome task of engaging the MMU.
+ * The reason its gruesome is because when the MMU becomes engaged it
+ * maps logical addresses to physical addresses. The Program Counter
+ * register is then passed through the MMU before the next instruction
+ * is fetched (the instruction following the engage MMU instruction).
+ * This may mean one of two things:
+ * 1. The Program Counter falls within the logical address space of
+ * the kernel of which there are two sub-possibilities:
+ * A. The PC maps to the correct instruction (logical PC == physical
+ * code location), or
+ * B. The PC does not map through and the processor will read some
+ * data (or instruction) which is not the logically next instr.
+ * As you can imagine, A is good and B is bad.
+ * Alternatively,
+ * 2. The Program Counter does not map through the MMU. The processor
+ * will take a Bus Error.
+ * Clearly, 2 is bad.
+ * It doesn't take a wiz kid to figure you want 1.A.
+ * This code creates that possibility.
+ * There are two possible 1.A. states (we now ignore the other above states):
+ * A. The kernel is located at physical memory addressed the same as
+ * the logical memory for the kernel, i.e., 0x01000.
+ * B. The kernel is located some where else. e.g., 0x0400.0000
+ *
+ * Under some conditions the Macintosh can look like A or B.
+ * [A friend and I once noted that Apple hardware engineers should be
+ * wacked twice each day: once when they show up at work (as in, Whack!,
+ * "This is for the screwy hardware we know you're going to design today."),
+ * and also at the end of the day (as in, Whack! "I don't know what
+ * you designed today, but I'm sure it wasn't good."). -- rst]
+ *
+ * This code works on the following premise:
+ * If the kernel start (%d5) is within the first 16 Meg of RAM,
+ * then create a mapping for the kernel at logical 0x8000.0000 to
+ * the physical location of the pc. And, create a transparent
+ * translation register for the first 16 Meg. Then, after the MMU
+ * is engaged, the PC can be moved up into the 0x8000.0000 range
+ * and then the transparent translation can be turned off and then
+ * the PC can jump to the correct logical location and it will be
+ * home (finally). This is essentially the code that the Amiga used
+ * to use. Now, it's generalized for all processors. Which means
+ * that a fresh (but temporary) mapping has to be created. The mapping
+ * is made in page 0 (an as of yet unused location -- except for the
+ * stack!). This temporary mapping will only require 1 pointer table
+ * and a single page table (it can map 256K).
+ *
+ * OK, alternatively, imagine that the Program Counter is not within
+ * the first 16 Meg. Then, just use Transparent Translation registers
+ * to do the right thing.
+ *
+ * Last, if _start is already at 0x01000, then there's nothing special
+ * to do (in other words, in a degenerate case of the first case above,
+ * do nothing).
+ *
+ * Let's do it.
+ *
+ *
*/
- /*
- * save physaddr of phys mem in register a3
- */
- .chip 68030
- lea %pc@(Lmmu),%a3
- movel %d5,%d0
- andl #0xff000000,%d0 /* logical address base */
- orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
- movel %d0,%a3@
- pmove %a3@,%tt0
- /* no limit, 4byte descriptors */
- movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
- /*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
- */
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- jmp 1f
-1:
- .chip 68k
+ putc 'H'
- /*
- * Fix up the custom register to point to the new location of the LEDs.
- */
- lea %pc@(Lcustom),%a1
- movel #0xf0000000,%a1@
+ mmu_engage
- /*
- * Energise the FPU and caches.
- */
- orl #0x64, 0xf05f400c
-
-Lmapphysnothp300:
+#ifdef CONFIG_AMIGA
+ is_not_amiga(1f)
+ /* fixup the Amiga custom register location before printing */
+ clrl L(custom)
+1:
+#endif
+
+#ifdef CONFIG_ATARI
+ is_not_atari(1f)
+ /* fixup the Atari iobase register location before printing */
+ movel #0xff000000,L(iobase)
+1:
+#endif
+#ifdef CONFIG_MAC
+ is_not_mac(1f)
+ movel #~VIDEOMEMMASK,%d0
+ andl L(mac_videobase),%d0
+ addl #VIDEOMEMBASE,%d0
+ movel %d0,L(mac_videobase)
+1:
#endif
-#if defined(CONFIG_BVME6000)
- is_not_bvme6000(Lmapphysnotbvm)
+#ifdef CONFIG_HP300
+ is_not_hp300(1f)
/*
- * save physaddr of phys mem in register a3
+ * Fix up the custom register to point to the new location of the LEDs.
*/
- moveq #'L',%d7
- jbsr Lserial_putc
+ movel #0xf0000000,L(custom)
- .word 0xf4d8 /* CINVA I/D */
- .word 0xf518 /* pflusha */
- .long 0x4e7bd807 /* movec a5,srp */
- .long 0x4e7bd806 /* movec a5,urp */
- movel #(TC_ENABLE+TC_PAGE4K),%d0
/*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
+ * Energise the FPU and caches.
*/
- .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
- jra LdoneMMUenable /* branch to continuation of startup */
-
-Lmapphysnotbvm:
-
+ movel #0x60,0xf05f400c
+1:
#endif
-LdoneMMUenable:
-
/*
* Fixup the addresses for the kernel pointer table and availmem.
* Convert them from physical addresses to virtual addresses.
*/
- putc('M')
- leds(0x10)
-
- /*
- * d5 contains physaddr of kernel start
- */
- subl %d5,SYMBOL_NAME(kpt)
+ putc 'I'
+ leds 0x10
- /*
- * do the same conversion on the first available memory
+ /* do the same conversion on the first available memory
* address (in a6).
*/
- subl %d5,%a6
- movel %a6,SYMBOL_NAME(availmem) /* first available memory address */
-
- putc('N')
+ movel L(memory_start),%d0
+ movel %d0,SYMBOL_NAME(availmem)
/*
* Enable caches
*/
- is_040_or_060(Lcache680460)
- movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
- movec %d0,%cacr
- jra 1f
+ is_not_040_or_060(L(cache_not_680460))
-Lcache680460:
+L(cache680460):
.chip 68040
+ nop
cpusha %bc
- .chip 68k
+ nop
- is_060(Lcache68060)
+ is_060(L(cache68060))
movel #CC6_ENABLE_D+CC6_ENABLE_I,%d0
/* MMU stuff works in copyback mode now, so enable the cache */
movec %d0,%cacr
- jra 1f
+ jra L(cache_done)
-Lcache68060:
- .chip 68060
+L(cache68060):
movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0
/* MMU stuff works in copyback mode now, so enable the cache */
movec %d0,%cacr
/* enable superscalar dispatch in PCR */
moveq #1,%d0
+ .chip 68060
movec %d0,%pcr
+
+ jbra L(cache_done)
+L(cache_not_680460):
+L(cache68030):
+ .chip 68030
+ movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
+ movec %d0,%cacr
+
+ jra L(cache_done)
.chip 68k
-1:
+L(cache_done):
+
+ putc 'J'
/*
* Setup initial stack pointer
- * We need to get current loaded up with our first task...
*/
lea SYMBOL_NAME(init_task_union),%a2
- lea 8192(%a2),%sp
+ lea 0x2000(%a2),%sp
/* jump to the kernel start */
- putr()
- leds(0x55)
+ putc '\n'
+ leds 0x55
- subl %a6,%a6 /* clear a6 for gdb */
+ subl %a6,%a6 /* clear a6 for gdb */
jbsr SYMBOL_NAME(start_kernel)
/*
@@ -1090,33 +1288,1260 @@ Lcache68060:
* Returns: d0: size (-1 if not found)
* a0: data pointer (end-of-records if not found)
*/
-Lget_bi_record:
+func_start get_bi_record,%d1
+
+ movel ARG1,%d0
lea %pc@(SYMBOL_NAME(_end)),%a0
-1: tstw %a0@(BIR_tag)
+1: tstw %a0@(BIR_TAG)
jeq 3f
- cmpw %a0@(BIR_tag),%d0
+ cmpw %a0@(BIR_TAG),%d0
jeq 2f
- addw %a0@(BIR_size),%a0
+ addw %a0@(BIR_SIZE),%a0
jra 1b
2: moveq #0,%d0
- movew %a0@(BIR_size),%d0
- lea %a0@(BIR_data),%a0
- rts
+ movew %a0@(BIR_SIZE),%d0
+ lea %a0@(BIR_DATA),%a0
+ jra 4f
3: moveq #-1,%d0
- lea %a0@(BIR_size),%a0
+ lea %a0@(BIR_SIZE),%a0
+4:
+func_return get_bi_record
+
+
+/*
+ * MMU Initialization Begins Here
+ *
+ * The structure of the MMU tables on the 68k machines
+ * is thus:
+ * Root Table
+ * Logical addresses are translated through
+ * a hierarchical translation mechanism where the high-order
+ * seven bits of the logical address (LA) are used as an
+ * index into the "root table." Each entry in the root
+ * table has a bit which specifies if it's a valid pointer to a
+ * pointer table. Each entry defines a 32KMeg range of memory.
+ * If an entry is invalid then that logical range of 32M is
+ * invalid and references to that range of memory (when the MMU
+ * is enabled) will fault. If the entry is valid, then it does
+ * one of two things. On 040/060 class machines, it points to
+ * a pointer table which then describes more finely the memory
+ * within that 32M range. On 020/030 class machines, a technique
+ * called "early terminating descriptors" are used. This technique
+ * allows an entire 32Meg to be described by a single entry in the
+ * root table. Thus, this entry in the root table, contains the
+ * physical address of the memory or I/O at the logical address
+ * which the entry represents and it also contains the necessary
+ * cache bits for this region.
+ *
+ * Pointer Tables
+ * Per the Root Table, there will be one or more
+ * pointer tables. Each pointer table defines a 32M range.
+ * Not all of the 32M range need be defined. Again, the next
+ * seven bits of the logical address are used an index into
+ * the pointer table to point to page tables (if the pointer
+ * is valid). There will undoubtedly be more than one
+ * pointer table for the kernel because each pointer table
+ * defines a range of only 32M. Valid pointer table entries
+ * point to page tables, or are early terminating entries
+ * themselves.
+ *
+ * Page Tables
+ * Per the Pointer Tables, each page table entry points
+ * to the physical page in memory that supports the logical
+ * address that translates to the particular index.
+ *
+ * In short, the Logical Address gets translated as follows:
+ * bits 31..26 - index into the Root Table
+ * bits 25..18 - index into the Pointer Table
+ * bits 17..12 - index into the Page Table
+ * bits 11..0 - offset into a particular 4K page
+ *
+ * The algorithms which follows do one thing: they abstract
+ * the MMU hardware. For example, there are three kinds of
+ * cache settings that are relevant. Either, memory is
+ * being mapped in which case it is either Kernel Code (or
+ * the RamDisk) or it is MMU data. On the 030, the MMU data
+ * option also describes the kernel. Or, I/O is being mapped
+ * in which case it has its own kind of cache bits. There
+ * are constants which abstract these notions from the code that
+ * actually makes the call to map some range of memory.
+ *
+ *
+ *
+ */
+
+#ifdef MMU_PRINT
+/*
+ * mmu_print
+ *
+ * This algorithm will print out the current MMU mappings.
+ *
+ * Input:
+ * %a5 points to the root table. Everything else is calculated
+ * from this.
+ */
+
+#define mmu_next_valid 0
+#define mmu_start_logical 4
+#define mmu_next_logical 8
+#define mmu_start_physical 12
+#define mmu_next_physical 16
+
+#define MMU_PRINT_INVALID -1
+#define MMU_PRINT_VALID 1
+#define MMU_PRINT_UNINITED 0
+
+#define putZc(z,n) jbne 1f; putc z; jbra 2f; 1: putc n; 2:
+
+func_start mmu_print,%a0-%a6/%d0-%d7
+
+ movel %pc@(L(kernel_pgdir_ptr)),%a5
+ lea %pc@(L(mmu_print_data)),%a0
+ movel #MMU_PRINT_UNINITED,%a0@(mmu_next_valid)
+
+ is_not_040_or_060(mmu_030_print)
+
+mmu_040_print:
+ puts "\nMMU040\n"
+ puts "rp:"
+ putn %a5
+ putc '\n'
+#if 0
+ /*
+ * The following #if/#endif block is a tight algorithm for dumping the 040
+ * MMU Map in gory detail. It really isn't that practical unless the
+ * MMU Map algorithm appears to go awry and you need to debug it at the
+ * entry per entry level.
+ */
+ movel #ROOT_TABLE_SIZE,%d5
+#if 0
+ movel %a5@+,%d7 | Burn an entry to skip the kernel mappings,
+ subql #1,%d5 | they (might) work
+#endif
+1: tstl %d5
+ jbeq mmu_print_done
+ subq #1,%d5
+ movel %a5@+,%d7
+ btst #1,%d7
+ jbeq 1b
+
+2: putn %d7
+ andil #0xFFFFFE00,%d7
+ movel %d7,%a4
+ movel #PTR_TABLE_SIZE,%d4
+ putc ' '
+3: tstl %d4
+ jbeq 11f
+ subq #1,%d4
+ movel %a4@+,%d7
+ btst #1,%d7
+ jbeq 3b
+
+4: putn %d7
+ andil #0xFFFFFF00,%d7
+ movel %d7,%a3
+ movel #PAGE_TABLE_SIZE,%d3
+5: movel #8,%d2
+6: tstl %d3
+ jbeq 31f
+ subq #1,%d3
+ movel %a3@+,%d6
+ btst #0,%d6
+ jbeq 6b
+7: tstl %d2
+ jbeq 8f
+ subq #1,%d2
+ putc ' '
+ jbra 91f
+8: putc '\n'
+ movel #8+1+8+1+1,%d2
+9: putc ' '
+ dbra %d2,9b
+ movel #7,%d2
+91: putn %d6
+ jbra 6b
+
+31: putc '\n'
+ movel #8+1,%d2
+32: putc ' '
+ dbra %d2,32b
+ jbra 3b
+
+11: putc '\n'
+ jbra 1b
+#endif /* MMU 040 Dumping code that's gory and detailed */
+
+ lea %pc@(SYMBOL_NAME(kernel_pg_dir)),%a5
+ movel %a5,%a0 /* a0 has the address of the root table ptr */
+ movel #0x00000000,%a4 /* logical address */
+ moveql #0,%d0
+40:
+ /* Increment the logical address and preserve in d5 */
+ movel %a4,%d5
+ addil #PAGESIZE<<13,%d5
+ movel %a0@+,%d6
+ btst #1,%d6
+ jbne 41f
+ jbsr mmu_print_tuple_invalidate
+ jbra 48f
+41:
+ movel #0,%d1
+ andil #0xfffffe00,%d6
+ movel %d6,%a1
+42:
+ movel %a4,%d5
+ addil #PAGESIZE<<6,%d5
+ movel %a1@+,%d6
+ btst #1,%d6
+ jbne 43f
+ jbsr mmu_print_tuple_invalidate
+ jbra 47f
+43:
+ movel #0,%d2
+ andil #0xffffff00,%d6
+ movel %d6,%a2
+44:
+ movel %a4,%d5
+ addil #PAGESIZE,%d5
+ movel %a2@+,%d6
+ btst #0,%d6
+ jbne 45f
+ jbsr mmu_print_tuple_invalidate
+ jbra 46f
+45:
+ moveml %d0-%d1,%sp@-
+ movel %a4,%d0
+ movel %d6,%d1
+ andil #0xfffff4e0,%d1
+ lea %pc@(mmu_040_print_flags),%a6
+ jbsr mmu_print_tuple
+ moveml %sp@+,%d0-%d1
+46:
+ movel %d5,%a4
+ addq #1,%d2
+ cmpib #64,%d2
+ jbne 44b
+47:
+ movel %d5,%a4
+ addq #1,%d1
+ cmpib #128,%d1
+ jbne 42b
+48:
+ movel %d5,%a4 /* move to the next logical address */
+ addq #1,%d0
+ cmpib #128,%d0
+ jbne 40b
+
+ .chip 68040
+ movec %dtt1,%d0
+ movel %d0,%d1
+ andiw #0x8000,%d1 /* is it valid ? */
+ jbeq 1f /* No, bail out */
+
+ movel %d0,%d1
+ andil #0xff000000,%d1 /* Get the address */
+ putn %d1
+ puts "=="
+ putn %d1
+
+ movel %d0,%d6
+ jbsr mmu_040_print_flags_tt
+1:
+ movec %dtt0,%d0
+ movel %d0,%d1
+ andiw #0x8000,%d1 /* is it valid ? */
+ jbeq 1f /* No, bail out */
+
+ movel %d0,%d1
+ andil #0xff000000,%d1 /* Get the address */
+ putn %d1
+ puts "=="
+ putn %d1
+
+ movel %d0,%d6
+ jbsr mmu_040_print_flags_tt
+1:
+ .chip 68k
+
+ jbra mmu_print_done
+
+mmu_040_print_flags:
+ btstl #10,%d6
+ putZc(' ','G') /* global bit */
+ btstl #7,%d6
+ putZc(' ','S') /* supervisor bit */
+mmu_040_print_flags_tt:
+ btstl #6,%d6
+ jbne 3f
+ putc 'C'
+ btstl #5,%d6
+ putZc('w','c') /* write through or copy-back */
+ jbra 4f
+3:
+ putc 'N'
+ btstl #5,%d6
+ putZc('s',' ') /* serialized non-cacheable, or non-cacheable */
+4:
+ rts
+
+mmu_030_print_flags:
+ btstl #6,%d6
+ putZc('C','I') /* write through or copy-back */
+ rts
+
+mmu_030_print:
+ puts "\nMMU030\n"
+ puts "\nrp:"
+ putn %a5
+ putc '\n'
+ movel %a5,%d0
+ andil #0xfffffff0,%d0
+ movel %d0,%a0
+ movel #0x00000000,%a4 /* logical address */
+ movel #0,%d0
+30:
+ movel %a4,%d5
+ addil #PAGESIZE<<13,%d5
+ movel %a0@+,%d6
+ btst #1,%d6 /* is it a ptr? */
+ jbne 31f /* yes */
+ btst #0,%d6 /* is it early terminating? */
+ jbeq 1f /* no */
+ jbsr mmu_030_print_helper
+ jbra 38f
+1:
+ jbsr mmu_print_tuple_invalidate
+ jbra 38f
+31:
+ movel #0,%d1
+ andil #0xfffffff0,%d6
+ movel %d6,%a1
+32:
+ movel %a4,%d5
+ addil #PAGESIZE<<6,%d5
+ movel %a1@+,%d6
+ btst #1,%d6
+ jbne 33f
+ btst #0,%d6
+ jbeq 1f /* no */
+ jbsr mmu_030_print_helper
+ jbra 37f
+1:
+ jbsr mmu_print_tuple_invalidate
+ jbra 37f
+33:
+ movel #0,%d2
+ andil #0xfffffff0,%d6
+ movel %d6,%a2
+34:
+ movel %a4,%d5
+ addil #PAGESIZE,%d5
+ movel %a2@+,%d6
+ btst #0,%d6
+ jbne 35f
+ jbsr mmu_print_tuple_invalidate
+ jbra 36f
+35:
+ jbsr mmu_030_print_helper
+36:
+ movel %d5,%a4
+ addq #1,%d2
+ cmpib #64,%d2
+ jbne 34b
+37:
+ movel %d5,%a4
+ addq #1,%d1
+ cmpib #128,%d1
+ jbne 32b
+38:
+ movel %d5,%a4 /* move to the next logical address */
+ addq #1,%d0
+ cmpib #128,%d0
+ jbne 30b
+
+mmu_print_done:
+ puts "\n\n"
+
+func_return mmu_print
+
+
+mmu_030_print_helper:
+ moveml %d0-%d1,%sp@-
+ movel %a4,%d0
+ movel %d6,%d1
+ lea %pc@(mmu_030_print_flags),%a6
+ jbsr mmu_print_tuple
+ moveml %sp@+,%d0-%d1
+ rts
+
+mmu_print_tuple_invalidate:
+ moveml %a0/%d7,%sp@-
+
+ lea %pc@(L(mmu_print_data)),%a0
+ tstl %a0@(mmu_next_valid)
+ jbmi mmu_print_tuple_invalidate_exit
+
+ movel #MMU_PRINT_INVALID,%a0@(mmu_next_valid)
+
+ putn %a4
+
+ puts "##\n"
+
+mmu_print_tuple_invalidate_exit:
+ moveml %sp@+,%a0/%d7
+ rts
+
+
+mmu_print_tuple:
+ moveml %d0-%d7/%a0,%sp@-
+
+ lea %pc@(L(mmu_print_data)),%a0
+
+ tstl %a0@(mmu_next_valid)
+ jble mmu_print_tuple_print
+
+ cmpl %a0@(mmu_next_physical),%d1
+ jbeq mmu_print_tuple_increment
+
+mmu_print_tuple_print:
+ putn %d0
+ puts "->"
+ putn %d1
+
+ movel %d1,%d6
+ jbsr %a6@
+
+mmu_print_tuple_record:
+ movel #MMU_PRINT_VALID,%a0@(mmu_next_valid)
+
+ movel %d1,%a0@(mmu_next_physical)
+
+mmu_print_tuple_increment:
+ movel %d5,%d7
+ subl %a4,%d7
+ addl %d7,%a0@(mmu_next_physical)
+
+mmu_print_tuple_exit:
+ moveml %sp@+,%d0-%d7/%a0
rts
+mmu_print_machine_cpu_types:
+ puts "machine: "
+
+ is_not_amiga(1f)
+ puts "amiga"
+ jbra 9f
+1:
+ is_not_atari(2f)
+ puts "atari"
+ jbra 9f
+2:
+ is_not_mac(3f)
+ puts "macintosh"
+ jbra 9f
+3: puts "unknown"
+9: putc '\n'
+
+ puts "cputype: 0"
+ is_not_060(1f)
+ putc '6'
+ jbra 9f
+1:
+ is_not_040_or_060(2f)
+ putc '4'
+ jbra 9f
+2: putc '3'
+9: putc '0'
+ putc '\n'
+
+ rts
+#endif /* MMU_PRINT */
+
+/*
+ * mmu_map_tt
+ *
+ * This is a specific function which works on all 680x0 machines.
+ * On 030, 040 & 060 it will attempt to use Transparent Translation
+ * registers (tt1).
+ * On 020 it will call the standard mmu_map which will use early
+ * terminating descriptors.
+ */
+func_start mmu_map_tt,%d0/%d1/%a0,4
+
+ dputs "mmu_map_tt:"
+ dputn ARG1
+ dputn ARG2
+ dputn ARG3
+ dputn ARG4
+ dputc '\n'
+
+ is_020(L(do_map))
+
+ /* Extract the highest bit set
+ */
+ bfffo ARG3{#0,#32},%d1
+ cmpw #8,%d0
+ jcc L(do_map)
+
+ /* And get the mask
+ */
+ moveq #-1,%d0
+ lsrl %d1,%d0
+ lsrl #1,%d0
+
+ /* Mask the address
+ */
+ movel %d0,%d1
+ notl %d1
+ andl ARG2,%d1
+
+ /* Generate the upper 16bit of the tt register
+ */
+ lsrl #8,%d0
+ orl %d0,%d1
+ clrw %d1
+
+ is_040_or_060(L(mmu_map_tt_040))
+
+ /* set 030 specific bits (read/write access for supervisor mode
+ * (highest function code set, lower two bits masked))
+ */
+ orw #TTR_ENABLE+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d1
+ movel ARG4,%d0
+ btst #6,%d0
+ jeq 1f
+ orw #TTR_CI,%d1
+
+1: lea STACK,%a0
+ dputn %d1
+ movel %d1,%a0@
+ .chip 68030
+ tstl ARG1
+ jne 1f
+ pmove %a0@,%tt0
+ jra 2f
+1: pmove %a0@,%tt1
+2: .chip 68k
+ jra L(mmu_map_tt_done)
+
+ /* set 040 specific bits
+ */
+L(mmu_map_tt_040):
+ orw #TTR_ENABLE+TTR_KERNELMODE,%d1
+ orl ARG4,%d1
+ dputn %d1
+
+ .chip 68040
+ tstl ARG1
+ jne 1f
+ movec %d1,%itt0
+ movec %d1,%dtt0
+ jra 2f
+1: movec %d1,%itt1
+ movec %d1,%dtt1
+2: .chip 68k
+
+ jra L(mmu_map_tt_done)
+
+L(do_map):
+ mmu_map_eq ARG2,ARG3,ARG4
+
+L(mmu_map_tt_done):
+
+func_return mmu_map_tt
+
+/*
+ * mmu_map
+ *
+ * This routine will map a range of memory using a pointer
+ * table and allocating the pages on the fly from the kernel.
+ * The pointer table does not have to be already linked into
+ * the root table, this routine will do that if necessary.
+ *
+ * NOTE
+ * This routine will assert failure and use the serial_putc
+ * routines in the case of a run-time error. For example,
+ * if the address is already mapped.
+ *
+ * NOTE-2
+ * This routine will use early terminating descriptors
+ * where possible for the 68020+68851 and 68030 type
+ * processors.
+ */
+func_start mmu_map,%d0-%d4/%a0-%a4
+
+ dputs "\nmmu_map:"
+ dputn ARG1
+ dputn ARG2
+ dputn ARG3
+ dputn ARG4
+ dputc '\n'
+
+ /* Get logical address and round it down to 256KB
+ */
+ movel ARG1,%d0
+ andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0
+ movel %d0,%a3
+
+ /* Get the end address
+ */
+ movel ARG1,%a4
+ addl ARG3,%a4
+ subql #1,%a4
+
+ /* Get physical address and round it down to 256KB
+ */
+ movel ARG2,%d0
+ andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0
+ movel %d0,%a2
+
+ /* Add page attributes to the physical address
+ */
+ movel ARG4,%d0
+ orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0
+ addw %d0,%a2
+
+ dputn %a2
+ dputn %a3
+ dputn %a4
+
+ is_not_040_or_060(L(mmu_map_030))
+
+ addw #_PAGE_GLOBAL040,%a2
+/*
+ * MMU 040 & 060 Support
+ *
+ * The MMU usage for the 040 and 060 is different enough from
+ * the 030 and 68851 that there is separate code. This comment
+ * block describes the data structures and algorithms built by
+ * this code.
+ *
+ * The 040 does not support early terminating descriptors, as
+ * the 030 does. Therefore, a third level of table is needed
+ * for the 040, and that would be the page table. In Linux,
+ * page tables are allocated directly from the memory above the
+ * kernel.
+ *
+ */
+
+L(mmu_map_040):
+ /* Calculate the offset into the root table
+ */
+ movel %a3,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel %a3,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* Calculate the offset into the page table
+ */
+ movel %a3,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ mmu_get_page_table_entry %a0,%d0
+
+ /* The page table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ movel %a2,%a0@
+2:
+ addw #PAGESIZE,%a2
+ addw #PAGESIZE,%a3
+
+ /* Ready with mapping?
+ */
+ lea %a3@(-1),%a0
+ cmpl %a0,%a4
+ jhi L(mmu_map_040)
+ jra L(mmu_map_done)
+
+L(mmu_map_030):
+ /* Calculate the offset into the root table
+ */
+ movel %a3,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Check if logical address 32MB aligned,
+ * so we can try to map it once
+ */
+ movel %a3,%d0
+ andl #(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1)&(-ROOT_TABLE_SIZE),%d0
+ jne 1f
+
+ /* Is there enough to map for 32MB at once
+ */
+ lea %a3@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1),%a1
+ cmpl %a1,%a4
+ jcs 1f
+
+ addql #1,%a1
+
+ /* The root table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ dputs "early term1"
+ dputn %a2
+ dputn %a3
+ dputn %a1
+ dputc '\n'
+ movel %a2,%a0@
+
+ movel %a1,%a3
+ lea %a2@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE),%a2
+ jra L(mmu_mapnext_030)
+1:
+ /* Calculate the offset into the pointer table
+ */
+ movel %a3,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* The pointer table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ dputs "early term2"
+ dputn %a2
+ dputn %a3
+ dputc '\n'
+ movel %a2,%a0@
+
+ addl #PAGE_TABLE_SIZE*PAGESIZE,%a2
+ addl #PAGE_TABLE_SIZE*PAGESIZE,%a3
+
+L(mmu_mapnext_030):
+ /* Ready with mapping?
+ */
+ lea %a3@(-1),%a0
+ cmpl %a0,%a4
+ jhi L(mmu_map_030)
+ jra L(mmu_map_done)
+
+L(mmu_map_error):
+
+ dputs "mmu_map error:"
+ dputn %a2
+ dputn %a3
+ dputc '\n'
+
+L(mmu_map_done):
+
+func_return mmu_map
+
+/*
+ * mmu_fixup
+ *
+ * On the 040 class machines, all pages that are used for the
+ * mmu have to be fixed up.
+ */
+
+func_start mmu_fixup_page_mmu_cache,%d0/%a0
+
+ dputs "mmu_fixup_page_mmu_cache"
+ dputn ARG1
+
+ /* Calculate the offset into the root table
+ */
+ movel ARG1,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel ARG1,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* Calculate the offset into the page table
+ */
+ movel ARG1,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ mmu_get_page_table_entry %a0,%d0
+
+ movel %a0@,%d0
+ andil #_CACHEMASK040,%d0
+ orl %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%d0
+ movel %d0,%a0@
+
+ dputc '\n'
+
+func_return mmu_fixup_page_mmu_cache
+
+/*
+ * mmu_temp_map
+ *
+ * create a temporary mapping to enable the mmu,
+ * this we don't need any transparation translation tricks.
+ */
+
+func_start mmu_temp_map,%d0/%d1/%a0/%a1
+
+ dputs "mmu_temp_map"
+ dputn ARG1
+ dputn ARG2
+ dputc '\n'
+
+ lea %pc@(L(temp_mmap_mem)),%a1
+
+ /* Calculate the offset in the root table
+ */
+ movel ARG2,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Check if the table is temporary allocated, so we have to reuse it
+ */
+ movel %a0@,%d0
+ cmpl %pc@(L(memory_start)),%d0
+ jcc 1f
+
+ /* Temporary allocate a ptr table and insert it into the root table
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+ dputs " (new)"
+1:
+ dputn %d0
+ /* Mask the root table entry for the ptr table
+ */
+ andw #-ROOT_TABLE_SIZE,%d0
+ movel %d0,%a0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel ARG2,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ lea %a0@(%d0*4),%a0
+ dputn %a0
+
+ /* Check if a temporary page table is already allocated
+ */
+ movel %a0@,%d0
+ jne 1f
+
+ /* Temporary allocate a page table and insert it into the ptr table
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+ dputs " (new)"
+1:
+ dputn %d0
+ /* Mask the ptr table entry for the page table
+ */
+ andw #-PTR_TABLE_SIZE,%d0
+ movel %d0,%a0
+
+ /* Calculate the offset into the page table
+ */
+ movel ARG2,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ lea %a0@(%d0*4),%a0
+ dputn %a0
+
+ /* Insert the address into the page table
+ */
+ movel ARG1,%d0
+ andw #-PAGESIZE,%d0
+ orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0
+ movel %d0,%a0@
+ dputn %d0
+
+ dputc '\n'
+
+func_return mmu_temp_map
+
+func_start mmu_engage,%d0-%d2/%a0-%a3
+
+ moveq #ROOT_TABLE_SIZE-1,%d0
+ /* Temporarily use a different root table. */
+ lea %pc@(L(kernel_pgdir_ptr)),%a0
+ movel %a0@,%a2
+ movel %pc@(L(memory_start)),%a1
+ movel %a1,%a0@
+ movel %a2,%a0
+1:
+ movel %a0@+,%a1@+
+ dbra %d0,1b
+
+ lea %pc@(L(temp_mmap_mem)),%a0
+ movel %a1,%a0@
+
+ movew #PAGESIZE-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ lea %pc@(1b),%a0
+ movel #1b,%a1
+ /* Skip temp mappings if phys == virt */
+ cmpl %a0,%a1
+ jeq 1f
+
+ mmu_temp_map %a0,%a0
+ mmu_temp_map %a0,%a1
+
+ addw #PAGESIZE,%a0
+ addw #PAGESIZE,%a1
+ mmu_temp_map %a0,%a0
+ mmu_temp_map %a0,%a1
+1:
+ movel %pc@(L(memory_start)),%a3
+ movel %pc@(L(phys_kernel_start)),%d2
+
+ is_not_040_or_060(L(mmu_engage_030))
+
+L(mmu_engage_040):
+ .chip 68040
+ nop
+ cinva %bc
+ nop
+ pflusha
+ nop
+ movec %a3,%srp
+ movel #TC_ENABLE+TC_PAGE4K,%d0
+ movec %d0,%tc /* enable the MMU */
+ jmp 1f:l
+1: nop
+ movec %a2,%srp
+ nop
+ cinva %bc
+ nop
+ pflusha
+ .chip 68k
+ jra L(mmu_engage_cleanup)
+
+L(mmu_engage_030_temp):
+ .space 12
+L(mmu_engage_030):
+ .chip 68030
+ lea %pc@(L(mmu_engage_030_temp)),%a0
+ movel #0x80000002,%a0@
+ movel %a3,%a0@(4)
+ movel #0x0808,%d0
+ movec %d0,%cacr
+ pmove %a0@,%srp
+ pflusha
+ /*
+ * enable,super root enable,4096 byte pages,7 bit root index,
+ * 7 bit pointer index, 6 bit page table index.
+ */
+ movel #0x82c07760,%a0@(8)
+ pmove %a0@(8),%tc /* enable the MMU */
+ jmp 1f:l
+1: movel %a2,%a0@(4)
+ movel #0x0808,%d0
+ movec %d0,%cacr
+ pmove %a0@,%srp
+ pflusha
+ .chip 68k
+
+L(mmu_engage_cleanup):
+ subl %d2,%a2
+ movel %a2,L(kernel_pgdir_ptr)
+ subl %d2,%fp
+ subl %d2,%sp
+ subl %d2,ARG0
+ subl %d2,L(memory_start)
+
+func_return mmu_engage
+
+func_start mmu_get_root_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_root_table_entry:"
+ dputn ARG1
+ dputs " ="
+#endif
+
+ movel %pc@(L(kernel_pgdir_ptr)),%a0
+ tstl %a0
+ jne 2f
+
+ dputs "\nmmu_init:"
+
+ /* Find the start of free memory, get_bi_record does this for us,
+ * as the bootinfo structure is located directly behind the kernel
+ * and and we simply search for the last entry.
+ */
+ get_bi_record BI_LAST
+ addw #PAGESIZE-1,%a0
+ movel %a0,%d0
+ andw #-PAGESIZE,%d0
+
+ dputn %d0
+
+ lea %pc@(L(memory_start)),%a0
+ movel %d0,%a0@
+ lea %pc@(L(kernel_end)),%a0
+ movel %d0,%a0@
+
+ /* we have to return the first page at _stext since the init code
+ * in mm/init.c simply expects kernel_pg_dir there, the rest of
+ * page is used for further ptr tables in get_ptr_table.
+ */
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ lea %pc@(L(mmu_cached_pointer_tables)),%a1
+ movel %a0,%a1@
+ addl #ROOT_TABLE_SIZE*4,%a1@
+
+ lea %pc@(L(mmu_num_pointer_tables)),%a1
+ addql #1,%a1@
+
+ /* clear the page
+ */
+ movel %a0,%a1
+ movew #PAGESIZE/4-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ lea %pc@(L(kernel_pgdir_ptr)),%a1
+ movel %a0,%a1@
+
+ dputn %a0
+ dputc '\n'
+2:
+ movel ARG1,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_root_table_entry
+
+
+
+func_start mmu_get_ptr_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_ptr_table_entry:"
+ dputn ARG1
+ dputn ARG2
+ dputs " ="
+#endif
+
+ movel ARG1,%a0
+ movel %a0@,%d0
+ jne 2f
+
+ /* Keep track of the number of pointer tables we use
+ */
+ dputs "\nmmu_get_new_ptr_table:"
+ lea %pc@(L(mmu_num_pointer_tables)),%a0
+ movel %a0@,%d0
+ addql #1,%a0@
+
+ /* See if there is a free pointer table in our cache of pointer tables
+ */
+ lea %pc@(L(mmu_cached_pointer_tables)),%a1
+ andw #7,%d0
+ jne 1f
+
+ /* Get a new pointer table page from above the kernel memory
+ */
+ get_new_page
+ movel %a0,%a1@
+1:
+ /* There is an unused pointer table in our cache... use it
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+
+ dputn %d0
+ dputc '\n'
+
+ /* Insert the new pointer table into the root table
+ */
+ movel ARG1,%a0
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+2:
+ /* Extract the pointer table entry
+ */
+ andw #-PTR_TABLE_SIZE,%d0
+ movel %d0,%a0
+ movel ARG2,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_ptr_table_entry
+
+
+func_start mmu_get_page_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_page_table_entry:"
+ dputn ARG1
+ dputn ARG2
+ dputs " ="
+#endif
+
+ movel ARG1,%a0
+ movel %a0@,%d0
+ jne 2f
+
+ /* If the page table entry doesn't exist, we allocate a complete new
+ * page and use it as one continues big page table which can cover
+ * 4MB of memory, nearly almost all mappings have that alignment.
+ */
+ get_new_page
+ addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
+
+ /* align pointer table entry for a page of page tables
+ */
+ movel ARG1,%d0
+ andw #-(PAGESIZE/PAGE_TABLE_SIZE),%d0
+ movel %d0,%a1
+
+ /* Insert the page tables into the pointer entries
+ */
+ moveq #PAGESIZE/PAGE_TABLE_SIZE/4-1,%d0
+1:
+ movel %a0,%a1@+
+ lea %a0@(PAGE_TABLE_SIZE*4),%a0
+ dbra %d0,1b
+
+ /* Now we can get the initialized pointer table entry
+ */
+ movel ARG1,%a0
+ movel %a0@,%d0
+2:
+ /* Extract the page table entry
+ */
+ andw #-PAGE_TABLE_SIZE,%d0
+ movel %d0,%a0
+ movel ARG2,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_page_table_entry
+
+/*
+ * get_new_page
+ *
+ * Return a new page from the memory start and clear it.
+ */
+func_start get_new_page,%d0/%a1
+
+ dputs "\nget_new_page:"
+
+ /* allocate the page and adjust memory_start
+ */
+ lea %pc@(L(memory_start)),%a0
+ movel %a0@,%a1
+ addl #PAGESIZE,%a0@
+
+ /* clear the new page
+ */
+ movel %a1,%a0
+ movew #PAGESIZE/4-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ dputn %a0
+ dputc '\n'
+
+func_return get_new_page
+
+
+
/*
* Debug output support
* Atarians have a choice between the parallel port, the serial port
* from the MFP or a serial port of the SCC
*/
+#ifdef CONFIG_MAC
+
+L(scc_initable_mac):
+ .byte 9,12 /* Reset */
+ .byte 4,0x44 /* x16, 1 stopbit, no parity */
+ .byte 3,0xc0 /* receiver: 8 bpc */
+ .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */
+ .byte 9,0 /* no interrupts */
+ .byte 10,0 /* NRZ */
+ .byte 11,0x50 /* use baud rate generator */
+ .byte 12,10,13,0 /* 9600 baud */
+ .byte 14,1 /* Baud rate generator enable */
+ .byte 3,0xc1 /* enable receiver */
+ .byte 5,0xea /* enable transmitter */
+ .byte -1
+ .even
+#endif
+
#ifdef CONFIG_ATARI
/* #define USE_PRINTER */
-/* #define USE_SCC */
+/* #define USE_SCC_B */
+/* #define USE_SCC_A */
#define USE_MFP
+#if defined(USE_SCC_A) || defined(USE_SCC_B)
+#define USE_SCC
+/* Initialisation table for SCC */
+L(scc_initable):
+ .byte 9,12 /* Reset */
+ .byte 4,0x44 /* x16, 1 stopbit, no parity */
+ .byte 3,0xc0 /* receiver: 8 bpc */
+ .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */
+ .byte 9,0 /* no interrupts */
+ .byte 10,0 /* NRZ */
+ .byte 11,0x50 /* use baud rate generator */
+ .byte 12,24,13,0 /* 9600 baud */
+ .byte 14,2,14,3 /* use master clock for BRG, enable */
+ .byte 3,0xc1 /* enable receiver */
+ .byte 5,0xea /* enable transmitter */
+ .byte -1
+ .even
+#endif
+
#ifdef USE_PRINTER
LPSG_SELECT = 0xff8800
@@ -1129,13 +2554,18 @@ LSTMFP_GPIP = 0xfffa01
LSTMFP_DDR = 0xfffa05
LSTMFP_IERB = 0xfffa09
-#elif defined(USE_SCC)
-
-LSCC_CTRL_B = 0xff8c85
-LSCC_DATA_B = 0xff8c87
+#elif defined(USE_SCC_B)
+
+LSCC_CTRL = 0xff8c85
+LSCC_DATA = 0xff8c87
+
+#elif defined(USE_SCC_A)
+
+LSCC_CTRL = 0xff8c81
+LSCC_DATA = 0xff8c83
/* Initialisation table for SCC */
-scc_initable:
+L(scc_initable):
.byte 9,12 /* Reset */
.byte 4,0x44 /* x16, 1 stopbit, no parity */
.byte 3,0xc0 /* receiver: 8 bpc */
@@ -1159,45 +2589,48 @@ LMFP_TSR = 0xfffa2d
LMFP_UDR = 0xfffa2f
#endif
-#endif
-
-#if defined (CONFIG_BVME6000)
-BVME_SCC_CTRL_A = 0xffb0000b
-BVME_SCC_DATA_A = 0xffb0000f
-#endif
+#endif /* CONFIG_ATARI */
/*
* Serial port output support.
*/
-LSERPER = 0xdff032
-LSERDAT = 0xdff030
-LSERDATR = 0xdff018
-LSERIAL_CNTRL = 0xbfd000
-LSERIAL_DTR = 7
/*
* Initialize serial port hardware for 9600/8/1
- * a0 thrashed
- * Amiga d0 trashed
- * Atari d0 trashed (a1 in case of SCC)
*/
- .even
-Lserial_init:
+func_start serial_init,%d0/%d1/%a0/%a1
+ /*
+ * Some of the register usage that follows
+ * CONFIG_AMIGA
+ * a0 = pointer to boot info record
+ * d0 = boot info offset
+ * CONFIG_ATARI
+ * a0 = address of SCC
+ * a1 = Liobase address/address of scc_initable
+ * d0 = init data for serial port
+ * CONFIG_MAC
+ * a0 = address of SCC
+ * a1 = address of scc_initable_mac
+ * d0 = init data for serial port
+ */
+
#ifdef CONFIG_AMIGA
- cmpil #MACH_AMIGA,%d4
- jne 1f
- bclr #LSERIAL_DTR,LSERIAL_CNTRL
- movew #BI_AMIGA_SERPER,%d0
- jbsr Lget_bi_record
- movew %a0@,LSERPER
- jra 9f
+#define SERIAL_DTR 7
+#define SERIAL_CNTRL CIABBASE+C_PRA
+
+ is_not_amiga(1f)
+ lea %pc@(L(custom)),%a0
+ movel #-ZTWOBASE,%a0@
+ bclr #SERIAL_DTR,SERIAL_CNTRL-ZTWOBASE
+ get_bi_record BI_AMIGA_SERPER
+ movew %a0@,CUSTOMBASE+C_SERPER-ZTWOBASE
+| movew #61,CUSTOMBASE+C_SERPER-ZTWOBASE
1:
#endif
#ifdef CONFIG_ATARI
- cmpil #MACH_ATARI,%d4
- jne 4f
- movel %pc@(Liobase),%a1
-#ifdef USE_PRINTER
+ is_not_atari(4f)
+ movel %pc@(L(iobase)),%a1
+#if defined(USE_PRINTER)
bclr #0,%a1@(LSTMFP_IERB)
bclr #0,%a1@(LSTMFP_DDR)
moveb #LPSG_CONTROL,%a1@(LPSG_SELECT)
@@ -1209,8 +2642,8 @@ Lserial_init:
bset #5,%d0
moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC)
- lea %a1@(LSCC_CTRL_B),%a0
- lea %pc@(scc_initable:w),%a1
+ lea %a1@(LSCC_CTRL),%a0
+ lea %pc@(L(scc_initable)),%a1
2: moveb %a1@+,%d0
jmi 3f
moveb %d0,%a0@
@@ -1225,174 +2658,854 @@ Lserial_init:
orb #1,%a1@(LMFP_TDCDR)
bset #1,%a1@(LMFP_TSR)
#endif
+ jra L(serial_init_done)
4:
#endif
-9:
- rts
-
-#ifdef CONFIG_HP300
-/* Set LEDs to %d7 */
- .even
-Lset_leds:
- moveml %a0/%a1,%sp@-
- movel %pc@(Lcustom),%a1
- moveb %d7,%a1@(0x1ffff)
- moveml %sp@+,%a0/%a1
- rts
+#ifdef CONFIG_MAC
+ is_not_mac(L(serial_init_not_mac))
+#ifdef MAC_SERIAL_DEBUG
+#if !defined(MAC_USE_SCC_A) && !defined(MAC_USE_SCC_B)
+#define MAC_USE_SCC_B
#endif
-
+#define mac_scc_cha_b_ctrl_offset 0x0
+#define mac_scc_cha_a_ctrl_offset 0x2
+#define mac_scc_cha_b_data_offset 0x4
+#define mac_scc_cha_a_data_offset 0x6
+
+#ifdef MAC_USE_SCC_A
+ /* Initialize channel A */
+ movel %pc@(L(mac_sccbase)),%a0
+ lea %pc@(L(scc_initable_mac)),%a1
+5: moveb %a1@+,%d0
+ jmi 6f
+ moveb %d0,%a0@(mac_scc_cha_a_ctrl_offset)
+ moveb %a1@+,%a0@(mac_scc_cha_a_ctrl_offset)
+ jra 5b
+6:
+#endif /* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+ /* Initialize channel B */
+#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */
+ movel %pc@(L(mac_sccbase)),%a0
+#endif /* MAC_USE_SCC_A */
+ lea %pc@(L(scc_initable_mac)),%a1
+7: moveb %a1@+,%d0
+ jmi 8f
+ moveb %d0,%a0@(mac_scc_cha_b_ctrl_offset)
+ moveb %a1@+,%a0@(mac_scc_cha_b_ctrl_offset)
+ jra 7b
+8:
+#endif /* MAC_USE_SCC_B */
+#endif /* MAC_SERIAL_DEBUG */
+
+ jra L(serial_init_done)
+L(serial_init_not_mac):
+#endif /* CONFIG_MAC */
+
+L(serial_init_done):
+func_return serial_init
+
/*
- * Output character in d7 on serial port.
- * d7 thrashed.
+ * Output character on serial port.
*/
-Lserial_putc:
- moveml %a0/%a1,%sp@-
-#if defined(CONFIG_MVME16x)
- cmpil #MACH_MVME16x,%d4
- jne 2f
- moveb %d7,%sp@-
- .long 0x4e4f0020
- jra 9f
-2:
-#endif
-#ifdef CONFIG_BVME6000
- cmpil #MACH_BVME6000,%d4
- jne 2f
-1: btst #2,BVME_SCC_CTRL_A
- jeq 1b
- moveb %d7,BVME_SCC_DATA_A
- jra 9f
-2:
-#endif
+func_start serial_putc,%d0/%d1/%a0/%a1
+
+ movel ARG1,%d0
+ cmpib #'\n',%d0
+ jbne 1f
+
+ /* A little safe recursion is good for the soul */
+ serial_putc #'\r'
+1:
+
#ifdef CONFIG_AMIGA
- cmpil #MACH_AMIGA,%d4
- jne 2f
- andw #0x00ff,%d7
- oriw #0x0100,%d7
- movel %pc@(Lcustom),%a1
- movew %d7,%a1@(LSERDAT)
-1: movew %a1@(LSERDATR),%d7
- andw #0x2000,%d7
+ is_not_amiga(2f)
+ andw #0x00ff,%d0
+ oriw #0x0100,%d0
+ movel %pc@(L(custom)),%a0
+ movew %d0,%a0@(CUSTOMBASE+C_SERDAT)
+1: movew %a0@(CUSTOMBASE+C_SERDATR),%d0
+ andw #0x2000,%d0
jeq 1b
- jra 9f
+ jra L(serial_putc_done)
2:
#endif
+
+#ifdef CONFIG_MAC
+ is_not_mac(5f)
+
+#ifdef CONSOLE
+ console_putc %d0
+#endif /* CONSOLE */
+
+#ifdef MAC_SERIAL_DEBUG
+
+#ifdef MAC_USE_SCC_A
+ movel %pc@(L(mac_sccbase)),%a1
+3: btst #2,%a1@(mac_scc_cha_a_ctrl_offset)
+ jeq 3b
+ moveb %d0,%a1@(mac_scc_cha_a_data_offset)
+#endif /* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */
+ movel %pc@(L(mac_sccbase)),%a1
+#endif /* MAC_USE_SCC_A */
+4: btst #2,%a1@(mac_scc_cha_b_ctrl_offset)
+ jeq 4b
+ moveb %d0,%a1@(mac_scc_cha_b_data_offset)
+#endif /* MAC_USE_SCC_B */
+
+#endif /* MAC_SERIAL_DEBUG */
+
+ jra L(serial_putc_done)
+5:
+#endif /* CONFIG_MAC */
+
#ifdef CONFIG_ATARI
- cmpil #MACH_ATARI,%d4
- jne 4f
- movel %pc@(Liobase),%a1
-#ifdef USE_PRINTER
+ is_not_atari(4f)
+ movel %pc@(L(iobase)),%a1
+#if defined(USE_PRINTER)
3: btst #0,%a1@(LSTMFP_GPIP)
jne 3b
moveb #LPSG_IO_B,%a1@(LPSG_SELECT)
- moveb %d7,%a1@(LPSG_WRITE)
+ moveb %d0,%a1@(LPSG_WRITE)
moveb #LPSG_IO_A,%a1@(LPSG_SELECT)
- moveb %a1@(LPSG_READ),%d7
- bclr #5,%d7
- moveb %d7,%a1@(LPSG_WRITE)
+ moveb %a1@(LPSG_READ),%d0
+ bclr #5,%d0
+ moveb %d0,%a1@(LPSG_WRITE)
nop
nop
- bset #5,%d7
- moveb %d7,%a1@(LPSG_WRITE)
+ bset #5,%d0
+ moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC)
-3: btst #2,%a1@(LSCC_CTRL_B)
+3: btst #2,%a1@(LSCC_CTRL)
jeq 3b
- moveb %d7,%a1@(LSCC_DATA_B)
+ moveb %d0,%a1@(LSCC_DATA)
#elif defined(USE_MFP)
3: btst #7,%a1@(LMFP_TSR)
jeq 3b
- moveb %d7,%a1@(LMFP_UDR)
+ moveb %d0,%a1@(LMFP_UDR)
#endif
+ jra L(serial_putc_done)
4:
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_MVME16x
+ is_not_mvme16x(2f)
+ /*
+ * The VME 16x class has PROM support for serial output
+ * of some kind; the TRAP table is still valid.
+ */
+ moveml %d0-%d7/%a2-%a6,%sp@-
+ moveb %d0,%sp@-
+ trap #15
+ .word 0x0020 /* TRAP 0x020 */
+ moveml %sp@+,%d0-%d7/%a2-%a6
+ jbra L(serial_putc_done)
+2:
+#endif CONFIG_MVME162 | CONFIG_MVME167
+
+#ifdef CONFIG_BVME6000
+ is_not_bvme6000(2f)
+ /*
+ * The BVME6000 machine has a serial port ...
+ */
+1: btst #2,BVME_SCC_CTRL_A
+ jeq 1b
+ moveb %d0,BVME_SCC_DATA_A
+ jbra L(serial_putc_done)
+2:
+#endif
+
+L(serial_putc_done):
+func_return serial_putc
+
+/*
+ * Output a string.
+ */
+func_start puts,%d0/%a0
+
+ movel ARG1,%a0
+ jra 2f
+1:
+#ifdef CONSOLE
+ console_putc %d0
+#endif
+#ifdef SERIAL_DEBUG
+ serial_putc %d0
+#endif
+2: moveb %a0@+,%d0
+ jne 1b
+
+func_return puts
+
+/*
+ * Output number in hex notation.
+ */
+
+func_start putn,%d0-%d2
+
+ putc ' '
+
+ movel ARG1,%d0
+ moveq #7,%d1
+1: roll #4,%d0
+ move %d0,%d2
+ andb #0x0f,%d2
+ addb #'0',%d2
+ cmpb #'9',%d2
+ jls 2f
+ addb #'A'-('9'+1),%d2
+2:
+#ifdef CONSOLE
+ console_putc %d2
+#endif
+#ifdef SERIAL_DEBUG
+ serial_putc %d2
#endif
-9:
- moveml %sp@+,%a0/%a1
+ dbra %d1,1b
+
+func_return putn
+
+#ifdef CONFIG_MAC
+/*
+ * mac_serial_print
+ *
+ * This routine takes its parameters on the stack. It then
+ * turns around and calls the internal routine. This routine
+ * is used until the Linux console driver initializes itself.
+ *
+ * The calling parameters are:
+ * void mac_serial_print(const char *str);
+ *
+ * This routine does NOT understand variable arguments only
+ * simple strings!
+ */
+ENTRY(mac_serial_print)
+ moveml %d0/%a0,%sp@-
+#if 1
+ move %sr,%sp@-
+ ori #0x0700,%sr
+#endif
+ movel %sp@(10),%a0 /* fetch parameter */
+ jra 2f
+1: serial_putc %d0
+2: moveb %a0@+,%d0
+ jne 1b
+#if 1
+ move %sp@+,%sr
+#endif
+ moveml %sp@+,%d0/%a0
rts
+#endif /* CONFIG_MAC */
+
+#ifdef CONFIG_HP300
+func_start set_leds,%d0/%a0
+ movel ARG1,%d0
+ movel %pc@(Lcustom),%a0
+ moveb %d0,%a0@(0x1ffff)
+func_return set_leds
+#endif
+#ifdef CONSOLE
/*
- * Output string pointed to by a0 to serial port.
- * a0 trashed.
+ * For continuity, see the data alignment
+ * to which this structure is tied.
*/
-Lserial_puts:
- movel %d7,%sp@-
-1: moveb %a0@+,%d7
- jeq 2f
- jbsr Lserial_putc
- jra 1b
-2: movel %sp@+,%d7
+#define Lconsole_struct_cur_column 0
+#define Lconsole_struct_cur_row 4
+#define Lconsole_struct_num_columns 8
+#define Lconsole_struct_num_rows 12
+#define Lconsole_struct_left_edge 16
+#define Lconsole_struct_penguin_putc 20
+
+L(console_init):
+ /*
+ * Some of the register usage that follows
+ * a0 = pointer to boot_info
+ * a1 = pointer to screen
+ * a2 = pointer to Lconsole_globals
+ * d3 = pixel width of screen
+ * d4 = pixel height of screen
+ * (d3,d4) ~= (x,y) of a point just below
+ * and to the right of the screen
+ * NOT on the screen!
+ * d5 = number of bytes per scan line
+ * d6 = number of bytes on the entire screen
+ */
+ moveml %a0-%a4/%d0-%d7,%sp@-
+
+ lea %pc@(L(console_globals)),%a2
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d5
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d3 /* -> low byte */
+ movel %d3,%d4
+ swap %d4 /* -> high byte */
+ andl #0xffff,%d3 /* d3 = screen width in pixels */
+ andl #0xffff,%d4 /* d4 = screen height in pixels */
+
+ movel %d5,%d6
+ subl #20,%d6
+ mulul %d4,%d6 /* scan line bytes x num scan lines */
+ divul #8,%d6 /* we'll clear 8 bytes at a time */
+ subq #1,%d6
+
+console_clear_loop:
+ movel #0xffffffff,%a1@+ /* Mac_black */
+ movel #0xffffffff,%a1@+ /* Mac_black */
+ dbra %d6,console_clear_loop
+
+ /* Calculate font size */
+
+#if defined(FONT_8x8)
+ lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#elif defined(FONT_8x16)
+ lea %pc@(SYMBOL_NAME(font_vga_8x16)),%a0
+#elif defined(FONT_6x11)
+ lea %pc@(SYMBOL_NAME(font_vga_6x11)),%a0
+#else /* (FONT_8x8) default */
+ lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#endif
+
+ /*
+ * At this point we make a shift in register usage
+ * a1 = address of Lconsole_font pointer
+ */
+ lea %pc@(L(console_font)),%a1
+ movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */
+
+ /*
+ * Calculate global maxs
+ * Note - we can use either an
+ * 8 x 16 or 8 x 8 character font
+ * 6 x 11 also supported
+ */
+ /* ASSERT: a0 = contents of Lconsole_font */
+ movel %d3,%d0 /* screen width in pixels */
+ divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */
+
+ movel %d4,%d1 /* screen height in pixels */
+ divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */
+
+ movel %d0,%a2@(Lconsole_struct_num_columns)
+ movel %d1,%a2@(Lconsole_struct_num_rows)
+
+ /*
+ * Clear the current row and column
+ */
+ clrl %a2@(Lconsole_struct_cur_column)
+ clrl %a2@(Lconsole_struct_cur_row)
+ clrl %a2@(Lconsole_struct_left_edge)
+
+ /*
+ * Initialization is complete
+ */
+ moveml %sp@+,%a0-%a4/%d0-%d7
+ rts
+
+L(console_put_stats):
+ /*
+ * Some of the register usage that follows
+ * a0 = pointer to boot_info
+ * d7 = value of boot_info fields
+ */
+ moveml %a0/%d7,%sp@-
+
+ puts "\nMacLinux\n\n"
+
+#ifdef SERIAL_DEBUG
+ puts " vidaddr:"
+ putn %pc@(L(mac_videobase)) /* video addr. */
+
+ puts "\n _stext:"
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ putn %a0
+
+ puts "\nbootinfo:"
+ lea %pc@(SYMBOL_NAME(_end)),%a0
+ putn %a0
+
+ puts "\ncpuid:"
+ putn %pc@(L(cputype))
+ putc '\n'
+
+# if defined(MMU_PRINT)
+ jbsr mmu_print_machine_cpu_types
+# endif /* MMU_PRINT */
+#endif /* SERIAL_DEBUG */
+
+ moveml %sp@+,%a0/%d7
+ rts
+
+#ifdef CONSOLE_PENGUIN
+L(console_put_penguin):
+ /*
+ * Get 'that_penguin' onto the screen in the upper right corner
+ * penguin is 64 x 74 pixels, align against right edge of screen
+ */
+ moveml %a0-%a1/%d0-%d7,%sp@-
+
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d0
+ andil #0xffff,%d0
+ subil #64,%d0 /* snug up against the right edge */
+ clrl %d1 /* start at the top */
+ movel #73,%d7
+ lea %pc@(SYMBOL_NAME(that_penguin)),%a1
+console_penguin_row:
+ movel #31,%d6
+console_penguin_pixel_pair:
+ moveb %a1@,%d2
+ lsrb #4,%d2
+ jbsr console_plot_pixel
+ addq #1,%d0
+ moveb %a1@+,%d2
+ jbsr console_plot_pixel
+ addq #1,%d0
+ dbra %d6,console_penguin_pixel_pair
+
+ subil #64,%d0
+ addq #1,%d1
+ dbra %d7,console_penguin_row
+
+ moveml %sp@+,%a0-%a1/%d0-%d7
+ rts
+#endif
+
+console_scroll:
+ moveml %a0-%a4/%d0-%d7,%sp@-
+
+ /*
+ * Calculate source and destination addresses
+ * output a1 = dest
+ * a2 = source
+ */
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ movel %a1,%a2
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d5
+ movel %pc@(L(console_font)),%a0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */
+ addal %d5,%a2
+
+ /*
+ * Get dimensions
+ */
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d3
+ movel %d3,%d4
+ swap %d4
+ andl #0xffff,%d3 /* d3 = screen width in pixels */
+ andl #0xffff,%d4 /* d4 = screen height in pixels */
+
+ /*
+ * Calculate number of bytes to move
+ */
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d6
+ movel %pc@(L(console_font)),%a0
+ subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */
+ mulul %d4,%d6 /* scan line bytes x num scan lines */
+ divul #32,%d6 /* we'll move 8 longs at a time */
+ subq #1,%d6
+
+console_scroll_loop:
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ dbra %d6,console_scroll_loop
+
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d6
+ movel %pc@(L(console_font)),%a0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */
+ divul #32,%d6 /* we'll move 8 words at a time */
+ subq #1,%d6
+
+ moveq #-1,%d0
+console_scroll_clear_loop:
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ dbra %d6,console_scroll_clear_loop
+
+ moveml %sp@+,%a0-%a4/%d0-%d7
rts
+
+func_start console_putc,%a0/%a1/%d0-%d7
+
+ is_not_mac(console_exit)
+
+ /* Output character in d7 on console.
+ */
+ movel ARG1,%d7
+ cmpib #'\n',%d7
+ jbne 1f
+
+ /* A little safe recursion is good for the soul */
+ console_putc #'\r'
+1:
+ lea %pc@(L(console_globals)),%a0
+
+ cmpib #10,%d7
+ jne console_not_lf
+ movel %a0@(Lconsole_struct_cur_row),%d0
+ addil #1,%d0
+ movel %d0,%a0@(Lconsole_struct_cur_row)
+ movel %a0@(Lconsole_struct_num_rows),%d1
+ cmpl %d1,%d0
+ jcs 1f
+ subil #1,%d0
+ movel %d0,%a0@(Lconsole_struct_cur_row)
+ jbsr console_scroll
+1:
+ jra console_exit
+
+console_not_lf:
+ cmpib #13,%d7
+ jne console_not_cr
+ clrl %a0@(Lconsole_struct_cur_column)
+ jra console_exit
+
+console_not_cr:
+ cmpib #1,%d7
+ jne console_not_home
+ clrl %a0@(Lconsole_struct_cur_row)
+ clrl %a0@(Lconsole_struct_cur_column)
+ jra console_exit
+
/*
- * Output number in d7 in hex notation on serial port.
+ * At this point we know that the %d7 character is going to be
+ * rendered on the screen. Register usage is -
+ * a0 = pointer to console globals
+ * a1 = font data
+ * d0 = cursor column
+ * d1 = cursor row to draw the character
+ * d7 = character number
*/
+console_not_home:
+ movel %a0@(Lconsole_struct_cur_column),%d0
+ addil #1,%a0@(Lconsole_struct_cur_column)
+ movel %a0@(Lconsole_struct_num_columns),%d1
+ cmpl %d1,%d0
+ jcs 1f
+ putc '\n' /* recursion is OK! */
+1:
+ movel %a0@(Lconsole_struct_cur_row),%d1
-Lserial_putnum:
- moveml %d0-%d2/%d7,%sp@-
- movel %d7,%d1
- moveq #4,%d0
- moveq #7,%d2
-L1: roll %d0,%d1
- moveb %d1,%d7
- andb #0x0f,%d7
- cmpb #0x0a,%d7
- jcc 1f
- addb #'0',%d7
- jra 2f
-1: addb #'A'-10,%d7
-2: jbsr Lserial_putc
- dbra %d2,L1
- moveq #32,%d7
- jbsr Lserial_putc
- moveml %sp@+,%d0-%d2/%d7
+ /*
+ * At this point we make a shift in register usage
+ * a0 = address of pointer to font data (fbcon_font_desc)
+ */
+ movel %pc@(L(console_font)),%a0
+ movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */
+ andl #0x000000ff,%d7
+ /* ASSERT: a0 = contents of Lconsole_font */
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */
+ addl %d7,%a1 /* a1 = points to char image */
+
+ /*
+ * At this point we make a shift in register usage
+ * d0 = pixel coordinate, x
+ * d1 = pixel coordinate, y
+ * d2 = (bit 0) 1/0 for white/black (!) pixel on screen
+ * d3 = font scan line data (8 pixels)
+ * d6 = count down for the font's pixel width (8)
+ * d7 = count down for the font's pixel count in height
+ */
+ /* ASSERT: a0 = contents of Lconsole_font */
+ mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1
+ movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */
+ subq #1,%d7
+console_read_char_scanline:
+ moveb %a1@+,%d3
+
+ /* ASSERT: a0 = contents of Lconsole_font */
+ movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */
+ subql #1,%d6
+
+console_do_font_scanline:
+ lslb #1,%d3
+ scsb %d2 /* convert 1 bit into a byte */
+ jbsr console_plot_pixel
+ addq #1,%d0
+ dbra %d6,console_do_font_scanline
+
+ /* ASSERT: a0 = contents of Lconsole_font */
+ subl %a0@(FBCON_FONT_DESC_WIDTH),%d0
+ addq #1,%d1
+ dbra %d7,console_read_char_scanline
+
+console_exit:
+
+func_return console_putc
+
+console_plot_pixel:
+ /*
+ * Input:
+ * d0 = x coordinate
+ * d1 = y coordinate
+ * d2 = (bit 0) 1/0 for white/black (!)
+ * All registers are preserved
+ */
+ moveml %a0-%a1/%d0-%d4,%sp@-
+
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_videodepth)),%a0
+ movel %a0@,%d3
+ lea %pc@(L(mac_rowbytes)),%a0
+ mulul %a0@,%d1
+
+ /*
+ * Register usage:
+ * d0 = x coord becomes byte offset into frame buffer
+ * d1 = y coord
+ * d2 = black or white (0/1)
+ * d3 = video depth
+ * d4 = temp of x (d0) for many bit depths
+ * d5 = unused
+ * d6 = unused
+ * d7 = unused
+ */
+test_1bit:
+ cmpb #1,%d3
+ jbne test_2bit
+ movel %d0,%d4 /* we need the low order 3 bits! */
+ divul #8,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #7,%d4
+ eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */
+ andb #1,%d2
+ jbne white_1
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_1:
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_2bit:
+ cmpb #2,%d3
+ jbne test_4bit
+ movel %d0,%d4 /* we need the low order 2 bits! */
+ divul #4,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #3,%d4
+ eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */
+ lsll #1,%d4 /* ! */
+ andb #1,%d2
+ jbne white_2
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_2:
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_4bit:
+ cmpb #4,%d3
+ jbne test_8bit
+ movel %d0,%d4 /* we need the low order bit! */
+ divul #2,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d4
+ eorb #1,%d4
+ lsll #2,%d4 /* ! */
+ andb #1,%d2
+ jbne white_4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_4:
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_8bit:
+ cmpb #8,%d3
+ jbne test_16bit
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d2
+ jbne white_8
+ moveb #0xff,%a1@
+ jbra console_plot_pixel_exit
+white_8:
+ clrb %a1@
+ jbra console_plot_pixel_exit
+
+test_16bit:
+ cmpb #16,%d3
+ jbne console_plot_pixel_exit
+ addal %d0,%a1
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d2
+ jbne white_16
+ clrw %a1@
+ jbra console_plot_pixel_exit
+white_16:
+ movew #0x0fff,%a1@
+ jbra console_plot_pixel_exit
+
+console_plot_pixel_exit:
+ moveml %sp@+,%a0-%a1/%d0-%d4
rts
+#endif /* CONSOLE */
#if 0
-Lshowtest:
+/*
+ * This is some old code lying around. I don't believe
+ * it's used or important anymore. My guess is it contributed
+ * to getting to this point, but it's done for now.
+ * It was still in the 2.1.77 head.S, so it's still here.
+ * (And still not used!)
+ */
+L(showtest):
moveml %a0/%d7,%sp@-
- putc('A')
- putc('=')
- putn(%a1)
+ puts "A="
+ putn %a1
- ptestr #5,%a1@,#7,%a0
+ .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0
- putc('D')
- putc('A')
- putc('=')
- putn(%a0)
+ puts "DA="
+ putn %a0
- putc('D')
- putc('=')
- putn(%a0@)
+ puts "D="
+ putn %a0@
- putc('S')
- putc('=')
- lea %pc@(Lmmu),%a0
- pmove %psr,%a0@
+ puts "S="
+ lea %pc@(L(mmu)),%a0
+ .long 0xf0106200 | pmove %psr,%a0@
clrl %d7
movew %a0@,%d7
- jbsr Lserial_putnum
+ putn %d7
- putr()
+ putc '\n'
moveml %sp@+,%a0/%d7
rts
+#endif /* 0 */
+
+__INITDATA
+ .align 4
+
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || defined(CONFIG_HP300)
+L(custom):
+L(iobase):
+ .long 0
+#endif
+
+#ifdef CONFIG_MAC
+L(console_video_virtual):
+ .long 0
+#endif /* CONFIG_MAC */
+
+#if defined(CONSOLE)
+L(console_globals):
+ .long 0 /* cursor column */
+ .long 0 /* cursor row */
+ .long 0 /* max num columns */
+ .long 0 /* max num rows */
+ .long 0 /* left edge */
+ .long 0 /* mac putc */
+L(console_font):
+ .long 0 /* pointer to console font (struct fbcon_font_desc) */
+#endif /* CONSOLE */
+
+#if defined(MMU_PRINT)
+L(mmu_print_data):
+ .long 0 /* valid flag */
+ .long 0 /* start logical */
+ .long 0 /* next logical */
+ .long 0 /* start physical */
+ .long 0 /* next physical */
+#endif /* MMU_PRINT */
+
+L(cputype):
+ .long 0
+L(mmu_cached_pointer_tables):
+ .long 0
+L(mmu_num_pointer_tables):
+ .long 0
+L(phys_kernel_start):
+ .long 0
+L(kernel_end):
+ .long 0
+L(memory_start):
+ .long 0
+L(kernel_pgdir_ptr):
+ .long 0
+L(temp_mmap_mem):
+ .long 0
+
+
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
+#if defined(CONFIG_MAC)
+L(mac_booter_data):
+ .long 0
+L(mac_videobase):
+ .long 0
+L(mac_videodepth):
+ .long 0
+L(mac_dimensions):
+ .long 0
+L(mac_rowbytes):
+ .long 0
+#ifdef MAC_SERIAL_DEBUG
+L(mac_sccbase):
+ .long 0
+#endif /* MAC_SERIAL_DEBUG */
#endif
+
+__FINIT
.data
- .even
-Lcustom:
-Liobase:
- .long 0
-Lmmu: .quad 0
-SYMBOL_NAME_LABEL(kpt)
- .long 0
+ .align 4
+
SYMBOL_NAME_LABEL(availmem)
- .long 0
+ .long 0
SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
- .long 0
-#ifdef CONFIG_060_WRITETHROUGH
+ .long 0
SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
- .long 0
-#endif
+ .long 0
#if defined(CONFIG_MVME16x)
SYMBOL_NAME_LABEL(mvme_bdid_ptr)
- .long 0
+ .long 0
#endif
diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c
index 122bf63be..e2e6715e7 100644
--- a/arch/m68k/kernel/m68k_defs.c
+++ b/arch/m68k/kernel/m68k_defs.c
@@ -10,14 +10,78 @@
#include <linux/stddef.h>
#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <video/font.h>
#define DEFINE(sym, val) \
- asm volatile("\n#define " #sym " %0" : : "i" (val))
+ asm volatile("\n#define " #sym " %c0" : : "i" (val))
int main(void)
{
- DEFINE(TS_TSS, offsetof(struct task_struct, tss));
- DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0));
- DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp));
+ /* offsets into the task struct */
+ DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
+ DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
+ DEFINE(TASK_TSS, offsetof(struct task_struct, tss));
+ DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+
+ /* offsets into the thread struct */
+ DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(TSS_USP, offsetof(struct thread_struct, usp));
+ DEFINE(TSS_SR, offsetof(struct thread_struct, sr));
+ DEFINE(TSS_FS, offsetof(struct thread_struct, fs));
+ DEFINE(TSS_CRP, offsetof(struct thread_struct, crp));
+ DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0));
+ DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp));
+ DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl));
+ DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+ /* offsets into the pt_regs */
+ DEFINE(PT_D0, offsetof(struct pt_regs, d0));
+ DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+ DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+
+ /* bitfields are a bit difficult */
+ DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+
+ /* offsets into the irq_handler struct */
+ DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
+ DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
+ DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
+
+ /* offsets into the kernel_stat struct */
+ DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
+
+ /* offsets into the bi_record struct */
+ DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+ DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+ DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+ /* offsets into fbcon_font_desc (video/font.h) */
+ DEFINE(FBCON_FONT_DESC_IDX, offsetof(struct fbcon_font_desc, idx));
+ DEFINE(FBCON_FONT_DESC_NAME, offsetof(struct fbcon_font_desc, name));
+ DEFINE(FBCON_FONT_DESC_WIDTH, offsetof(struct fbcon_font_desc, width));
+ DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height));
+ DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data));
+ DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref));
+
+ /* offsets into the custom struct */
+ DEFINE(CUSTOMBASE, &custom);
+ DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+ DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+ DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+ DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+ DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+ DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+ DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+ DEFINE(CIAABASE, &ciaa);
+ DEFINE(CIABBASE, &ciab);
+ DEFINE(C_PRA, offsetof(struct CIA, pra));
+ DEFINE(ZTWOBASE, zTwoBase);
+
return 0;
}
diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h
index 992d390c7..b32e6a1c9 100644
--- a/arch/m68k/kernel/m68k_defs.h
+++ b/arch/m68k/kernel/m68k_defs.h
@@ -3,6 +3,6 @@
*/
#define TS_MAGICKEY 0x5a5a5a5a
-#define TS_TSS 478
-#define TS_ESP0 498
-#define TS_FPU 502
+#define TS_TSS 482
+#define TS_ESP0 502
+#define TS_FPU 506
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 40b692e0c..793ca6ec7 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -13,6 +13,7 @@
#include <asm/machdep.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
+#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/checksum.h>
#include <asm/hardirq.h>
@@ -37,8 +38,10 @@ EXPORT_SYMBOL(mm_ptov);
EXPORT_SYMBOL(mm_end_of_chunk);
#endif
EXPORT_SYMBOL(mm_vtop_fallback);
+EXPORT_SYMBOL(m68k_realnum_memory);
EXPORT_SYMBOL(m68k_memory);
-EXPORT_SYMBOL(kernel_map);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(m68k_debug_device);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(dump_thread);
@@ -49,6 +52,8 @@ EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_set_cachemode);
+EXPORT_SYMBOL(kernel_thread);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index fb9bac400..c7c3f458e 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -56,16 +56,13 @@ asmlinkage void ret_from_exception(void);
*/
asmlinkage int sys_idle(void)
{
- int ret = -EPERM;
-
- lock_kernel();
if (current->pid != 0)
- goto out;
+ return -EPERM;
/* endless idle loop with no priority at all */
- current->priority = -100;
+ current->priority = 0;
current->counter = -100;
- for (;;){
+ for (;;) {
if (!current->need_resched)
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
@@ -73,14 +70,9 @@ asmlinkage int sys_idle(void)
#else /* portable version */
__asm__("stop #0x2000" : : : "cc");
#endif /* machine compilation types */
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
schedule();
+ check_pgt_cache();
}
- ret = 0;
-out:
- unlock_kernel();
- return ret;
}
void machine_restart(char * __unused)
@@ -115,6 +107,44 @@ void show_regs(struct pt_regs * regs)
printk("USP: %08lx\n", rdusp());
}
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ int pid;
+ mm_segment_t fs;
+
+ fs = get_fs();
+ set_fs (KERNEL_DS);
+
+ {
+ register long retval __asm__ ("d0");
+ register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+
+ __asm__ __volatile__
+ ("clrl %%d2\n\t"
+ "trap #0\n\t" /* Linux/m68k system call */
+ "tstl %0\n\t" /* child or parent */
+ "jne 1f\n\t" /* parent - jump */
+ "lea %%sp@(-8192),%6\n\t" /* reload current */
+ "movel %3,%%sp@-\n\t" /* push argument */
+ "jsr %4@\n\t" /* call fn */
+ "movel %0,%%d1\n\t" /* pass exit value */
+ "movel %2,%0\n\t" /* exit */
+ "trap #0\n"
+ "1:"
+ : "=d" (retval)
+ : "0" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
+ : "d0", "d2");
+ pid = retval;
+ }
+
+ set_fs (fs);
+ return pid;
+}
+
void flush_thread(void)
{
unsigned long zero = 0;
@@ -137,6 +167,19 @@ asmlinkage int m68k_fork(struct pt_regs *regs)
return do_fork(SIGCHLD, rdusp(), regs);
}
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+ int child;
+ struct semaphore sem = MUTEX_LOCKED;
+
+ child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
+
+ if (child > 0)
+ down(&sem);
+
+ return child;
+}
+
asmlinkage int m68k_clone(struct pt_regs *regs)
{
unsigned long clone_flags;
@@ -147,7 +190,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
newsp = regs->d2;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags, newsp, regs);
+ return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 9888d83c1..5aeb2534b 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -325,12 +325,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = 0;
goto out;
}
- if (pid == 1) /* you may not mess with init */
- goto out;
ret = -ESRCH;
- if (!(child = find_task_by_pid(pid)))
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!!! */
+ if (!child)
goto out;
ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
@@ -375,7 +378,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
ret = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (ret >= 0)
ret = put_user(tmp, (unsigned long *) data);
goto out;
@@ -408,7 +413,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
ret = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index e12786344..ade12c46d 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -48,6 +48,7 @@ extern int end;
extern unsigned long availmem;
int m68k_num_memory = 0;
+int m68k_realnum_memory = 0;
struct mem_info m68k_memory[NUM_MEMINFO];
static struct mem_info m68k_ramdisk = { 0, 0 };
@@ -62,8 +63,6 @@ void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initd
int (*mach_keyb_init) (void) __initdata;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
-/* machine dependent "kbd-reset" setup function */
-void (*kbd_reset_setup) (char *, int) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -159,6 +158,7 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
record = (struct bi_record *)((u_long)record+record->size);
}
+ m68k_realnum_memory = m68k_num_memory;
#ifdef CONFIG_SINGLE_MEMORY_CHUNK
if (m68k_num_memory > 1) {
printk("Ignoring last %i chunks of physical memory\n",
@@ -398,9 +398,9 @@ void floppy_eject(void)
}
#endif
-__initfunc(unsigned long arch_kbd_init(void))
+/* for "kbd-reset" cmdline param */
+void __init kbd_reset_setup(char *str, int *ints)
{
- return mach_keyb_init();
}
void arch_gettod(int *year, int *mon, int *day, int *hour,
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index af5af69b6..a2b9ce1d4 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -361,7 +361,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
: "a0");
#undef frame_offset
/*
- * If we ever get here an exception occured while
+ * If we ever get here an exception occurred while
* building the above stack-frame.
*/
goto badframe;
@@ -460,7 +460,7 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
: "a0");
#undef frame_offset
/*
- * If we ever get here an exception occured while
+ * If we ever get here an exception occurred while
* building the above stack-frame.
*/
goto badframe;
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 75da52541..a85da4e10 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -112,7 +112,8 @@ asmlinkage int old_select(struct sel_arg_struct *arg)
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int sys_ipc (uint call, int first, int second,
+ int third, void *ptr, long fifth)
{
int version, ret;
@@ -122,88 +123,76 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
if (call <= SEMCTL)
switch (call) {
case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
+ return sys_semop (first, (struct sembuf *)ptr, second);
case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
+ return sys_semget (first, second, third);
case SEMCTL: {
union semun fourth;
- ret = -EINVAL;
if (!ptr)
- goto out;
- if ((ret = get_user(fourth.__pad, (void **) ptr)))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
+ return -EINVAL;
+ if (get_user(fourth.__pad, (void **) ptr))
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
}
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (call <= MSGCTL)
switch (call) {
case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
second, third);
- goto out;
case MSGRCV:
switch (version) {
case 0: {
struct ipc_kludge tmp;
- ret = -EINVAL;
if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user (&tmp, ptr, sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
+ return -EINVAL;
+ if (copy_from_user (&tmp,
+ (struct ipc_kludge *)ptr,
+ sizeof (tmp)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp, second,
+ tmp.msgtyp, third);
}
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ default:
+ return sys_msgrcv (first,
+ (struct msgbuf *) ptr,
+ second, fifth, third);
}
case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
+ return sys_msgget ((key_t) first, second);
case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
+ return sys_msgctl (first, second,
+ (struct msqid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (call <= SHMCTL)
switch (call) {
case SHMAT:
switch (version) {
- case 0: default: {
+ default: {
ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ ret = sys_shmat (first, (char *) ptr,
+ second, &raddr);
if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ return ret;
+ return put_user (raddr, (ulong *) third);
}
}
case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
+ return sys_shmdt ((char *)ptr);
case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
+ return sys_shmget (first, second, third);
case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
+
+ return -EINVAL;
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 8f11a00d8..107d0de7f 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -5,6 +5,9 @@
*
* This file contains the m68k-specific time handling details.
* Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h> /* CONFIG_HEARTBEAT */
@@ -65,9 +68,10 @@ static void timer_interrupt(int irq, void *dummy, 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 && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1)) {
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
@@ -146,27 +150,38 @@ void time_init(void)
mach_sched_init(timer_interrupt);
}
+extern rwlock_t xtime_lock;
+
/*
* This version of gettimeofday has near microsecond resolution.
*/
void do_gettimeofday(struct timeval *tv)
{
+ extern volatile unsigned long lost_ticks;
unsigned long flags;
-
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += mach_gettimeoffset();
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
+ unsigned long usec, sec, lost;
+
+ read_lock_irqsave(&xtime_lock, flags);
+ usec = mach_gettimeoffset();
+ lost = lost_ticks;
+ if (lost)
+ usec += lost * (1000000/HZ);
+ sec = xtime.tv_sec;
+ usec += xtime.tv_usec;
+ read_unlock_irqrestore(&xtime_lock, flags);
+
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
}
- restore_flags(flags);
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
- cli();
+ write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
@@ -175,14 +190,16 @@ void do_settimeofday(struct timeval *tv)
*/
tv->tv_usec -= mach_gettimeoffset();
- if (tv->tv_usec < 0) {
+ while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = MAXPHASE;
- time_esterror = MAXPHASE;
+ 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();
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index f410182e0..8e902d0bd 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -55,9 +55,6 @@ extern char m68k_command_line[CL_SIZE];
void *mac_env; /* Loaded by the boot asm */
-/* The logical video addr. determined by head.S - testing */
-extern unsigned long mac_videobase;
-
/* The phys. video addr. - might be bogus on some machines */
unsigned long mac_orig_videoaddr;
@@ -65,7 +62,6 @@ unsigned long mac_orig_videoaddr;
extern int mac_keyb_init(void);
extern int mac_kbdrate(struct kbd_repeat *k);
extern void mac_kbd_leds(unsigned int leds);
-extern void mac_kbd_reset_setup(char*, int);
/* Mac specific irq functions */
extern void mac_init_IRQ (void);
@@ -100,17 +96,15 @@ extern void mac_debug_init(void);
extern void mac_debugging_long(int, long);
#ifdef CONFIG_MAGIC_SYSRQ
-
-/* XXX FIXME: Atari scancodes still */
static char mac_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
- "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
- "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\000\000\000()/*789456123" /* 0x60 - 0x6f */
- "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
+ "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */
+ "yt123465=97-80)o" /* 0x10 - 0x1f */
+ "u(ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
+ "\t `\000\033\000\000\000\000\000\000\000\000\000\000\000" /* 0x30 - 0x3f */
+ "\000.\000*\000+\000\000\000\000\000/\r\000-\000" /* 0x40 - 0x4f */
+ "\000\00001234567a89\000\000\000" /* 0x50 - 0x5f */
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
#endif
extern void (*kd_mksound)(unsigned int, unsigned int);
@@ -243,9 +237,7 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
mac_bi_data.id = *data;
break;
case BI_MAC_VADDR:
- /* save booter supplied videobase; use the one mapped in head.S! */
- mac_orig_videoaddr = *data;
- mac_bi_data.videoaddr = mac_videobase;
+ mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
break;
case BI_MAC_VDEPTH:
mac_bi_data.videodepth = *data;
@@ -309,7 +301,6 @@ __initfunc(void config_mac(void))
mach_keyb_init = mac_keyb_init;
mach_kbdrate = mac_kbdrate;
mach_kbd_leds = mac_kbd_leds;
- kbd_reset_setup = mac_kbd_reset_setup;
mach_init_IRQ = mac_init_IRQ;
mach_request_irq = mac_request_irq;
mach_free_irq = mac_free_irq;
@@ -336,7 +327,7 @@ __initfunc(void config_mac(void))
#endif
kd_mksound = mac_mksound;
#ifdef CONFIG_MAGIC_SYSRQ
- mach_sysrq_key = 98; /* HELP */
+ mach_sysrq_key = 114; /* HELP */
mach_sysrq_shift_state = 8; /* Alt */
mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
mach_sysrq_xlate = mac_sysrq_xlate;
@@ -399,10 +390,10 @@ static struct mac_model mac_data_table[]=
*
*/
- { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+ { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/*
* Weirdified MacII hardware - all subtley different. Gee thanks
@@ -425,7 +416,7 @@ static struct mac_model mac_data_table[]=
*/
{ MAC_MODEL_CLII, "Classic II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_CCL, "Color Classic", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_CCL, "Color Classic", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/*
* Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
@@ -461,11 +452,11 @@ static struct mac_model mac_data_table[]=
* Performa - more LC type machines
*/
- { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
@@ -477,8 +468,8 @@ static struct mac_model mac_data_table[]=
* Centris - just guessing again; maybe like Quadra
*/
- { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
/*
@@ -551,7 +542,7 @@ void mac_identify(void)
m++;
}
if(m->ident==-1)
- mac_boom(5);
+ panic("mac model config data corrupt!\n");
}
/*
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 62a8a6187..5aa7ce6cf 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -36,7 +36,10 @@ extern unsigned long mac_videobase;
extern unsigned long mac_videodepth;
extern unsigned long mac_rowbytes;
-#define DEBUG_SCREEN
+extern void mac_serial_print(char *);
+
+#define DEBUG_HEADS
+#undef DEBUG_SCREEN
#define DEBUG_SERIAL
/*
@@ -129,121 +132,6 @@ void mac_debugging_long(int pos, long addr)
#endif
}
-/*
- * Penguin - used by head.S console; obsolete
- */
-char that_penguin[]={
-#include "that_penguin.h"
-};
-
-#ifdef DEBUG_SCREEN
-/*
- * B/W version of penguin, unfinished - any takers??
- */
-static char bw_penguin[]={
-#include "bw_penguin.h"
-};
-#endif
-
-void mac_debugging_penguin(int peng)
-{
-#ifdef DEBUG_SCREEN
- unsigned char *pengoffset;
- unsigned char *pptr;
- unsigned char *bwpdptr=bw_penguin;
- int i;
-#endif
-
-#ifdef DEBUG_SERIAL
- printk("Penguin: #%d !\n", peng);
-#endif
-
-#ifdef DEBUG_SCREEN
- if (!MACH_IS_MAC)
- return;
-
- if (mac_videodepth ==1)
- pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
- +5*peng;
- else
- pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
- +20*peng;
-
- pptr=pengoffset;
-
- for(i=0;i<36;i++)
- {
- memcpy(pptr,bwpdptr,4);
- bwpdptr+=4;
- pptr+=mac_rowbytes;
- }
-#endif
-}
-
-#ifdef DEBUG_SCREEN
-/*
- * B/W version of flaming Mac, unfinished (see above).
- */
-static char bw_kaboom_map[]={
-#include "bw_mac.h"
-};
-#endif
-
-#ifdef DEBUG_SCREEN
-static void mac_boom_boom(void)
-{
- static unsigned char *boomoffset=NULL;
- unsigned char *pptr;
- unsigned char *bwpdptr=bw_kaboom_map;
- int i;
-
-#ifdef DEBUG_SERIAL
- printk("BOOM !\n");
-#endif
-
- if (!MACH_IS_MAC)
- return;
-
- if(!boomoffset)
- if (mac_videodepth == 1) {
- boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
- } else {
- boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes);
- }
- else
- if (mac_videodepth == 1)
- boomoffset+=5;
- else
- boomoffset+=32;
-
- pptr=boomoffset;
-
- for(i=0;i<36;i++)
- {
- memcpy(pptr,bwpdptr,4);
- bwpdptr+=4;
- pptr+=mac_rowbytes;
- }
-}
-#endif
-
-void mac_boom(int booms)
-{
-#ifdef DEBUG_SCREEN
- int i;
-#endif
-
- if (!MACH_IS_MAC)
- return;
-
-#ifdef DEBUG_SCREEN
- for(i=0;i<booms;i++)
- mac_boom_boom();
- while(1);
-#endif
-}
-
-
#ifdef DEBUG_SERIAL
/*
* TODO: serial debug code
@@ -284,6 +172,29 @@ static struct console mac_console_driver = {
NULL
};
+/*
+ * Crude hack to get console output to the screen before the framebuffer
+ * is initialized (happens a lot later in 2.1!).
+ * We just use the console routines declared in head.S, this will interfere
+ * with regular framebuffer console output and should be used exclusively
+ * to debug kernel problems manifesting before framebuffer init (aka WSOD)
+ *
+ * To keep this hack from interfering with the regular console driver, either
+ * deregister this driver before/on framebuffer console init, or silence this
+ * function after the fbcon driver is running (will lose console messages!?).
+ * To debug real early bugs, need to write a 'mac_register_console_hack()'
+ * that is called from start_kernel() before setup_arch() and just registers
+ * this driver if Mac.
+ */
+
+void mac_debug_console_write (struct console *co, const char *str,
+ unsigned int count)
+{
+ mac_serial_print(str);
+}
+
+
+
/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
#define uSEC 1
@@ -486,19 +397,30 @@ __initfunc(void mac_debug_init(void))
/* Mac modem port */
mac_init_scc_port( B9600|CS8, 0 );
mac_console_driver.write = mac_scca_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
mac_console_driver.wait_key = mac_scca_console_wait_key;
+#endif
scc_port = 0;
}
else if (!strcmp( m68k_debug_device, "ser2" )) {
/* Mac printer port */
mac_init_scc_port( B9600|CS8, 1 );
mac_console_driver.write = mac_sccb_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
mac_console_driver.wait_key = mac_sccb_console_wait_key;
+#endif
scc_port = 1;
}
+#endif
+#ifdef DEBUG_HEADS
+ if ( !strcmp( m68k_debug_device, "scn" )
+ || !strcmp( m68k_debug_device, "con" )) {
+ /* display, using head.S console routines */
+ mac_console_driver.write = mac_debug_console_write;
+ }
+#endif
if (mac_console_driver.write)
register_console(&mac_console_driver);
-#endif
}
/*
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 95078a384..1731c929c 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -1,6 +1,12 @@
/*
* Mac bong noise generator. Note - we ought to put a boingy noise
* here 8)
+ *
+ * ----------------------------------------------------------------------
+ * 16.11.98:
+ * rewrote some functions, added support for Enhanced ASC (Quadras)
+ * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck
+ * Juergen Mellinger (juergen.mellinger@t-online.de)
*/
#include <linux/sched.h>
@@ -9,124 +15,281 @@
#include <asm/macintosh.h>
#include <asm/mac_asc.h>
+static int mac_asc_inited = 0;
+/*
+ * dumb triangular wave table
+ */
+static __u8 mac_asc_wave_tab[ 0x800 ];
+
+/*
+ * Alan's original sine table; needs interpolating to 0x800
+ * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric)
+ */
static const signed char sine_data[] = {
0, 39, 75, 103, 121, 127, 121, 103, 75, 39,
0, -39, -75, -103, -121, -127, -121, -103, -75, -39
};
-#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0]))
-static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+/*
+ * where the ASC hides ...
+ */
+static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
-static volatile unsigned char *asc_base=(void *)0x50F14000;
+/*
+ * sample rate; is this a good default value?
+ */
+static unsigned long mac_asc_samplespersec = 11050;
+static int mac_bell_duration = 0;
+static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */
+static unsigned long mac_bell_phasepersample;
+
+/*
+ * some function protos
+ */
+static void mac_init_asc( void );
+static void mac_nosound( unsigned long );
+static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
+static void mac_quadra_ring_bell( unsigned long );
+static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
+static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL;
+/*
+ * our timer to start/continue/stop the bell
+ */
+static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound };
-void mac_mksound( unsigned int hz, unsigned int ticks )
+/*
+ * Sort of initialize the sound chip (called from mac_mksound on the first
+ * beep).
+ */
+static void mac_init_asc( void )
{
- static int inited = 0;
- unsigned long flags;
- int samples=512;
+ int i;
- if (macintosh_config->ident == MAC_MODEL_C660
- || macintosh_config->ident == MAC_MODEL_Q840)
+ /*
+ * do some machine specific initialization
+ * BTW:
+ * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via
+ * mac_asc_regs[ 0x800 ] & 0xF0 != 0
+ * this makes no sense here, because we have to set the default sample
+ * rate anyway if we want correct frequencies
+ */
+ switch ( macintosh_config->ident )
{
- /*
- * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
- * It appears to be similar to the "AWACS" custom ASIC in the Power Mac
- * [678]100. Because Singer and AWACS may have a similar hardware
- * interface, this would imply that the code in drivers/sound/dmasound.c
- * for AWACS could be used as a basis for Singer support. All we have to
- * do is figure out how to do DMA on the 660AV/840AV through the PSC and
- * figure out where the Singer hardware sits in memory. (I'd look in the
- * vicinity of the AWACS location in a Power Mac [678]100 first, or the
- * current location of the Apple Sound Chip--ASC--in other Macs.) The
- * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
- *
- * Quoted from Apple's Tech Info Library, article number 16405:
- * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
- * Macintosh models have 16-bit audio input and output capability
- * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
- * codec circuitry in the AVs. The Audio Waveform Amplifier and
- * Converter (AWAC) chip in the Power Macintosh performs the same
- * 16-bit I/O functionality. The PowerBook 500 series computers
- * support 16-bit stereo output, but only mono input."
- *
- * http://til.info.apple.com/techinfo.nsf/artnum/n16405
- *
- * --David Kilzer
- */
+ case MAC_MODEL_IIFX:
+ /*
+ * The IIfx is always special ...
+ */
+ mac_asc_regs = ( void* )0x50010000;
+ break;
+ /*
+ * not sure about how correct this list is
+ * machines with the EASC enhanced apple sound chip
+ */
+ case MAC_MODEL_Q630:
+ case MAC_MODEL_P475:
+ mac_special_bell = mac_quadra_start_bell;
+ mac_asc_samplespersec = 22150;
+ break;
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ /*
+ * Currently not implemented!
+ */
+ /*
+ * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
+ * It appears to be similar to the "AWACS" custom ASIC in the Power Mac
+ * [678]100. Because Singer and AWACS may have a similar hardware
+ * interface, this would imply that the code in drivers/sound/dmasound.c
+ * for AWACS could be used as a basis for Singer support. All we have to
+ * do is figure out how to do DMA on the 660AV/840AV through the PSC and
+ * figure out where the Singer hardware sits in memory. (I'd look in the
+ * vicinity of the AWACS location in a Power Mac [678]100 first, or the
+ * current location of the Apple Sound Chip--ASC--in other Macs.) The
+ * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
+ *
+ * Quoted from Apple's Tech Info Library, article number 16405:
+ * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
+ * Macintosh models have 16-bit audio input and output capability
+ * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
+ * codec circuitry in the AVs. The Audio Waveform Amplifier and
+ * Converter (AWAC) chip in the Power Macintosh performs the same
+ * 16-bit I/O functionality. The PowerBook 500 series computers
+ * support 16-bit stereo output, but only mono input."
+ *
+ * http://til.info.apple.com/techinfo.nsf/artnum/n16405
+ *
+ * --David Kilzer
+ */
+ mac_special_bell = mac_av_start_bell;
+ break;
+ }
+
+ /*
+ * init the wave table with a simple triangular wave
+ * A sine wave would sure be nicer here ...
+ */
+ for ( i = 0; i < 0x400; i++ )
+ {
+ mac_asc_wave_tab[ i ] = i / 4;
+ mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4;
+ }
+ mac_asc_inited = 1;
+}
+/*
+ * Called to make noise; current single entry to the boing driver.
+ * Does the job for simple ASC, calls other routines else.
+ * XXX Fixme:
+ * Should be split into asc_mksound, easc_mksound, av_mksound and
+ * function pointer set in mac_init_asc which would be called at
+ * init time.
+ * _This_ is rather ugly ...
+ */
+void mac_mksound( unsigned int freq, unsigned int length )
+{
+ __u32 cfreq = ( freq << 5 ) / 468;
+ __u32 flags;
+ int i;
+
+ if ( !mac_asc_inited )
+ mac_init_asc();
+
+ if ( mac_special_bell )
+ {
+ mac_special_bell( freq, length, 128 );
return;
}
-
- if(!inited)
+
+ if ( freq < 20 || freq > 20000 || length == 0 )
{
- int i=0;
- int j=0;
- int k=0;
- int l=0;
-
- /*
- * The IIfx strikes again!
- */
-
- if(macintosh_config->ident==MAC_MODEL_IIFX)
- asc_base=(void *)0x50010000;
-
- for(i=0;i<samples;i++)
- {
- asc_base[i]=sine_data[j];
- asc_base[i+512]=sine_data[j];
- asc_base[i+1024]=sine_data[j];
- asc_base[i+1536]=sine_data[j];
- j++;
- if(j==DATA_SIZE)
- j=0;
- if(i&1)
- k++;
- if(k==DATA_SIZE)
- k=0;
- if((i&3)==3)
- l++;
- if(l==DATA_SIZE)
- l=0;
- }
- inited=1;
+ mac_nosound( 0 );
+ return;
}
- save_flags(flags);
+
+ save_flags( flags );
cli();
- del_timer( &sound_timer );
- if (hz > 20 && hz < 32767) {
- int i;
- u_long asc_pulses=((hz<<5)*samples)/468;
- for(i=0;i<4;i++)
+ del_timer( &mac_sound_timer );
+
+ for ( i = 0; i < 0x800; i++ )
+ mac_asc_regs[ i ] = 0;
+ for ( i = 0; i < 0x800; i++ )
+ mac_asc_regs[ i ] = mac_asc_wave_tab[ i ];
+
+ for ( i = 0; i < 8; i++ )
+ *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq;
+
+ mac_asc_regs[ 0x807 ] = 0;
+ mac_asc_regs[ ASC_VOLUME ] = 128;
+ mac_asc_regs[ 0x805 ] = 0;
+ mac_asc_regs[ 0x80F ] = 0;
+ mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE;
+ mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE;
+
+ mac_sound_timer.expires = jiffies + length;
+ add_timer( &mac_sound_timer );
+
+ restore_flags( flags );
+}
+
+/*
+ * regular ASC: stop whining ..
+ */
+static void mac_nosound( unsigned long ignored )
+{
+ mac_asc_regs[ ASC_ENABLE ] = 0;
+}
+
+/*
+ * EASC entry; init EASC, don't load wavetable, schedule 'start whining'.
+ */
+static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
+{
+ __u32 flags;
+
+ /* if the bell is already ringing, ring longer */
+ if ( mac_bell_duration > 0 )
+ {
+ mac_bell_duration += length;
+ return;
+ }
+
+ mac_bell_duration = length;
+ mac_bell_phase = 0;
+ mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
+ /* this is reasonably big for small frequencies */
+
+ save_flags( flags );
+ cli();
+
+ /* set the volume */
+ mac_asc_regs[ 0x806 ] = volume;
+
+ /* set up the ASC registers */
+ if ( mac_asc_regs[ 0x801 ] != 1 )
+ {
+ /* select mono mode */
+ mac_asc_regs[ 0x807 ] = 0;
+ /* select sampled sound mode */
+ mac_asc_regs[ 0x802 ] = 0;
+ /* ??? */
+ mac_asc_regs[ 0x801 ] = 1;
+ mac_asc_regs[ 0x803 ] |= 0x80;
+ mac_asc_regs[ 0x803 ] &= 0x7F;
+ }
+
+ mac_sound_timer.function = mac_quadra_ring_bell;
+ mac_sound_timer.expires = jiffies + 1;
+ add_timer( &mac_sound_timer );
+
+ restore_flags( flags );
+}
+
+/*
+ * EASC 'start/continue whining'; I'm not sure why the above function didn't
+ * already load the wave table, or at least call this one...
+ * This piece keeps reloading the wave table until done.
+ */
+static void mac_quadra_ring_bell( unsigned long ignored )
+{
+ int i, count = mac_asc_samplespersec / HZ;
+ __u32 flags;
+
+ /*
+ * we neither want a sound buffer overflow nor underflow, so we need to match
+ * the number of samples per timer interrupt as exactly as possible.
+ * using the asc interrupt will give better results in the future
+ * ...and the possibility to use a real sample (a boingy noise, maybe...)
+ */
+
+ save_flags( flags );
+ cli();
+
+ del_timer( &mac_sound_timer );
+
+ if ( mac_bell_duration-- > 0 )
+ {
+ for ( i = 0; i < count; i++ )
{
- asc_base[ASC_FREQ(i,0)]=0x00;
- asc_base[ASC_FREQ(i,1)]=20;
- asc_base[ASC_FREQ(i,2)]=0x00;
- asc_base[ASC_FREQ(i,3)]=20;
- asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
- asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
- asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
- asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+ mac_bell_phase += mac_bell_phasepersample;
+ mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
}
- asc_base[ASC_CHAN]=0x03;
- asc_base[ASC_VOLUME]=128;
- asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
- asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
- if (ticks) {
- sound_timer.expires = jiffies + ticks;
- add_timer( &sound_timer );
- }
- } else {
- nosound( 0 );
+ mac_sound_timer.expires = jiffies + 1;
+ add_timer( &mac_sound_timer );
}
- restore_flags(flags);
+ else
+ mac_asc_regs[ 0x801 ] = 0;
+
+ restore_flags( flags );
}
-
-static void nosound( unsigned long ignored )
+/*
+ * AV code - please fill in.
+ */
+static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
{
- asc_base[ASC_ENABLE]=0;
-}
+}
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index b703cb275..87e6692d4 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -163,7 +163,14 @@ static unsigned long nubus_irqs[8];
static unsigned long *mac_irqs[8];
/*
- * VIA2 / RBV register base pointers
+ * Some special nutcases ...
+ */
+
+static unsigned long mac_ide_irqs = 0;
+static unsigned long nubus_stuck_events = 0;
+
+/*
+ * VIA/RBV/OSS/PSC register base pointers
*/
volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
@@ -217,9 +224,13 @@ void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
/* #define DEBUG_MACINTS */
-/* #define DEBUG_NUBUS_INT */
+
+#define DEBUG_SPURIOUS
+#define DEBUG_NUBUS_SPURIOUS
+#define DEBUG_NUBUS_INT
+
/* #define DEBUG_VIA */
-/* #define DEBUG_VIA_NUBUS */
+#define DEBUG_VIA_NUBUS
void mac_init_IRQ(void)
{
@@ -247,7 +258,7 @@ void mac_init_IRQ(void)
/* yes, this is messy - the IIfx deserves a class of his own */
if (macintosh_config->ident == MAC_MODEL_IIFX) {
- /* no real VIA2, the OSS seems _very_different */
+ /* no real VIA2, the OSS seems _very_ different */
via2_is_oss = 1;
/* IIfx has OSS, at a different base address than RBV */
rbv_regp = (unsigned char *) OSS_BAS;
@@ -351,6 +362,12 @@ void mac_init_IRQ(void)
mac_irqs[7] = &nubus_irqs[0];
/*
+ * Nubus Macs: turn off the Nubus dispatch interrupt for now
+ */
+
+ mac_turnoff_irq(IRQ_MAC_NUBUS);
+
+ /*
* AV Macs: shutup the PSC ints
*/
if (macintosh_config->ident == MAC_MODEL_C660
@@ -430,8 +447,10 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
return 0;
}
- /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
-
+ /*
+ * code below: only for VIA irqs currently
+ * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq
+ */
via = (volatile unsigned char *) via_table[srcidx];
if (!via)
return -EINVAL;
@@ -459,7 +478,7 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
/*
* Set vPCR for SCSI interrupts. (what about RBV here?)
- * 980429 MS: RBV is ok, OSS seems to be differentt
+ * 980429 MS: RBV is ok, OSS seems to be different
*/
if (!via2_is_oss)
if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
@@ -602,7 +621,10 @@ void mac_disable_irq (unsigned int irq)
/*
* In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
- * "stored". This is done with the VIA interrupt enable register
+ * "stored". This is done with the VIA interrupt enable register on VIAs.
+ *
+ * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least
+ * have undesired side effects.
*/
void mac_turnon_irq( unsigned int irq )
@@ -615,14 +637,14 @@ void mac_turnon_irq( unsigned int irq )
if (!via)
return;
- if (srcidx == SRC_VIA2 && via2_is_rbv)
+ if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */
via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
+ else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
via_write(oss_regp, oss_map[irqidx]+8, 2);
- else if (srcidx > SRC_VIA2)
+ else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */
via_write(via, (0x104 + 0x10*srcidx),
via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
- else
+ else /* VIA1+2 */
via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
}
@@ -637,9 +659,9 @@ void mac_turnoff_irq( unsigned int irq )
if (!via)
return;
- if (srcidx == SRC_VIA2 && via2_is_rbv)
+ if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */
via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
+ else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
via_write(oss_regp, oss_map[irqidx]+8, 0);
/*
* VIA2 is fixed. The stuff above VIA2 is for later
@@ -648,7 +670,7 @@ void mac_turnoff_irq( unsigned int irq )
else if (srcidx > SRC_VIA2)
via_write(via, (0x104 + 0x10*srcidx),
via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
- else
+ else /* VIA1+2 */
via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
}
@@ -694,12 +716,18 @@ int mac_irq_pending( unsigned int irq )
return (pending);
}
+/*
+ * for /proc/interrupts: log interrupt stats broken down by
+ * autovector int first, then by actual interrupt source.
+ */
+
int mac_get_irq_list (char *buf)
{
int i, len = 0;
int srcidx, irqidx;
for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+ /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */
srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
irqidx = (i & IRQ_IDX_MASK);
@@ -764,6 +792,32 @@ int mac_get_irq_list (char *buf)
}
if (num_spurious)
len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+
+ /*
+ * XXX Fixme: Nubus sources are never logged above ...
+ */
+
+ len += sprintf(buf+len, "Nubus interrupts:\n");
+
+ for (i = 0; i < 7; i++) {
+ if (nubus_handler[i].handler == nubus_wtf)
+ continue;
+ len += sprintf(buf+len, "nubus %01X: %10lu ",
+ i+9,
+ nubus_irqs[i]);
+ len += sprintf(buf+len, "%s\n",
+ nubus_param[i].devname);
+
+ }
+ len += sprintf(buf+len, "nubus spurious ints: %10lu\n",
+ nubus_irqs[7]);
+ len += sprintf(buf+len, "nubus stuck events : %10lu\n",
+ nubus_stuck_events);
+#ifdef CONFIG_BLK_DEV_IDE
+ len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n",
+ mac_ide_irqs);
+#endif
+
return len;
}
@@ -784,8 +838,9 @@ void via_scsi_clear(void)
void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
{
-#ifdef DEBUG_VIA
- printk("Unexpected IRQ %d\n", irq);
+#ifdef DEBUG_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
#endif
}
@@ -861,6 +916,18 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
}
/*
+ * Unexpected via interrupt
+ */
+
+void via_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected nubus event %d on via %p\n",slot,via);
+#endif
+}
+
+/*
* The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
* via6522.c :-), disable/pending masks added.
* The int *viaidx etc. is just to keep the prototype happy ...
@@ -1115,17 +1182,6 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
}
/*
- * Unexpected via interrupt
- */
-
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_VIA
- printk("Unexpected event %d on via %p\n",slot,via);
-#endif
-}
-
-/*
* Nubus / SCSI interrupts; OSS style
* The OSS is even more different than the RBV. OSS appears to stand for
* Obscenely Screwed Silicon ...
@@ -1264,8 +1320,9 @@ void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
void nubus_wtf(int slot, void *via, struct pt_regs *regs)
{
-#ifdef DEBUG_VIA_NUBUS
- printk("Unexpected interrupt on nubus slot %d\n",slot);
+#ifdef DEBUG_NUBUS_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected interrupt on nubus slot %d\n",slot);
#endif
}
@@ -1279,9 +1336,10 @@ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
int i;
/* 1+2: compatibility with PSC ! */
for (i = 1; i < 3; i++) /* currently only these two used */
- if (scc_handler[i].handler != mac_default_handler)
+ if (scc_handler[i].handler != mac_default_handler) {
(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
-
+ scc_irqs[i]++;
+ }
}
/*
@@ -1310,7 +1368,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
if(events==0)
{
#ifdef DEBUG_VIA
- printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+ printk("psc_irq: nothing pending, flags %x mask %x!\n",
via_read(via, pIFR), via_read(via,pIER));
#endif
mac_irqs[srcidx][7]++;
@@ -1319,7 +1377,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
#ifdef DEBUG_VIA
/*
- * limited verbosity for RBV interrupts (add more if needed)
+ * limited verbosity for PSC interrupts (add more if needed)
*/
if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */
printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events);
@@ -1423,6 +1481,7 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct
if (!nubus_active && !via2_is_oss) {
request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
"nubus dispatch", via_do_nubus);
+ mac_turnon_irq(IRQ_MAC_NUBUS);
}
nubus_active|=1<<slot;
@@ -1472,6 +1531,7 @@ int nubus_free_irq(int slot)
* IDE interrupt hook
*/
extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+extern int (*mac_ide_irq_p_hook)(void);
#endif
/*
@@ -1479,13 +1539,13 @@ extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
*/
static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
{
- unsigned char map;
+ unsigned char map, allints;
int i;
int ct=0;
-
-/* printk("nubus interrupt\n");*/
+ int ide_pending = 0;
/* lock the nubus interrupt */
+ /* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */
if (via2_is_rbv)
via_write(rbv_regp, rIFR, 0x82);
else
@@ -1493,36 +1553,69 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
#ifdef CONFIG_BLK_DEV_MAC_IDE
/* IDE hack */
- if (mac_ide_intr_hook)
+ if (mac_ide_intr_hook) {
/* 'slot' is lacking the machspec bit in 2.0 */
/* need to pass proper dev_id = hwgroup here */
mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+ mac_ide_irqs++;
+ }
#endif
while(1)
{
if (via2_is_rbv)
- map = ~via_read(rbv_regp, rBufA);
+ allints = ~via_read(rbv_regp, rBufA);
else
- map = ~via_read(via2_regp, vBufA);
+ allints = ~via_read(via2_regp, vBufA);
- if( (map = (map&nubus_active)) ==0 ) {
-#ifdef DEBUG_NUBUS_INT
- printk("nubus_irq: nothing pending, map %x mask %x\n",
- map, nubus_active);
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ if (mac_ide_irq_p_hook)
+ ide_pending = mac_ide_irq_p_hook();
+#endif
+
+ if ( (map = (allints&nubus_active)) == 0
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ && !ide_pending
#endif
- nubus_irqs[7]++;
+ )
+ {
+ if (ct == 0) {
+#ifdef DEBUG_VIA_NUBUS
+ if (console_loglevel > 5)
+ printk("nubus_irq: nothing pending, map %x mask %x active %x\n",
+ allints, nubus_active, map);
+#endif
+ nubus_irqs[7]++;
+ }
+ /* clear it */
+ if (allints)
+ if (via2_is_rbv)
+ via_write(rbv_regp, rIFR, 0x02);
+ else
+ via_write(via2_regp, vIFR, 0x02);
break;
}
-#ifdef DEBUG_NUBUS_INT
- printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+
+#ifdef DEBUG_VIA_NUBUS
+ if (console_loglevel > 6)
+ printk("nubus_irq: map %x mask %x active %x\n",
+ allints, nubus_active, map);
+#endif
+
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ if (mac_ide_intr_hook && ide_pending) {
+ mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+ mac_ide_irqs++;
+ }
#endif
if(ct++>2)
{
-#ifdef DEBUG_NUBUS_INT
- printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
+ if (console_loglevel > 5)
+ printk("nubus stuck events - %x/%x/%x ide %x\n",
+ allints, nubus_active, map, ide_pending);
+ nubus_stuck_events++;
+
return;
}
@@ -1579,12 +1672,14 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
printk("nubus_irq: map %x mask %x\n", map, nubus_active);
#endif
if( (map = (map&nubus_active)) ==0 ) {
+ if (ct == 0) {
#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (!mac_ide_intr_hook)
- printk("nubus_irq: nothing pending, map %x mask %x\n",
- map, nubus_active);
+ if (!mac_ide_intr_hook)
+ printk("nubus_irq: nothing pending, map %x mask %x\n",
+ map, nubus_active);
#endif
- nubus_irqs[7]++;
+ nubus_irqs[7]++;
+ }
break;
}
diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c
index 64cd5e1f8..5a6ae7c75 100644
--- a/arch/m68k/mac/mackeyb.c
+++ b/arch/m68k/mac/mackeyb.c
@@ -1,5 +1,12 @@
/*
- * linux/arch/m68k/mac/mackeyb.c
+ * linux/arch/m68k/mac/mackeyb.c
+ *
+ * Keyboard driver for Macintosh computers.
+ *
+ * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 1997 Michael Schmitz.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
@@ -10,6 +17,7 @@
* misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/kd.h>
@@ -59,8 +67,15 @@ extern void put_queue(int);
static void mac_leds_done(struct adb_request *);
static void keyboard_input(unsigned char *, int, struct pt_regs *);
static void mouse_input(unsigned char *, int, struct pt_regs *);
-/* Hook for mouse driver */
-void (*adb_mouse_interrupt_hook) (char *, int);
+
+#ifdef CONFIG_ADBMOUSE
+/* XXX: Hook for mouse driver */
+void (*adb_mouse_interrupt_hook)(unsigned char *, int);
+int adb_emulate_buttons = 0;
+int adb_button2_keycode = 0x7d; /* right control key */
+int adb_button3_keycode = 0x7c; /* right option key */
+#endif
+
/* The mouse driver - for debugging */
extern void adb_mouse_interrupt(char *, int);
/* end keyb */
@@ -275,9 +290,11 @@ input_keycode(int keycode, int repeat)
kbd = kbd_table + fg_console;
up_flag = (keycode & 0x80);
keycode &= 0x7f;
+
if (!repeat)
del_timer(&repeat_timer);
+#ifdef CONFIG_ADBMOUSE
/*
* XXX: Add mouse button 2+3 fake codes here if mouse open.
* As we only report up/down events, keep track of faked buttons.
@@ -289,7 +306,8 @@ input_keycode(int keycode, int repeat)
* (wanted: command and alt/option, or KP= and KP( ...)
* Debug version; might be rewritten to be faster on normal keys.
*/
- if (adb_mouse_interrupt_hook || console_loglevel >= 8) {
+ if (adb_emulate_buttons
+ && (adb_mouse_interrupt_hook || console_loglevel >= 8)) {
unsigned char button, button2, button3, fake_event;
static unsigned char button2state=0, button3state=0; /* up */
/* faked ADB packet */
@@ -297,21 +315,20 @@ input_keycode(int keycode, int repeat)
button = 0;
fake_event = 0;
- switch (keycode) { /* which 'button' ? */
- case 0x7c: /* R-option */
- button2 = (!up_flag); /* new state */
- if (button2 != button2state) /* change ? */
- button = 2;
- button2state = button2; /* save state */
- fake_event = 2;
- break;
- case 0x7d: /* R-control */
- button3 = (!up_flag); /* new state */
- if (button3 != button3state) /* change ? */
- button = 3;
- button3state = button3; /* save state */
- fake_event = 3;
- break;
+ if (keycode == adb_button2_keycode) { /* which 'button' ? */
+ /* R-option */
+ button2 = (!up_flag); /* new state */
+ if (button2 != button2state) /* change ? */
+ button = 2;
+ button2state = button2; /* save state */
+ fake_event = 2;
+ } else if (keycode == adb_button3_keycode) {
+ /* R-control */
+ button3 = (!up_flag); /* new state */
+ if (button3 != button3state) /* change ? */
+ button = 3;
+ button3state = button3; /* save state */
+ fake_event = 3;
}
#ifdef DEBUG_ADBMOUSE
if (fake_event && console_loglevel >= 8)
@@ -340,6 +357,7 @@ input_keycode(int keycode, int repeat)
if (fake_event)
return;
}
+#endif /* CONFIG_ADBMOUSE */
/*
* Convert R-shift/control/option to L version.
@@ -365,16 +383,18 @@ input_keycode(int keycode, int repeat)
* transition into a key-down transition.
* MSch: need to turn each caps-lock event into a down-up
* double event (keyboard code assumes caps-lock is a toggle)
+ * 981127: fix LED behavior (kudos atong!)
*/
-#if 0
- if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
- up_flag = 0;
-#else
- if (keycode == 0x39) {
+ switch (keycode) {
+ case 0x39:
handle_scancode(keycode); /* down */
up_flag = 0x80; /* see below ... */
+ mark_bh(KEYBOARD_BH);
+ break;
+ case 0x47:
+ mark_bh(KEYBOARD_BH);
+ break;
}
-#endif
}
handle_scancode(keycode + up_flag);
@@ -740,8 +760,3 @@ __initfunc(int mac_keyb_init(void))
return 0;
}
-
-/* for "kbd-reset" cmdline param */
-__initfunc(void mac_kbd_reset_setup(char *str, int *ints))
-{
-}
diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c
index 08ca49071..05e6f44e4 100644
--- a/arch/m68k/mac/via6522.c
+++ b/arch/m68k/mac/via6522.c
@@ -304,10 +304,11 @@ void mac_reset(void)
unsigned long flags;
unsigned long *reset_hook;
- save_flags(flags);
- cli();
-
/* need ROMBASE in booter */
+ /* indeed, plus need to MAP THE ROM !! */
+
+ if (mac_bi_data.rombase == 0)
+ mac_bi_data.rombase = 0x40800000;
/* works on some */
rom_reset = (void *) (mac_bi_data.rombase + 0xa);
@@ -318,12 +319,22 @@ void mac_reset(void)
printk("ROM reset hook: %p\n", *reset_hook);
rom_reset = *reset_hook;
#endif
+ if (macintosh_config->ident == MAC_MODEL_SE30) {
+ /*
+ * MSch: Machines known to crash on ROM reset ...
+ */
+ printk("System halted.\n");
+ while(1);
+ } else {
+ save_flags(flags);
+ cli();
- rom_reset();
+ rom_reset();
- restore_flags(flags);
+ restore_flags(flags);
+ }
- /* We never make it this far... */
+ /* We never make it this far... it usually panics above. */
printk ("Restart failed. Please restart manually.\n");
/* XXX - delay do we need to spin here ? */
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 62129782b..ef1b855bd 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/traps.h>
@@ -32,8 +33,7 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
- struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
+ struct mm_struct *mm = current->mm;
struct vm_area_struct * vma;
unsigned long fixup;
int write;
@@ -41,9 +41,17 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
#ifdef DEBUG
printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
regs->sr, regs->pc, address, error_code,
- tsk->mm->pgd);
+ current->mm->pgd);
#endif
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto no_context;
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -86,7 +94,14 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(current, vma, address, write);
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ if (!handle_mm_fault(current, vma, address, write))
+ goto do_sigbus;
/* There seems to be a missing invalidate somewhere in do_no_page.
* Until I found it, this one cures the problem and makes
@@ -106,10 +121,15 @@ bad_area:
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) {
- force_sig (SIGSEGV, tsk);
+ siginfo_t info;
+ info.si_signo = SIGSEGV;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGSEGV, &info, current);
return 1;
}
+no_context:
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->pc)) != 0) {
struct pt_regs *tregs;
@@ -136,5 +156,22 @@ bad_area:
die_if_kernel("Oops", regs, error_code);
do_exit(SIGKILL);
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+do_sigbus:
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ force_sig(SIGBUS, current);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+
return 1;
}
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 395fb41b6..8e520702f 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -28,8 +28,9 @@
#include <asm/atari_stram.h>
#endif
+#undef DEBUG
+
extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void init_kpointer_table(void);
extern void show_net_buffers(void);
int do_check_pgt_cache(int low, int high)
@@ -122,17 +123,14 @@ void show_mem(void)
unsigned long mm_cachebits = 0;
#endif
-pte_t *kernel_page_table (unsigned long *memavailp)
+static pte_t *__init kernel_page_table(unsigned long *memavailp)
{
pte_t *ptablep;
- if (memavailp) {
- ptablep = (pte_t *)*memavailp;
- *memavailp += PAGE_SIZE;
- }
- else
- ptablep = (pte_t *)__get_free_page(GFP_KERNEL);
+ ptablep = (pte_t *)*memavailp;
+ *memavailp += PAGE_SIZE;
+ clear_page((unsigned long)ptablep);
flush_page_to_ram((unsigned long) ptablep);
flush_tlb_kernel_page((unsigned long) ptablep);
nocache_page ((unsigned long)ptablep);
@@ -140,199 +138,164 @@ pte_t *kernel_page_table (unsigned long *memavailp)
return ptablep;
}
-__initfunc(static unsigned long
-map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
-{
-#define ONEMEG (1024*1024)
-#define L3TREESIZE (256*1024)
+static pmd_t *last_pgtable __initdata = NULL;
- static unsigned long mem_mapped = 0;
- static unsigned long virtaddr = 0;
- static pte_t *ktablep = NULL;
- unsigned long *kpointerp;
- unsigned long physaddr;
- extern pte_t *kpt;
- int pindex; /* index into pointer table */
- pgd_t *page_dir = pgd_offset_k (virtaddr);
-
- if (!pgd_present (*page_dir)) {
- /* we need a new pointer table */
- kpointerp = (unsigned long *) get_kpointer_table ();
- pgd_set (page_dir, (pmd_t *) kpointerp);
- memset (kpointerp, 0, PTRS_PER_PMD * sizeof (pmd_t));
- }
- else
- kpointerp = (unsigned long *) pgd_page (*page_dir);
+static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+{
+ if (!last_pgtable) {
+ unsigned long pmd, last;
+ int i;
- /*
- * pindex is the offset into the pointer table for the
- * descriptors for the current virtual address being mapped.
- */
- pindex = (virtaddr >> 18) & 0x7f;
+ last = (unsigned long)kernel_pg_dir;
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (!pgd_val(kernel_pg_dir[i]))
+ continue;
+ pmd = pgd_page(kernel_pg_dir[i]);
+ if (pmd > last)
+ last = pmd;
+ }
+ last_pgtable = (pmd_t *)last;
#ifdef DEBUG
- printk ("mm=%ld, kernel_pg_dir=%p, kpointerp=%p, pindex=%d\n",
- mem_mapped, kernel_pg_dir, kpointerp, pindex);
+ printk("kernel_ptr_init: %p\n", last_pgtable);
#endif
+ }
- /*
- * if this is running on an '040, we already allocated a page
- * table for the first 4M. The address is stored in kpt by
- * arch/head.S
- *
- */
- if (CPU_IS_040_OR_060 && mem_mapped == 0)
- ktablep = kpt;
-
- for (physaddr = addr;
- physaddr < addr + size;
- mem_mapped += L3TREESIZE, virtaddr += L3TREESIZE) {
-
-#ifdef DEBUG
- printk ("pa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
+ if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) {
+ last_pgtable = (pmd_t *)*memavailp;
+ *memavailp += PAGE_SIZE;
- if (pindex > 127 && mem_mapped >= 32*ONEMEG) {
- /* we need a new pointer table every 32M */
-#ifdef DEBUG
- printk ("[new pointer]");
-#endif
+ clear_page((unsigned long)last_pgtable);
+ flush_page_to_ram((unsigned long)last_pgtable);
+ flush_tlb_kernel_page((unsigned long)last_pgtable);
+ nocache_page((unsigned long)last_pgtable);
+ } else
+ last_pgtable += PTRS_PER_PMD;
- kpointerp = (unsigned long *)get_kpointer_table ();
- pgd_set(pgd_offset_k(virtaddr), (pmd_t *)kpointerp);
- pindex = 0;
- }
+ return last_pgtable;
+}
- if (CPU_IS_040_OR_060) {
- int i;
- unsigned long ktable;
+static unsigned long __init
+map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+{
+#define PTRTREESIZE (256*1024)
+#define ROOTTREESIZE (32*1024*1024)
+ static unsigned long virtaddr = 0;
+ unsigned long physaddr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
- /* Don't map the first 4 MB again. The pagetables
- * for this range have already been initialized
- * in boot/head.S. Otherwise the pages used for
- * tables would be reinitialized to copyback mode.
- */
+ physaddr = (addr | m68k_supervisor_cachemode |
+ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ if (CPU_IS_040_OR_060)
+ physaddr |= _PAGE_GLOBAL040;
- if (mem_mapped < 4 * ONEMEG)
- {
+ while (size > 0) {
+#ifdef DEBUG
+ if (!(virtaddr & (PTRTREESIZE-1)))
+ printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
+ virtaddr);
+#endif
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (virtaddr && CPU_IS_020_OR_030) {
+ if (!(virtaddr & (ROOTTREESIZE-1)) &&
+ size >= ROOTTREESIZE) {
#ifdef DEBUG
- printk ("Already initialized\n");
+ printk ("[very early term]");
#endif
- physaddr += L3TREESIZE;
- pindex++;
+ pgd_val(*pgd_dir) = physaddr;
+ size -= ROOTTREESIZE;
+ virtaddr += ROOTTREESIZE;
+ physaddr += ROOTTREESIZE;
continue;
}
+ }
+ if (!pgd_present(*pgd_dir)) {
+ pmd_dir = kernel_ptr_table(memavailp);
#ifdef DEBUG
- printk ("[setup table]");
+ printk ("[new pointer %p]", pmd_dir);
#endif
+ pgd_set(pgd_dir, pmd_dir);
+ } else
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
- /*
- * 68040, use page tables pointed to by the
- * kernel pointer table.
- */
-
- if ((pindex & 15) == 0) {
- /* Need new page table every 4M on the '040 */
+ if (CPU_IS_020_OR_030) {
+ if (virtaddr) {
#ifdef DEBUG
- printk ("[new table]");
+ printk ("[early term]");
#endif
- ktablep = kernel_page_table (memavailp);
- }
-
- ktable = virt_to_phys(ktablep);
-
- /*
- * initialize section of the page table mapping
- * this 256K portion.
- */
- for (i = 0; i < 64; i++) {
- pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
- | m68k_supervisor_cachemode | _PAGE_GLOBAL040
- | _PAGE_ACCESSED;
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+ physaddr += PTRTREESIZE;
+ } else {
+ int i;
+#ifdef DEBUG
+ printk ("[zero map]");
+#endif
+ pte_dir = (pte_t *)kernel_ptr_table(memavailp);
+ pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
+ _PAGE_TABLE | _PAGE_ACCESSED;
+ pte_val(*pte_dir++) = 0;
physaddr += PAGE_SIZE;
+ for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
+ pte_val(*pte_dir++) = physaddr;
}
- ktablep += 64;
-
- /*
- * make the kernel pointer table point to the
- * kernel page table. Each entries point to a
- * 64 entry section of the page table.
- */
-
- kpointerp[pindex++] = ktable | _PAGE_TABLE | _PAGE_ACCESSED;
+ size -= PTRTREESIZE;
+ virtaddr += PTRTREESIZE;
} else {
- /*
- * 68030, use early termination page descriptors.
- * Each one points to 64 pages (256K).
- */
-#ifdef DEBUG
- printk ("[early term] ");
-#endif
- if (virtaddr == 0UL) {
- /* map the first 256K using a 64 entry
- * 3rd level page table.
- * UNMAP the first entry to trap
- * zero page (NULL pointer) references
- */
- int i;
- unsigned long *tbl;
-
- tbl = (unsigned long *)get_kpointer_table();
-
- kpointerp[pindex++] = virt_to_phys(tbl) | _PAGE_TABLE |_PAGE_ACCESSED;
-
- for (i = 0; i < 64; i++, physaddr += PAGE_SIZE)
- tbl[i] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED;
-
- /* unmap the zero page */
- tbl[0] = 0;
- } else {
- /* not the first 256K */
- kpointerp[pindex++] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED;
+ if (!pmd_present(*pmd_dir)) {
#ifdef DEBUG
- printk ("%lx=%lx ", virt_to_phys(&kpointerp[pindex-1]),
- kpointerp[pindex-1]);
+ printk ("[new table]");
#endif
- physaddr += 64 * PAGE_SIZE;
+ pte_dir = kernel_page_table(memavailp);
+ pmd_set(pmd_dir, pte_dir);
}
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ if (virtaddr) {
+ if (!pte_present(*pte_dir))
+ pte_val(*pte_dir) = physaddr;
+ } else
+ pte_val(*pte_dir) = 0;
+ size -= PAGE_SIZE;
+ virtaddr += PAGE_SIZE;
+ physaddr += PAGE_SIZE;
}
+
+ }
#ifdef DEBUG
- printk ("\n");
+ printk("\n");
#endif
- }
- return mem_mapped;
+ return virtaddr;
}
extern unsigned long free_area_init(unsigned long, unsigned long);
+extern void init_pointer_table(unsigned long ptable);
/* References to section boundaries */
extern char _text, _etext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
/*
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
*/
-__initfunc(unsigned long paging_init(unsigned long start_mem,
- unsigned long end_mem))
+unsigned long __init paging_init(unsigned long start_mem,
+ unsigned long end_mem)
{
int chunk;
unsigned long mem_avail = 0;
#ifdef DEBUG
{
- extern pte_t *kpt;
- printk ("start of paging_init (%p, %p, %lx, %lx, %lx)\n",
- kernel_pg_dir, kpt, availmem, start_mem, end_mem);
+ extern unsigned long availmem;
+ printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
+ kernel_pg_dir, availmem, start_mem, end_mem);
}
#endif
- init_kpointer_table();
-
/* Fix the cache mode in the page descriptors for the 680[46]0. */
if (CPU_IS_040_OR_060) {
int i;
@@ -366,6 +329,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
m68k_memory[chunk].size, &start_mem);
}
+
flush_tlb_all();
#ifdef DEBUG
printk ("memory available is %ldKB\n", mem_avail >> 10);
@@ -385,21 +349,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
start_mem += PAGE_SIZE;
memset((void *)empty_zero_page, 0, PAGE_SIZE);
-#if 0
/*
* allocate the "swapper" page directory and
* record in task 0 (swapper) tss
*/
- swapper_pg_dir = (pgd_t *)get_kpointer_table();
-
- init_mm.pgd = swapper_pg_dir;
-#endif
-
- memset (swapper_pg_dir, 0, sizeof(pgd_t)*PTRS_PER_PGD);
+ init_mm.pgd = (pgd_t *)kernel_ptr_table(&start_mem);
+ memset (init_mm.pgd, 0, sizeof(pgd_t)*PTRS_PER_PGD);
/* setup CPU root pointer for swapper task */
task[0]->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
- task[0]->tss.crp[1] = virt_to_phys (swapper_pg_dir);
+ task[0]->tss.crp[1] = virt_to_phys(init_mm.pgd);
#ifdef DEBUG
printk ("task 0 pagedir at %p virt, %#lx phys\n",
@@ -430,16 +389,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
#ifdef DEBUG
printk ("before free_area_init\n");
#endif
-
- return PAGE_ALIGN(free_area_init (start_mem, end_mem));
+ return PAGE_ALIGN(free_area_init(start_mem, end_mem));
}
-__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
+void __init mem_init(unsigned long start_mem, unsigned long end_mem)
{
int codepages = 0;
int datapages = 0;
int initpages = 0;
unsigned long tmp;
+ int i;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
@@ -480,6 +439,14 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
free_page(tmp);
}
+
+ /* insert pointer tables allocated so far into the tablelist */
+ init_pointer_table((unsigned long)kernel_pg_dir);
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (pgd_val(kernel_pg_dir[i]))
+ init_pointer_table(pgd_page(kernel_pg_dir[i]));
+ }
+
printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 802771ab4..d2cd29011 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -2,6 +2,9 @@
* linux/arch/m68k/mm/kmap.c
*
* Copyright (C) 1997 Roman Hodek
+ *
+ * 10/01/99 cleaned up the code and changing to the same interface
+ * used by other architectures /Roman Zippel
*/
#include <linux/mm.h>
@@ -9,250 +12,88 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/vmalloc.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/io.h>
#include <asm/system.h>
+#undef DEBUG
-extern pte_t *kernel_page_table (unsigned long *memavailp);
-
-/* Granularity of kernel_map() allocations */
-#define KMAP_STEP (256*1024)
-
-/* Size of pool of KMAP structures; that is needed, because kernel_map() can
- * be called at times where kmalloc() isn't initialized yet. */
-#define KMAP_POOL_SIZE 16
-
-/* structure for maintainance of kmap regions */
-typedef struct kmap {
- struct kmap *next, *prev; /* linking of list */
- unsigned long addr; /* start address of region */
- unsigned long mapaddr; /* address returned to user */
- unsigned long size; /* size of region */
- unsigned free : 1; /* flag whether free or allocated */
- unsigned kmalloced : 1; /* flag whether got this from kmalloc() */
- unsigned pool_alloc : 1; /* flag whether got this is alloced in pool */
-} KMAP;
-
-KMAP kmap_pool[KMAP_POOL_SIZE] = {
- { NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 },
- { NULL, NULL, 0, 0, 0, 0, 0, 0 },
-};
+#define PTRTREESIZE (256*1024)
/*
- * anchor of kmap region list
- *
- * The list is always ordered by addresses, and regions are always adjacent,
- * i.e. there must be no holes between them!
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
*/
-KMAP *kmap_regions = &kmap_pool[0];
-
-/* for protecting the kmap_regions list against races */
-static struct semaphore kmap_sem = MUTEX;
+#ifdef CPU_M68040_OR_M68060_ONLY
+#define IO_SIZE PAGE_SIZE
-/*
- * Low-level allocation and freeing of KMAP structures
- */
-static KMAP *alloc_kmap( int use_kmalloc )
+static inline struct vm_struct *get_io_area(unsigned long size)
{
- KMAP *p;
- int i;
-
- /* first try to get from the pool if possible */
- for( i = 0; i < KMAP_POOL_SIZE; ++i ) {
- if (!kmap_pool[i].pool_alloc) {
- kmap_pool[i].kmalloced = 0;
- kmap_pool[i].pool_alloc = 1;
- return( &kmap_pool[i] );
- }
- }
-
- if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) {
- p->kmalloced = 1;
- return( p );
- }
-
- return( NULL );
-}
-
-static void free_kmap( KMAP *p )
-{
- if (p->kmalloced)
- kfree( p );
- else
- p->pool_alloc = 0;
+ return get_vm_area(size);
}
-/*
- * Get a free region from the kmap address range
- */
-static KMAP *kmap_get_region( unsigned long size, int use_kmalloc )
+static inline void free_io_area(void *addr)
{
- KMAP *p, *q;
-
- /* look for a suitable free region */
- for( p = kmap_regions; p; p = p->next )
- if (p->free && p->size >= size)
- break;
- if (!p) {
- printk( KERN_ERR "kernel_map: address space for "
- "allocations exhausted\n" );
- return( NULL );
- }
-
- if (p->size > size) {
- /* if free region is bigger than we need, split off the rear free part
- * into a new region */
- if (!(q = alloc_kmap( use_kmalloc ))) {
- printk( KERN_ERR "kernel_map: out of memory\n" );
- return( NULL );
- }
- q->addr = p->addr + size;
- q->size = p->size - size;
- p->size = size;
- q->free = 1;
-
- q->prev = p;
- q->next = p->next;
- p->next = q;
- if (q->next) q->next->prev = q;
- }
-
- p->free = 0;
- return( p );
+ return vfree((void *)(PAGE_MASK & (unsigned long)addr));
}
+#else
-/*
- * Free a kernel_map region again
- */
-static void kmap_put_region( KMAP *p )
-{
- KMAP *q;
-
- p->free = 1;
+#define IO_SIZE (256*1024)
- /* merge with previous region if possible */
- q = p->prev;
- if (q && q->free) {
- if (q->addr + q->size != p->addr) {
- printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
- return;
- }
- q->size += p->size;
- q->next = p->next;
- if (p->next) p->next->prev = q;
- free_kmap( p );
- p = q;
- }
-
- /* merge with following region if possible */
- q = p->next;
- if (q && q->free) {
- if (p->addr + p->size != q->addr) {
- printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
- return;
- }
- p->size += q->size;
- p->next = q->next;
- if (q->next) q->next->prev = p;
- free_kmap( q );
- }
-}
+static struct vm_struct *iolist = NULL;
-
-/*
- * kernel_map() helpers
- */
-static inline pte_t *
-pte_alloc_kernel_map(pmd_t *pmd, unsigned long address,
- unsigned long *memavailp)
+static struct vm_struct *get_io_area(unsigned long size)
{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = kernel_page_table(memavailp);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- memset( page, 0, PAGE_SIZE );
- return page + address;
- }
- pmd_set(pmd, BAD_PAGETABLE);
- return NULL;
- }
- if (memavailp)
- panic("kernel_map: slept during init?!?");
- cache_page((unsigned long) page);
- free_page((unsigned long) page);
- }
- if (pmd_bad(*pmd)) {
- printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n",
- pmd_val(*pmd));
- pmd_set(pmd, BAD_PAGETABLE);
+ unsigned long addr;
+ struct vm_struct **p, *tmp, *area;
+
+ area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
return NULL;
+ addr = KMAP_START;
+ for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+ if (size + addr < (unsigned long)tmp->addr)
+ break;
+ if (addr > KMAP_END-size)
+ return NULL;
+ addr = tmp->size + (unsigned long)tmp->addr;
}
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-static inline void
-kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- pte_val(*pte) = phys_addr + pgprot_val(prot);
- address += PAGE_SIZE;
- phys_addr += PAGE_SIZE;
- pte++;
- } while (address < end);
+ area->addr = (void *)addr;
+ area->size = size + IO_SIZE;
+ area->next = *p;
+ *p = area;
+ return area;
}
-static inline int
-kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot,
- unsigned long *memavailp)
+static inline void free_io_area(void *addr)
{
- unsigned long end;
+ struct vm_struct **p, *tmp;
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
-
- if (CPU_IS_040_OR_060) {
- do {
- pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp);
- if (!pte)
- return -ENOMEM;
- kernel_map_pte(pte, address, end - address,
- address + phys_addr, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- } else {
- /* On the 68030 we use early termination page descriptors.
- Each one points to 64 pages (256K). */
- int i = (address >> (PMD_SHIFT-4)) & 15;
- do {
- (&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot);
- address += PMD_SIZE / 16;
- } while (address < end);
+ if (!addr)
+ return;
+ addr = (void *)((unsigned long)addr & -IO_SIZE);
+ for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+ if (tmp->addr == addr) {
+ *p = tmp->next;
+ __iounmap(tmp->addr, tmp->size);
+ kfree(tmp);
+ return;
+ }
}
- return 0;
}
+#endif
/*
* Map some physical address range into the kernel address space. The
@@ -260,304 +101,245 @@ kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size,
*/
/* Rewritten by Andreas Schwab to remove all races. */
-unsigned long kernel_map(unsigned long phys_addr, unsigned long size,
- int cacheflag, unsigned long *memavailp)
+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
- unsigned long retaddr, from, end;
- pgd_t *dir;
- pgprot_t prot;
- KMAP *kmap;
-
- /* Round down 'phys_addr' to 256 KB and adjust size */
- retaddr = phys_addr & (KMAP_STEP-1);
- size += retaddr;
- phys_addr &= ~(KMAP_STEP-1);
- /* Round up the size to 256 KB. It doesn't hurt if too much is
- mapped... */
- size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1);
-
- down( &kmap_sem );
- kmap = kmap_get_region(size, memavailp == NULL);
- if (!kmap) {
- up(&kmap_sem);
- return 0;
- }
- from = kmap->addr;
- retaddr += from;
- kmap->mapaddr = retaddr;
- end = from + size;
- up( &kmap_sem );
+ struct vm_struct *area;
+ unsigned long virtaddr, retaddr;
+ long offset;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ /*
+ * Don't allow mappings that wrap..
+ */
+ if (!size || size > physaddr + size)
+ return NULL;
+#ifdef DEBUG
+ printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+ /*
+ * Mappings have to be aligned
+ */
+ offset = physaddr & (IO_SIZE - 1);
+ physaddr &= -IO_SIZE;
+ size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_io_area(size);
+ if (!area)
+ return NULL;
+
+ virtaddr = (unsigned long)area->addr;
+ retaddr = virtaddr + offset;
+#ifdef DEBUG
+ printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+ /*
+ * add cache and table flags to physical address
+ */
if (CPU_IS_040_OR_060) {
- pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 |
- _PAGE_ACCESSED | _PAGE_DIRTY);
+ physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+ _PAGE_ACCESSED | _PAGE_DIRTY);
switch (cacheflag) {
- case KERNELMAP_FULL_CACHING:
- pgprot_val(prot) |= _PAGE_CACHE040;
+ case IOMAP_FULL_CACHING:
+ physaddr |= _PAGE_CACHE040;
break;
- case KERNELMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_SER:
default:
- pgprot_val(prot) |= _PAGE_NOCACHE_S;
+ physaddr |= _PAGE_NOCACHE_S;
break;
- case KERNELMAP_NOCACHE_NONSER:
- pgprot_val(prot) |= _PAGE_NOCACHE;
+ case IOMAP_NOCACHE_NONSER:
+ physaddr |= _PAGE_NOCACHE;
break;
- case KERNELMAP_NO_COPYBACK:
- pgprot_val(prot) |= _PAGE_CACHE040W;
+ case IOMAP_WRITETHROUGH:
+ physaddr |= _PAGE_CACHE040W;
break;
}
- } else
- pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED |
- _PAGE_DIRTY |
- ((cacheflag == KERNELMAP_FULL_CACHING ||
- cacheflag == KERNELMAP_NO_COPYBACK)
- ? 0 : _PAGE_NOCACHE030));
-
- phys_addr -= from;
- dir = pgd_offset_k(from);
- while (from < end) {
- pmd_t *pmd = pmd_alloc_kernel(dir, from);
-
- if (kernel_map_pmd(pmd, from, end - from, phys_addr + from,
- prot, memavailp)) {
- printk( KERN_ERR "kernel_map: out of memory\n" );
- return 0UL;
+ } else {
+ physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ switch (cacheflag) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ physaddr |= _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ break;
}
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
}
- return retaddr;
-}
-
+ while (size > 0) {
+#ifdef DEBUG
+ if (!(virtaddr & (PTRTREESIZE-1)))
+ printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+ pgd_dir = pgd_offset_k(virtaddr);
+ pmd_dir = pmd_alloc_kernel(pgd_dir, virtaddr);
+ if (!pmd_dir) {
+ printk("ioremap: no mem for pmd_dir\n");
+ return NULL;
+ }
-/*
- * kernel_unmap() helpers
- */
-static inline void pte_free_kernel_unmap( pmd_t *pmd )
-{
- unsigned long page = pmd_page(*pmd);
- mem_map_t *pagemap = &mem_map[MAP_NR(page)];
-
- pmd_clear(pmd);
- cache_page(page);
-
- if (PageReserved( pagemap )) {
- /* need to unreserve pages that were allocated with memavailp != NULL;
- * this works only if 'page' is page-aligned */
- if (page & ~PAGE_MASK)
- return;
- clear_bit( PG_reserved, &pagemap->flags );
- atomic_set( &pagemap->count, 1 );
- }
- free_page( page );
-}
+ if (CPU_IS_020_OR_030) {
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+ physaddr += PTRTREESIZE;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ } else {
+ pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+ if (!pte_dir) {
+ printk("ioremap: no mem for pte_dir\n");
+ return NULL;
+ }
-/*
- * This not only unmaps the requested region, but also loops over the whole
- * pmd to determine whether the other pte's are clear (so that the page can be
- * freed.) If so, it returns 1, 0 otherwise.
- */
-static inline int
-kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
-{
- pte_t *pte;
- unsigned long addr2, end, end2;
- int all_clear = 1;
-
- if (pmd_none(*pmd))
- return( 0 );
- if (pmd_bad(*pmd)) {
- printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n",
- pmd_val(*pmd) );
- pmd_clear(pmd);
- return( 0 );
- }
- address &= ~PMD_MASK;
- addr2 = 0;
- pte = pte_offset(pmd, addr2);
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- end2 = addr2 + PMD_SIZE;
- while( addr2 < end2 ) {
- if (!pte_none(*pte)) {
- if (address <= addr2 && addr2 < end)
- pte_clear(pte);
- else
- all_clear = 0;
+ pte_val(*pte_dir) = physaddr;
+ virtaddr += PAGE_SIZE;
+ physaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
- ++pte;
- addr2 += PAGE_SIZE;
}
- return( all_clear );
-}
-
-static inline void
-kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
-{
- pmd_t * pmd;
- unsigned long end;
+#ifdef DEBUG
+ printk("\n");
+#endif
+ flush_tlb_all();
- if (pgd_none(*dir))
- return;
- if (pgd_bad(*dir)) {
- printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n",
- pgd_val(*dir) );
- pgd_clear(dir);
- return;
- }
- pmd = pmd_offset(dir, address);
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
-
- if (CPU_IS_040_OR_060) {
- do {
- if (kernel_unmap_pte_range(pmd, address, end - address))
- pte_free_kernel_unmap( pmd );
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- } else {
- /* On the 68030 clear the early termination descriptors */
- int i = (address >> (PMD_SHIFT-4)) & 15;
- do {
- (&pmd_val(*pmd))[i++] = 0;
- address += PMD_SIZE / 16;
- } while (address < end);
- }
+ return (void *)retaddr;
}
/*
- * Unmap a kernel_map()ed region again
+ * Unmap a ioremap()ed region again
*/
-void kernel_unmap( unsigned long addr )
+void iounmap(void *addr)
{
- unsigned long end;
- pgd_t *dir;
- KMAP *p;
-
- down( &kmap_sem );
-
- /* find region for 'addr' in list; must search for mapaddr! */
- for( p = kmap_regions; p; p = p->next )
- if (!p->free && p->mapaddr == addr)
- break;
- if (!p) {
- printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" );
- return;
- }
- addr = p->addr;
- end = addr + p->size;
- kmap_put_region( p );
-
- dir = pgd_offset_k( addr );
- while( addr < end ) {
- kernel_unmap_pmd_range( dir, addr, end - addr );
- addr = (addr + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- }
-
- up( &kmap_sem );
- /* flushing for a range would do, but there's no such function for kernel
- * address space... */
- flush_tlb_all();
+ free_io_area(addr);
}
-
/*
- * kernel_set_cachemode() helpers
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
*/
-static inline void set_cmode_pte( pmd_t *pmd, unsigned long address,
- unsigned long size, unsigned cmode )
-{ pte_t *pte;
- unsigned long end;
-
- if (pmd_none(*pmd))
- return;
-
- pte = pte_offset( pmd, address );
- address &= ~PMD_MASK;
- end = address + size;
- if (end >= PMD_SIZE)
- end = PMD_SIZE;
-
- for( ; address < end; pte++ ) {
- pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode;
- address += PAGE_SIZE;
- }
-}
-
-
-static inline void set_cmode_pmd( pgd_t *dir, unsigned long address,
- unsigned long size, unsigned cmode )
+void __iounmap(void *addr, unsigned long size)
{
- pmd_t *pmd;
- unsigned long end;
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ while (size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
- if (pgd_none(*dir))
- return;
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & -16;
- pmd = pmd_offset( dir, address );
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
+ if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = 0;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ }
+ }
- if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) {
- /* 68030 early termination descriptor */
- pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode;
- return;
- }
- else {
- /* "normal" tables */
- for( ; address < end; pmd++ ) {
- set_cmode_pte( pmd, address, end - address, cmode );
- address = (address + PMD_SIZE) & PMD_MASK;
+ if (pmd_bad(*pmd_dir)) {
+ printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
}
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = 0;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
-}
+ flush_tlb_all();
+}
/*
* Set new cache mode for some kernel address space.
* The caller must push data for that range itself, if such data may already
* be in the cache.
*/
-void kernel_set_cachemode( unsigned long address, unsigned long size,
- unsigned cmode )
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
{
- pgd_t *dir = pgd_offset_k( address );
- unsigned long end = address + size;
-
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
if (CPU_IS_040_OR_060) {
- switch( cmode ) {
- case KERNELMAP_FULL_CACHING:
+ switch (cmode) {
+ case IOMAP_FULL_CACHING:
cmode = _PAGE_CACHE040;
break;
- case KERNELMAP_NOCACHE_SER:
- default:
+ case IOMAP_NOCACHE_SER:
+ default:
cmode = _PAGE_NOCACHE_S;
break;
- case KERNELMAP_NOCACHE_NONSER:
+ case IOMAP_NOCACHE_NONSER:
cmode = _PAGE_NOCACHE;
break;
- case KERNELMAP_NO_COPYBACK:
+ case IOMAP_WRITETHROUGH:
cmode = _PAGE_CACHE040W;
break;
}
- } else
- cmode = ((cmode == KERNELMAP_FULL_CACHING ||
- cmode == KERNELMAP_NO_COPYBACK) ?
- 0 : _PAGE_NOCACHE030);
-
- for( ; address < end; dir++ ) {
- set_cmode_pmd( dir, address, end - address, cmode );
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ } else {
+ switch (cmode) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ cmode = _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ cmode = 0;
+ }
+ }
+
+ while (size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+
+ if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+ _CACHEMASK040) | cmode;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ }
+ }
+
+ if (pmd_bad(*pmd_dir)) {
+ printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
+ }
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
- /* flushing for a range would do, but there's no such function for kernel
- * address space... */
+
flush_tlb_all();
}
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 39cc1d1a9..a97578ec2 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -10,6 +10,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/segment.h>
@@ -97,6 +98,31 @@ static ptable_desc ptable_list = { &ptable_list, &ptable_list };
#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
+void __init init_pointer_table(unsigned long ptable)
+{
+ ptable_desc *dp;
+ unsigned long page = ptable & PAGE_MASK;
+ unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE);
+
+ dp = PAGE_PD(page);
+ if (!(PD_MARKBITS(dp) & mask)) {
+ PD_MARKBITS(dp) = 0xff;
+ (dp->prev = ptable_list.prev)->next = dp;
+ (dp->next = &ptable_list)->prev = dp;
+ }
+
+ PD_MARKBITS(dp) &= ~mask;
+#ifdef DEBUG
+ printk("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));
+#endif
+
+ /* unreserve the page so it's possible to free that page */
+ dp->flags &= ~(1 << PG_reserved);
+ atomic_set(&dp->count, 1);
+
+ return;
+}
+
pmd_t *get_pointer_table (void)
{
ptable_desc *dp = ptable_list.next;
@@ -176,103 +202,6 @@ int free_pointer_table (pmd_t *ptable)
return 0;
}
-/* maximum pages used for kpointer tables */
-#define KPTR_PAGES 4
-/* # of reserved slots */
-#define RESERVED_KPTR 4
-extern pmd_tablepage kernel_pmd_table; /* reserved in head.S */
-
-static struct kpointer_pages {
- pmd_tablepage *page[KPTR_PAGES];
- u_char alloced[KPTR_PAGES];
-} kptr_pages;
-
-void init_kpointer_table(void) {
- short i = KPTR_PAGES-1;
-
- /* first page is reserved in head.S */
- kptr_pages.page[i] = &kernel_pmd_table;
- kptr_pages.alloced[i] = ~(0xff>>RESERVED_KPTR);
- for (i--; i>=0; i--) {
- kptr_pages.page[i] = NULL;
- kptr_pages.alloced[i] = 0;
- }
-}
-
-pmd_t *get_kpointer_table (void)
-{
- /* For pointer tables for the kernel virtual address space,
- * use the page that is reserved in head.S that can hold up to
- * 8 pointer tables. 3 of these tables are always reserved
- * (kernel_pg_dir, swapper_pg_dir and kernel pointer table for
- * the first 16 MB of RAM). In addition, the 4th pointer table
- * in this page is reserved. On Amiga and Atari, it is used to
- * map in the hardware registers. It may be used for other
- * purposes on other 68k machines. This leaves 4 pointer tables
- * available for use by the kernel. 1 of them are usually used
- * for the vmalloc tables. This allows mapping of 3 * 32 = 96 MB
- * of physical memory. But these pointer tables are also used
- * for other purposes, like kernel_map(), so further pages can
- * now be allocated.
- */
- pmd_tablepage *page;
- pmd_table *table;
- long nr, offset = -8;
- short i;
-
- for (i=KPTR_PAGES-1; i>=0; i--) {
- asm volatile("bfffo %1{%2,#8},%0"
- : "=d" (nr)
- : "d" ((u_char)~kptr_pages.alloced[i]), "d" (offset));
- if (nr)
- break;
- }
- if (i < 0) {
- printk("No space for kernel pointer table!\n");
- return NULL;
- }
- if (!(page = kptr_pages.page[i])) {
- if (!(page = (pmd_tablepage *)get_free_page(GFP_KERNEL))) {
- printk("No space for kernel pointer table!\n");
- return NULL;
- }
- flush_tlb_kernel_page((unsigned long) page);
- nocache_page((u_long)(kptr_pages.page[i] = page));
- }
- asm volatile("bfset %0@{%1,#1}"
- : /* no output */
- : "a" (&kptr_pages.alloced[i]), "d" (nr-offset));
- table = &(*page)[nr-offset];
- memset(table, 0, sizeof(pmd_table));
- return ((pmd_t *)table);
-}
-
-void free_kpointer_table (pmd_t *pmdp)
-{
- pmd_table *table = (pmd_table *)pmdp;
- pmd_tablepage *page = (pmd_tablepage *)((u_long)table & PAGE_MASK);
- long nr;
- short i;
-
- for (i=KPTR_PAGES-1; i>=0; i--) {
- if (kptr_pages.page[i] == page)
- break;
- }
- nr = ((u_long)table - (u_long)page) / sizeof(pmd_table);
- if (!table || i < 0 || (i == KPTR_PAGES-1 && nr < RESERVED_KPTR)) {
- printk("Attempt to free invalid kernel pointer table: %p\n", table);
- return;
- }
- asm volatile("bfclr %0@{%1,#1}"
- : /* no output */
- : "a" (&kptr_pages.alloced[i]), "d" (nr));
- if (!kptr_pages.alloced[i]) {
- kptr_pages.page[i] = 0;
- cache_page ((u_long)page);
- free_page ((u_long)page);
- }
-}
-
static unsigned long transp_transl_matches( unsigned long regval,
unsigned long vaddr )
{
@@ -308,7 +237,6 @@ static unsigned long transp_transl_matches( unsigned long regval,
*/
unsigned long mm_vtop (unsigned long vaddr)
{
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int i=0;
unsigned long voff = vaddr;
unsigned long offset = 0;
@@ -324,10 +252,6 @@ unsigned long mm_vtop (unsigned long vaddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
-#else
- if (vaddr < m68k_memory[0].size)
- return m68k_memory[0].addr + vaddr;
-#endif
return mm_vtop_fallback(vaddr);
}
@@ -449,7 +373,6 @@ unsigned long mm_vtop_fallback (unsigned long vaddr)
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
unsigned long mm_ptov (unsigned long paddr)
{
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int i = 0;
unsigned long offset = 0;
@@ -466,11 +389,6 @@ unsigned long mm_ptov (unsigned long paddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
-#else
- unsigned long base = m68k_memory[0].addr;
- if (paddr >= base && paddr < (base + m68k_memory[0].size))
- return (paddr - base);
-#endif
/*
* assume that the kernel virtual address is the same as the
@@ -560,7 +478,7 @@ unsigned long mm_ptov (unsigned long paddr)
* Jes was worried about performance (urhh ???) so its optional
*/
-extern void (*mach_l2_flush)(int) = NULL;
+void (*mach_l2_flush)(int) = NULL;
#endif
/*
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
index fbb370a07..9cc0d39d1 100644
--- a/arch/m68k/mvme16x/16xints.c
+++ b/arch/m68k/mvme16x/16xints.c
@@ -106,9 +106,12 @@ void mvme16x_free_irq(unsigned int irq, void *dev_id)
void mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
{
if (vec < 64 || vec > 255)
- panic ("mvme16x_process_int: Illegal vector %ld", vec);
- irq_tab[vec-64].count++;
- irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+ printk ("mvme16x_process_int: Illegal vector %ld", vec);
+ else
+ {
+ irq_tab[vec-64].count++;
+ irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+ }
}
int mvme16x_get_irq_list (char *buf)
diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds
index 88ee16b66..b79c9dd87 100644
--- a/arch/m68k/vmlinux.lds
+++ b/arch/m68k/vmlinux.lds
@@ -35,6 +35,9 @@ SECTIONS
_edata = .; /* End of data section */
+ . = ALIGN(16);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 8c66ff8c9..298e3d760 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -175,33 +175,35 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
if [ "$CONFIG_SGI" != "y" ]; then
- source drivers/net/hamradio/Config.in
+ source drivers/net/hamradio/Config.in
- mainmenu_option next_comment
- comment 'ISDN subsystem'
- tristate 'ISDN support' CONFIG_ISDN
- if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
- fi
- endmenu
+ mainmenu_option next_comment
+ comment 'ISDN subsystem'
- mainmenu_option next_comment
- comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+ if [ "$CONFIG_NET" != "n" ]; then
+ tristate 'ISDN support' CONFIG_ISDN
+ if [ "$CONFIG_ISDN" != "n" ]; then
+ source drivers/isdn/Config.in
+ fi
+ fi
+ endmenu
- bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
- if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
- source drivers/cdrom/Config.in
- fi
- endmenu
+
+ mainmenu_option next_comment
+ comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+
+ bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+ source drivers/cdrom/Config.in
+ fi
+ endmenu
fi
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/mips/defconfig b/arch/mips/defconfig
index 1b9ec2d0d..0b3de2ffe 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -142,6 +142,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
@@ -149,14 +150,16 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
@@ -210,6 +213,8 @@ CONFIG_PCNET32=y
# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
# CONFIG_WAN_DRIVERS is not set
# CONFIG_LAPBETHER is not set
# CONFIG_X25_ASY is not set
@@ -250,9 +255,17 @@ CONFIG_SERIAL=m
# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
CONFIG_RTC=y
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -264,35 +277,42 @@ CONFIG_RTC=y
# Filesystems
#
CONFIG_QUOTA=y
-CONFIG_MINIX_FS=m
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
+CONFIG_AUTOFS_FS=m
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_UMSDOS_FS=m
CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_MINIX_FS=m
+# CONFIG_NTFS_FS is not set
+CONFIG_HPFS_FS=m
CONFIG_PROC_FS=y
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=m
-CONFIG_NFSD=m
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=m
CONFIG_LOCKD=m
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
-CONFIG_HPFS_FS=m
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_AUTOFS_FS=m
-# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
#
@@ -323,6 +343,7 @@ CONFIG_NLS_ISO8859_6=m
CONFIG_NLS_ISO8859_7=m
CONFIG_NLS_ISO8859_8=m
CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_KOI8_R=m
#
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index cc4919bff..e7372fbc3 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.12 1998/06/30 00:21:49 ralf Exp $
+/* $Id: irq.c,v 1.13 1999/01/03 17:50:50 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -334,7 +334,7 @@ unsigned long probe_irq_on (void)
}
/* wait for spurious interrupts to mask themselves out again */
- for (delay = jiffies + HZ/10; delay > jiffies; )
+ for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
/* about 100ms delay */;
/* now filter out any obviously spurious interrupts */
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 38bef5f56..302eee2b1 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: mips_ksyms.c,v 1.13 1999/02/07 21:56:32 ulfc Exp $
+/* $Id: mips_ksyms.c,v 1.14 1999/02/09 22:54:10 adevries Exp $
*
* Export MIPS-specific functions needed for loadable modules.
*
@@ -50,6 +50,7 @@ EXPORT_SYMBOL_NOVERS(strncat);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(__mips_bh_counter);
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index ac7bfb771..6fb6735fd 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1,4 +1,4 @@
-/* $Id: ptrace.c,v 1.9 1998/09/19 19:16:16 ralf Exp $
+/* $Id: ptrace.c,v 1.10 1999/01/03 17:50:52 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -337,7 +337,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
res = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (res < 0)
goto out;
res = put_user(tmp,(unsigned long *) data);
@@ -406,7 +408,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
res = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: {
diff --git a/arch/mips/kernel/scall_o32.S b/arch/mips/kernel/scall_o32.S
index 42cb4311d..b31a8b18e 100644
--- a/arch/mips/kernel/scall_o32.S
+++ b/arch/mips/kernel/scall_o32.S
@@ -44,6 +44,7 @@ NESTED(handle_sys, PT_SIZE, sp)
beqz t2, illegal_syscall;
subu t0, t3, 5 # 5 or more arguments?
+ sw a3, PT_R26(sp) # save a3 for syscall restarting
bgez t0, stackargs
stack_done:
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index bca8b228f..c9d832c92 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.16 1998/08/25 09:14:41 ralf Exp $
+/* $Id: signal.c,v 1.17 1998/08/28 23:29:05 tsbogend Exp $
*
* linux/arch/mips/kernel/signal.c
*
@@ -392,6 +392,7 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
}
/* fallthrough */
case ERESTARTNOINTR: /* Userland will reload $v0. */
+ regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 8;
}
@@ -525,6 +526,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (regs->regs[2] == ERESTARTNOHAND ||
regs->regs[2] == ERESTARTSYS ||
regs->regs[2] == ERESTARTNOINTR) {
+ regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 8;
}
}
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 11415b79f..67e550cf3 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -1,10 +1,10 @@
-/* $Id: syscall.c,v 1.10 1998/08/20 14:38:40 ralf Exp $
+/* $Id: syscall.c,v 1.9 1998/08/25 09:14:41 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995 - 1998 by Ralf Baechle
+ * Copyright (C) 1995 - 1999 by Ralf Baechle
*
* TODO: Implement the compatibility syscalls.
* Don't waste that much memory for empty entries in the syscall
@@ -80,11 +80,10 @@ out:
asmlinkage int sys_idle(void)
{
unsigned long start_idle = 0;
- int ret = -EPERM;
- lock_kernel();
if (current->pid != 0)
- goto out;
+ return -EPERM;
+
/* endless idle loop with no priority at all */
current->priority = 0;
current->counter = 0;
@@ -110,10 +109,8 @@ asmlinkage int sys_idle(void)
start_idle = 0;
schedule();
}
- ret = 0;
-out:
- unlock_kernel();
- return ret;
+
+ return 0;
}
asmlinkage int sys_fork(struct pt_regs regs)
@@ -121,9 +118,7 @@ asmlinkage int sys_fork(struct pt_regs regs)
int res;
save_static(&regs);
- lock_kernel();
res = do_fork(SIGCHLD, regs.regs[29], &regs);
- unlock_kernel();
return res;
}
@@ -134,13 +129,11 @@ asmlinkage int sys_clone(struct pt_regs regs)
int res;
save_static(&regs);
- lock_kernel();
clone_flags = regs.regs[4];
newsp = regs.regs[5];
if (!newsp)
newsp = regs.regs[29];
res = do_fork(clone_flags, newsp, &regs);
- unlock_kernel();
return res;
}
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index e6c27cd52..0c4503da5 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.14 1999/02/01 01:28:56 ralf Exp $
+/* $Id: sysirix.c,v 1.15 1999/02/06 05:12:57 adevries Exp $
*
* sysirix.c: IRIX system call emulation.
*
@@ -2020,6 +2020,7 @@ out:
asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
{
struct file *file;
+ struct dentry *dentry;
struct inode *inode;
struct irix_dirent32 *lastdirent;
struct irix_dirent32_callback buf;
@@ -2031,44 +2032,55 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count
current->pid, fd, dirent, count, eob);
#endif
error = -EBADF;
- if (!(file = fget(fd)))
+ file = fget(fd);
+ if (!file)
goto out;
- /* Shouldn't it be ENOENT? */
- inode = file->f_dentry->d_inode;
- if (!inode)
- goto out_f;
-
- error = -ENOTDIR;
- if (!file->f_op || !file->f_op->readdir)
- goto out_f;
+ dentry = file->f_dentry;
+ if (!dentry)
+ goto out_putf;
- error = -EFAULT;
- if(!access_ok(VERIFY_WRITE, dirent, count) ||
- !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
- goto out_f;
+ inode = dentry->d_inode;
+ if (!inode)
+ goto out_putf;
- __put_user(0, eob);
buf.current_dir = (struct irix_dirent32 *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out_putf;
+
+ /*
+ * Get the inode's semaphore to prevent changes
+ * to the directory while we read it.
+ */
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, irix_filldir32);
+ up(&inode->i_sem);
if (error < 0)
- goto out_f;
+ goto out_putf;
+ error = buf.error;
lastdirent = buf.previous;
- if (!lastdirent) {
- error = buf.error;
- goto out_f;
+ if (lastdirent) {
+ put_user(file->f_pos, &lastdirent->d_off);
+ error = count - buf.count;
+ }
+
+ if (put_user(0, eob) < 0) {
+ error = EFAULT;
+ goto out_putf;
}
- lastdirent->d_off = (u32) file->f_pos;
+
+
#ifdef DEBUG_GETDENTS
printk("eob=%d returning %d\n", *eob, count - buf.count);
#endif
error = count - buf.count;
-out_f:
+out_putf:
fput(file);
out:
unlock_kernel();
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index cab6598db..1491da82d 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.9 1999/01/04 16:03:49 ralf Exp $
+/* $Id: time.c,v 1.10 1999/02/01 01:26:32 ralf Exp $
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
* Copyright (C) 1996, 1997, 1998 Ralf Baechle
@@ -253,9 +253,11 @@ void do_settimeofday(struct timeval *tv)
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = MAXPHASE;
- time_esterror = MAXPHASE;
+ 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();
}
@@ -265,6 +267,9 @@ void 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)
{
@@ -301,8 +306,12 @@ static int 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
@@ -353,9 +362,10 @@ timer_interrupt(int irq, void *dev_id, 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 && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2)
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index f7fa99a37..5a9b651ff 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.9 1998/09/19 19:16:18 ralf Exp $
+/* $Id: init.c,v 1.10 1999/01/04 16:03:53 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -132,6 +132,7 @@ static inline unsigned long setup_zero_pages(void)
pg = MAP_NR(empty_zero_page);
while(pg < MAP_NR(empty_zero_page) + (1 << order)) {
set_bit(PG_reserved, &mem_map[pg].flags);
+ atomic_set(&mem_map[pg].count, 0);
pg++;
}
@@ -293,8 +294,9 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
end_mem &= PAGE_MASK;
- max_mapnr = num_physpages = MAP_NR(end_mem);
+ max_mapnr = MAP_NR(end_mem);
high_memory = (void *)end_mem;
+ num_physpages = 0;
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
@@ -324,6 +326,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
datapages++;
continue;
}
+ num_physpages++;
atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_start || (tmp < initrd_start || tmp >=
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 8c3401d6f..126b724be 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -1,4 +1,5 @@
/*
+ * $Id: enet.c,v 1.8 1998/11/15 19:58:07 cort Exp $
* Ethernet driver for Motorola MPC8xx.
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
*
@@ -657,7 +658,7 @@ __initfunc(int cpm_enet_init(void))
cp = cpmp; /* Get pointer to Communication Processor */
- immap = (immap_t *)MBX_IMAP_ADDR; /* and to internal registers */
+ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
/* Allocate some private information.
*/
@@ -719,11 +720,11 @@ __initfunc(int cpm_enet_init(void))
* These are relative offsets in the DP ram address space.
* Initialize base addresses for the buffer descriptors.
*/
- i = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);
+ i = m8xx_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);
ep->sen_genscc.scc_rbase = i;
cep->rx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
- i = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);
+ i = m8xx_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);
ep->sen_genscc.scc_tbase = i;
cep->tx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
@@ -912,4 +913,3 @@ __initfunc(int cpm_enet_init(void))
return 0;
}
-
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
index fdbd0c796..94901245f 100644
--- a/arch/ppc/8xx_io/uart.c
+++ b/arch/ppc/8xx_io/uart.c
@@ -1692,7 +1692,7 @@ static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
schedule_timeout(char_time);
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
bdp = info->tx_cur;
} while (bdp->cbd_sc & BD_SC_READY);
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index cd98b4513..990b24b84 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -16,8 +16,6 @@ KERNELLOAD =0xc0000000
ifeq ($(shell uname -m),ppc)
CHECKS = checks
-else
-CROSS_COMPILE = ppc-linux-elf-
endif
ASFLAGS =
diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c
index 690173cc9..e8f72f298 100644
--- a/arch/ppc/amiga/amiints.c
+++ b/arch/ppc/amiga/amiints.c
@@ -19,7 +19,7 @@
* - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
* they're executed irq level is set to the previous
* one, but handlers don't need to be reentrant, if
- * reentrance occured, slow handlers will be just
+ * reentrance occurred, slow handlers will be just
* called again.
* The whole interrupt handling for CIAs is moved to cia.c
* /Roman Zippel
@@ -396,7 +396,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
for (;;) {
for (; node; node = node->next)
node->handler(irq, node->dev_id, fp);
- /* if reentrance occured, serve slow handlers again */
+ /* if reentrance occurred, serve slow handlers again */
custom.intena = ami_intena_vals[irq];
if (!server->reentrance) {
server->count--;
diff --git a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c
index f24a0c5b8..7639de68e 100644
--- a/arch/ppc/amiga/bootinfo.c
+++ b/arch/ppc/amiga/bootinfo.c
@@ -17,8 +17,8 @@
extern char cmd_line[CL_SIZE];
int num_memory = 0;
-extern struct mem_info memory[NUM_MEMINFO];
-extern struct mem_info ramdisk;
+struct mem_info memory[NUM_MEMINFO];
+struct mem_info ramdisk;
extern int amiga_parse_bootinfo(const struct bi_record *);
extern int atari_parse_bootinfo(const struct bi_record *);
diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c
index f79172390..2335adfb9 100644
--- a/arch/ppc/amiga/config.c
+++ b/arch/ppc/amiga/config.c
@@ -742,7 +742,7 @@ static void amiga_savekmsg_init(void)
static void amiga_serial_putc(char c)
{
custom.serdat = (unsigned char)c | 0x100;
- iobarrier ();
+ iobarrier_rw ();
while (!(custom.serdatr & 0x2000))
;
}
diff --git a/arch/ppc/apus_defconfig b/arch/ppc/apus_defconfig
index 1e9499a9c..c9f900cfe 100644
--- a/arch/ppc/apus_defconfig
+++ b/arch/ppc/apus_defconfig
@@ -14,6 +14,7 @@ CONFIG_PMAC=y
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
# CONFIG_MBX is not set
+# CONFIG_SMP is not set
CONFIG_MACH_SPECIFIC=y
#
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index fde1ad4c6..da4945fd7 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -48,6 +48,9 @@ OBJECTS += mbxtty.o
CFLAGS += -DCONFIG_MBX
else
OBJECTS += vreset.o kbd.o
+ ifeq ($(CONFIG_SERIAL_CONSOLE),y)
+ OBJECTS += ns16550.o
+ endif
endif
all: zImage
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index 42cb533da..470e1e4a9 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -1,7 +1,7 @@
/*
* misc.c
*
- * $Id: misc.c,v 1.52 1998/09/19 01:21:24 cort Exp $
+ * $Id: misc.c,v 1.53 1998/12/15 17:40:15 cort Exp $
*
* Adapted for PowerPC by Gary Thomas
*
@@ -12,7 +12,7 @@
#include <linux/types.h>
#include "../coffboot/zlib.h"
#include "asm/residual.h"
-#include <elf.h>
+#include <linux/elf.h>
#include <linux/config.h>
#include <asm/page.h>
#include <asm/processor.h>
@@ -23,6 +23,10 @@
#ifdef CONFIG_FADS
#include <asm/fads.h>
#endif
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#include "ns16550.h"
+struct NS16550 *com_port;
+#endif /* CONFIG_SERIAL_CONSOLE */
/*
* Please send me load/board info and such data for hardware not
@@ -42,6 +46,7 @@ char *end_avail;
* save here and pass to the kernel (command line and board info).
* On the MBX we grab some known memory holes to hold this information.
*/
+char cmd_preset[] = "console=tty0 console=ttyS0,9600n8";
char cmd_buf[256];
char *cmd_line = cmd_buf;
@@ -108,12 +113,19 @@ static void scroll()
tstc(void)
{
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+ return (CRT_tstc() || NS16550_tstc(com_port));
+#else
return (CRT_tstc() );
+#endif /* CONFIG_SERIAL_CONSOLE */
}
getc(void)
{
while (1) {
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+ if (NS16550_tstc(com_port)) return (NS16550_getc(com_port));
+#endif /* CONFIG_SERIAL_CONSOLE */
if (CRT_tstc()) return (CRT_getc());
}
}
@@ -123,6 +135,11 @@ putc(const char c)
{
int x,y;
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+ NS16550_putc(com_port, c);
+ if ( c == '\n' ) NS16550_putc(com_port, '\r');
+#endif /* CONFIG_SERIAL_CONSOLE */
+
x = orig_x;
y = orig_y;
@@ -162,12 +179,21 @@ void puts(const char *s)
y = orig_y;
while ( ( c = *s++ ) != '\0' ) {
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+ NS16550_putc(com_port, c);
+ if ( c == '\n' ) NS16550_putc(com_port, '\r');
+#endif /* CONFIG_SERIAL_CONSOLE */
+
if ( c == '\n' ) {
x = 0;
if ( ++y >= lines ) {
scroll();
y--;
}
+ } else if (c == '\b') {
+ if (x > 0) {
+ x--;
+ }
} else {
vidmem [ ( x + cols * y ) * 2 ] = c;
if ( ++x >= cols ) {
@@ -358,6 +384,10 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
_put_MSR(_get_MSR() & ~0x0030);
vga_init(0xC0000000);
+#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+ com_port = (struct NS16550 *)NS16550_init(0);
+#endif /* CONFIG_SERIAL_CONSOLE */
+
if (residual)
memcpy(hold_residual,residual,sizeof(RESIDUAL));
#else /* CONFIG_MBX */
@@ -510,6 +540,8 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
puts("\nLinux/PPC load: ");
timer = 0;
cp = cmd_line;
+ memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
+ while ( *cp ) putc(*cp++);
while (timer++ < 5*1000) {
if (tstc()) {
while ((ch = getc()) != '\n' && ch != '\r') {
diff --git a/arch/ppc/boot/ns16550.c b/arch/ppc/boot/ns16550.c
new file mode 100644
index 000000000..db0b94d03
--- /dev/null
+++ b/arch/ppc/boot/ns16550.c
@@ -0,0 +1,56 @@
+/*
+ * COM1 NS16550 support
+ */
+
+#include "ns16550.h"
+typedef struct NS16550 *NS16550_t;
+
+const NS16550_t COM_PORTS[] = { (NS16550_t) COM1,
+ (NS16550_t) COM2,
+ (NS16550_t) COM3,
+ (NS16550_t) COM4 };
+
+volatile struct NS16550 *
+NS16550_init(int chan)
+{
+ volatile struct NS16550 *com_port;
+ volatile unsigned char xx;
+ com_port = (struct NS16550 *) COM_PORTS[chan];
+ /* See if port is present */
+ com_port->lcr = 0x00;
+ com_port->ier = 0xFF;
+#if 0
+ if (com_port->ier != 0x0F) return ((struct NS16550 *)0);
+#endif
+ com_port->ier = 0x00;
+ com_port->lcr = 0x80; /* Access baud rate */
+ com_port->dll = 0xc; /* 9600 baud */
+ com_port->dlm = 0xc >> 8;
+ com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
+ com_port->mcr = 0x03; /* RTS/DTR */
+ com_port->fcr = 0x07; /* Clear & enable FIFOs */
+ return (com_port);
+}
+
+
+NS16550_putc(volatile struct NS16550 *com_port, unsigned char c)
+{
+ volatile int i;
+ while ((com_port->lsr & LSR_THRE) == 0) ;
+ com_port->thr = c;
+}
+
+unsigned char
+NS16550_getc(volatile struct NS16550 *com_port)
+{
+ while ((com_port->lsr & LSR_DR) == 0) ;
+ return (com_port->rbr);
+}
+
+NS16550_tstc(volatile struct NS16550 *com_port)
+{
+ return ((com_port->lsr & LSR_DR) != 0);
+}
+
+
+
diff --git a/arch/ppc/boot/ns16550.h b/arch/ppc/boot/ns16550.h
new file mode 100644
index 000000000..4baf4c1c5
--- /dev/null
+++ b/arch/ppc/boot/ns16550.h
@@ -0,0 +1,34 @@
+/*
+ * NS16550 Serial Port
+ */
+
+struct NS16550
+ {
+ unsigned char rbr; /* 0 */
+ unsigned char ier; /* 1 */
+ unsigned char fcr; /* 2 */
+ unsigned char lcr; /* 3 */
+ unsigned char mcr; /* 4 */
+ unsigned char lsr; /* 5 */
+ unsigned char msr; /* 6 */
+ unsigned char scr; /* 7 */
+ };
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+
+#define LSR_DR 0x01 /* Data ready */
+#define LSR_OE 0x02 /* Overrun */
+#define LSR_PE 0x04 /* Parity error */
+#define LSR_FE 0x08 /* Framing error */
+#define LSR_BI 0x10 /* Break */
+#define LSR_THRE 0x20 /* Xmit holding register empty */
+#define LSR_TEMT 0x40 /* Xmitter empty */
+#define LSR_ERR 0x80 /* Error */
+
+#define COM1 0x800003F8
+#define COM2 0x800002F8
+#define COM3 0x800003F8
+#define COM4 0x80000388
diff --git a/arch/ppc/chrp_defconfig b/arch/ppc/chrp_defconfig
index dcaf4b2d5..9141b2d90 100644
--- a/arch/ppc/chrp_defconfig
+++ b/arch/ppc/chrp_defconfig
@@ -14,6 +14,7 @@ CONFIG_CHRP=y
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
# CONFIG_MBX is not set
+# CONFIG_SMP is not set
CONFIG_MACH_SPECIFIC=y
#
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
index 72a6df455..4669d2228 100644
--- a/arch/ppc/coffboot/Makefile
+++ b/arch/ppc/coffboot/Makefile
@@ -3,18 +3,6 @@
#
# Paul Mackerras January 1997
-# PowerPC (cross) tools
-ifneq ($(shell uname -m),ppc)
-CROSS_COMPILE =powerpc-eabi-
-endif
-
-
-# PowerPC (cross) tools
-ifneq ($(shell uname -m),ppc)
-#CROSS_COMPILE =powerpc-eabi-
-CROSS_COMPILE =ppc-linux-elf-
-endif
-
HOSTCC = gcc
HOSTCFLAGS = -O -I$(TOPDIR)/include
diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig
index 916af99f1..f58965709 100644
--- a/arch/ppc/common_defconfig
+++ b/arch/ppc/common_defconfig
@@ -14,6 +14,7 @@ CONFIG_6xx=y
CONFIG_ALL_PPC=y
# CONFIG_APUS is not set
# CONFIG_MBX is not set
+# CONFIG_SMP is not set
#
# General setup
@@ -45,9 +46,9 @@ CONFIG_ADBMOUSE=y
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_PROC_DEVICETREE=y
# CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
# CONFIG_TOTALMP is not set
-# CONFIG_BOOTX_TEXT is not set
+CONFIG_BOOTX_TEXT=y
#
# Plug and Play support
@@ -113,6 +114,10 @@ CONFIG_SKB_LARGE=y
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -132,6 +137,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
@@ -139,14 +145,16 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
@@ -170,7 +178,7 @@ CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
# CONFIG_SCSI_DEBUG is not set
CONFIG_SCSI_MESH=y
CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MAC53C94=m
+CONFIG_SCSI_MAC53C94=y
#
# Network device support
@@ -188,6 +196,7 @@ CONFIG_BMAC=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
CONFIG_PCNET32=m
@@ -219,6 +228,7 @@ CONFIG_SLIP=m
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
#
# Amateur Radio support
@@ -239,14 +249,31 @@ CONFIG_SLIP=m
# Console drivers
#
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_OF is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_IMSTT=y
+CONFIG_FB_CT65550=y
+# CONFIG_FB_S3TRIO is not set
# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-# CONFIG_FBCON_FONTS is not set
+CONFIG_FBCON_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+CONFIG_FONT_SUN12x22=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
#
# Character devices
@@ -258,6 +285,10 @@ CONFIG_SERIAL=m
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
CONFIG_MOUSE=y
+
+#
+# Mice
+#
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
# CONFIG_MS_BUSMOUSE is not set
@@ -266,9 +297,17 @@ CONFIG_PSMOUSE=y
# CONFIG_PC110_PAD is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -280,36 +319,46 @@ CONFIG_PSMOUSE=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
-CONFIG_NFSD=y
+CONFIG_NFSD=m
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_NLS=y
#
@@ -340,6 +389,7 @@ CONFIG_NLS=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
#
@@ -368,6 +418,7 @@ CONFIG_SOUND_OSS=y
# CONFIG_SOUND_OPL3SA2 is not set
# CONFIG_SOUND_MAUI is not set
# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_OPL3SA1 is not set
# CONFIG_SOUND_SOFTOSS is not set
# CONFIG_SOUND_YM3812 is not set
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 59223a45c..b15e90afd 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -22,6 +22,9 @@ choice 'Machine Type' \
if [ "$CONFIG_ALL_PPC" != "y" ];then
define_bool CONFIG_MACH_SPECIFIC y
fi
+
+bool 'Symmetric multi-processing support' CONFIG_SMP
+
endmenu
if [ "$CONFIG_MBX" = "y" ];then
@@ -164,7 +167,6 @@ endmenu
source drivers/char/Config.in
source fs/Config.in
-source fs/nls/Config.in
mainmenu_option next_comment
comment 'Sound'
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index ae1303bb4..811d599c0 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -15,6 +15,7 @@ CONFIG_PMAC=y
# CONFIG_APUS is not set
# CONFIG_MBX is not set
CONFIG_MACH_SPECIFIC=y
+# CONFIG_SMP is not set
#
# General setup
@@ -137,6 +138,10 @@ CONFIG_ATALK=m
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -164,6 +169,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
@@ -174,14 +180,16 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
@@ -218,6 +226,7 @@ CONFIG_BMAC=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
@@ -225,7 +234,7 @@ CONFIG_NET_EISA=y
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
-CONFIG_DEC_ELCP=m
+# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_LNE390 is not set
@@ -253,6 +262,7 @@ CONFIG_PPP=y
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
#
# Amateur Radio support
@@ -282,6 +292,7 @@ CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
CONFIG_FBCON_CFB8=y
@@ -303,7 +314,7 @@ CONFIG_FONT_SUN12x22=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
@@ -311,9 +322,17 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-CONFIG_NVRAM=y
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -325,37 +344,47 @@ CONFIG_NVRAM=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
CONFIG_NFSD=y
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_NLS=y
#
@@ -386,6 +415,7 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
#
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 4846d5ebb..d047c2086 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -15,8 +15,7 @@ OX_OBJS := ppc_ksyms.o setup.o
O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \
- bitops.o ptrace.o align.o ppc_htab.o feature.o
-
+ bitops.o ptrace.o align.o ppc_htab.o
ifdef CONFIG_PCI
O_OBJS += pci.o
endif
@@ -33,15 +32,17 @@ else
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o prom.o openpic.o
else
+ifneq ($(CONFIG_MBX),y)
O_OBJS += prep_time.o pmac_time.o chrp_time.o \
pmac_setup.o pmac_support.o \
prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o openpic.o
+ residual.o prom.o openpic.o feature.o
OX_OBJS += chrp_setup.o prep_setup.o
endif
endif
+endif
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += smp.o
endif
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index 93c2fe2d1..c3a81ad3e 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -329,9 +329,9 @@ unsigned long mm_ptov (unsigned long paddr)
int i;
for (i = 0; i < kmap_chunk_count;){
- unsigned long virt = kmap_chunks[i++];
- unsigned long size = kmap_chunks[i++];
unsigned long phys = kmap_chunks[i++];
+ unsigned long size = kmap_chunks[i++];
+ unsigned long virt = kmap_chunks[i++];
if (paddr >= phys
&& paddr < (phys + size)){
ret = virt + paddr - phys;
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 4c528beb8..d7b791387 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,7 +1,7 @@
/*
* arch/ppc/kernel/head.S
*
- * $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $
+ * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -148,6 +148,10 @@ _start:
* r4: virtual address of boot_infos_t
* r5: 0
*
+ * APUS
+ * r3: 'APUS'
+ * Linux/m68k style BootInfo structure at &_end.
+ *
* PREP
* This is jumped to on prep systems right after the kernel is relocated
* to its proper place in memory by the boot loader. The expected layout
@@ -528,9 +532,10 @@ HardwareInterrupt:
stw r3,(_CCR+4)(r21);
#endif
- addi r3,r1,STACK_FRAME_OVERHEAD;
- li r20,MSR_KERNEL;
- bl transfer_to_handler;
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ li r4,0
+ bl transfer_to_handler
.long do_IRQ;
.long int_return
@@ -1195,18 +1200,34 @@ stack_ovf:
* physical address of the hash table are known. These definitions
* of Hash_base and Hash_bits below are just an example.
*/
-/*
- * Note that the 603s won't come here, since the 603
- * loads tlb directly into the tlb from the linux tables, while
- * others (601, 604, etc.) call hash_page() to load entries from
- * the linux tables into the hash table. -- Cort
- */
Hash_base = 0x180000
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
-
+
+ .globl hash_table_lock
+hash_table_lock:
+.long 0
+
.globl hash_page
hash_page:
+#ifdef __SMP__
+ lis r2,hash_table_lock@h
+ ori r2,r2,hash_table_lock@l
+ tophys(r2,r2,r6)
+ lis r6,100000000@h
+ mtctr r6
+ lwz r0,PROCESSOR-TSS(r5)
+ or r0,r0,r6
+10: lwarx r6,0,r2
+ cmpi 0,r6,0
+ bne- 12f
+ stwcx. r0,0,r2
+ beq+ 11f
+12: cmpw r6,r0
+ bdnzf 2,10b
+ tw 31,31,31
+11:
+#endif
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
tophys(r5,r5,r2) /* convert to phys addr */
@@ -1253,6 +1274,9 @@ hash_page_patch_A:
li r2,8 /* PTEs/group */
bne 10f /* no PTE: go look for an empty slot */
tlbie r3 /* invalidate TLB entry */
+#ifdef __SMP__
+ tlbsync
+#endif
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
@@ -1297,7 +1321,6 @@ hash_page_patch_C:
bdnzf 2,2b
beq+ found_empty
-#if 1
/*
* Choose an arbitrary slot in the primary PTEG to overwrite.
* Since both the primary and secondary PTEGs are full, and we
@@ -1313,26 +1336,6 @@ hash_page_patch_C:
andi. r2,r2,0x38
stw r2,next_slot@l(0)
add r3,r4,r2
-#else
- /* now, allow 2nd hash as well as 1st */
- lwz r2,next_slot@l(0)
- addi r2,r2,8
- andi. r2,r2,0x78
- stw r2,next_slot@l(0)
- cmpi 0,0,r2,0x38 /* if it's the 2nd hash */
- bgt second_evict
-first_evict:
- xori r5,r5,0x40 /* clear H bit again */
- add r3,r4,r2
- b 11f
-second_evict:
- .globl hash_page_patch_D
-hash_page_patch_D:
- xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
- xori r3,r3,0xffc0
- subi r2,r2,0x40
- addi r3,r3,r2
-#endif
11:
/* update counter of evicted pages */
lis r2,htab_evicts@h
@@ -1372,6 +1375,13 @@ found_slot:
addi r3,r3,1
stw r3,0(r2)
+#ifdef __SMP__
+ lis r2,hash_table_lock@ha
+ tophys(r2,r2,r6)
+ li r0,0
+ stw r0,hash_table_lock@l(r2)
+#endif
+
/* Return from the exception */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
@@ -1392,6 +1402,12 @@ found_slot:
rfi
hash_page_out:
+#ifdef __SMP__
+ lis r2,hash_table_lock@ha
+ tophys(r2,r2,r6)
+ li r0,0
+ stw r0,hash_table_lock@l(r2)
+#endif
blr
next_slot:
.long 0
@@ -1709,6 +1725,9 @@ start_here:
2:
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+#ifdef __SMP__
+ tlbsync
+#endif
#ifndef CONFIG_8xx
mtspr SDR1,r6
li r0,16 /* load up segment register values */
@@ -1980,16 +1999,13 @@ _GLOBAL(_switch)
/* FALL THROUGH into int_return */
#ifdef __SMP__
- /* drop scheduler_lock since we weren't called by schedule() */
+ /* call schedule_tail if this is the first time for a child process */
lwz r5,TSS_SMP_FORK_RET(r4)
cmpi 0,r5,0
beq+ int_return
li r3,0
- lis r5,scheduler_lock@ha
stw r3,TSS_SMP_FORK_RET(r4)
- stw r3,scheduler_lock@l+4(r5) /* owner_pc */
- stw r3,scheduler_lock@l+8(r5) /* owner_cpu */
- stw r3,scheduler_lock@l(r5) /* lock */
+ bl schedule_tail
#endif /* __SMP__ */
/*
@@ -2089,6 +2105,7 @@ _GLOBAL(fake_interrupt)
li r0,0x0fac
stw r0,TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
+ li r4,1
bl do_IRQ
addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
lwz r0,4(r1)
@@ -2206,8 +2223,31 @@ _GLOBAL(flush_hash_segments)
rlwinm r0,r0,16,27,31
lis r9,PVR_603_LIKE@h
rlwnm. r0,r9,r0,0,0
- bne 99f
+ beq+ 99f
+ tlbia
+ isync
+ blr
+99:
#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ /* Note - we had better not do anything which could generate
+ a hash table miss while we have the hash table locked,
+ or we'll get a deadlock. -paulus */
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,8
+10: lwarx r6,0,r9
+ cmpi 0,r6,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+#endif
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
@@ -2229,8 +2269,16 @@ _GLOBAL(flush_hash_segments)
stw r0,0(r5) /* invalidate entry */
2: bdnz 1b /* continue with loop */
sync
-99: tlbia
+ tlbia
isync
+#ifdef __SMP__
+ tlbsync
+ lis r3,hash_table_lock@ha
+ li r0,0
+ stw r0,hash_table_lock@l(r3)
+ mtmsr r10
+ SYNC
+#endif
blr
/*
@@ -2244,8 +2292,31 @@ _GLOBAL(flush_hash_page)
rlwinm r0,r0,16,27,31
lis r9,PVR_603_LIKE@h
rlwnm. r0,r9,r0,0,0
- bne 99f
+ beq+ 99f
+ tlbie r4 /* in hw tlb too */
+ isync
+ blr
+99:
#endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+ /* Note - we had better not do anything which could generate
+ a hash table miss while we have the hash table locked,
+ or we'll get a deadlock. -paulus */
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,9
+10: lwarx r6,0,r9
+ cmpi 0,r6,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+#endif
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
oris r3,r3,0x8000 /* set V (valid) bit */
@@ -2278,10 +2349,19 @@ _GLOBAL(flush_hash_page)
3: li r0,0
stw r0,0(r7) /* invalidate entry */
4: sync
-99: tlbie r4 /* in hw tlb too */
+ tlbie r4 /* in hw tlb too */
isync
+#ifdef __SMP__
+ tlbsync
+ lis r3,hash_table_lock@h
+ li r0,0
+ stw r0,hash_table_lock@l(r3)
+ mtmsr r10
+ SYNC
+#endif
blr
#endif /* CONFIG_8xx */
+
/*
* This routine is just here to keep GCC happy - sigh...
*/
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index b6c338946..af163699b 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $
+ * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -41,26 +41,25 @@ unsigned long powersave_nap = 0;
int idled(void *unused)
{
- int ret = -EPERM;
-
+ /* endless loop with no priority at all */
+ current->priority = 0;
+ current->counter = -100;
for (;;)
{
__sti();
- /* endless loop with no priority at all */
- current->priority = 0;
- current->counter = 0;
-
check_pgt_cache();
if ( !current->need_resched && zero_paged_on ) zero_paged();
if ( !current->need_resched && htab_reclaim_on ) htab_reclaim();
if ( !current->need_resched ) power_save();
- run_task_queue(&tq_scheduler);
- schedule();
+
+#ifdef __SMP__
+ if (current->need_resched)
+#endif
+ schedule();
}
- ret = 0;
- return ret;
+ return 0;
}
#ifdef __SMP__
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index a180e5f0a..f4a7c7143 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,4 +1,6 @@
/*
+ * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
+ *
* arch/ppc/kernel/irq.c
*
* Derived from arch/i386/kernel/irq.c
@@ -6,6 +8,7 @@
* Adapted from arch/i386 by Gary Thomas
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
* Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ * Copyright (C) 1996 Cort Dougan
* Adapted for Power Macintosh by Paul Mackerras
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
* Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
@@ -309,14 +312,14 @@ static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
static void mbx_mask_irq(unsigned int irq_nr)
{
cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
cached_irq_mask[0];
}
static void mbx_unmask_irq(unsigned int irq_nr)
{
cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
cached_irq_mask[0];
}
#endif /* CONFIG_8xx */
@@ -454,7 +457,6 @@ static inline void wait_on_bh(void)
}
-#define MAXCOUNT 100000000
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
@@ -507,7 +509,7 @@ static inline void wait_on_irq(int cpu)
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
- wait_on_bh();
+ wait_on_bh();
}
@@ -529,6 +531,8 @@ void synchronize_irq(void)
static inline void get_irqlock(int cpu)
{
+ unsigned int loops = MAXCOUNT;
+
if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ((unsigned char) cpu == global_irq_holder)
@@ -536,12 +540,17 @@ static inline void get_irqlock(int cpu)
/* Uhhuh.. Somebody else got it. Wait.. */
do {
do {
-
+ if (loops-- == 0) {
+ printk("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
} while (test_bit(0,&global_irq_lock));
} while (test_and_set_bit(0,&global_irq_lock));
}
/*
- * We also to make sure that nobody else is running
+ * We also need to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
@@ -637,7 +646,7 @@ void __global_restore_flags(unsigned long flags)
#endif /* __SMP__ */
-asmlinkage void do_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
{
int irq;
unsigned long bits;
@@ -656,9 +665,14 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
#ifdef __SMP__
if ( cpu != 0 )
{
- if (!atomic_read(&n_lost_interrupts))
+ if (!isfake)
{
extern void smp_message_recv(void);
+#ifdef CONFIG_XMON
+ static int xmon_2nd;
+ if (xmon_2nd)
+ xmon(regs);
+#endif
smp_message_recv();
goto out;
}
@@ -666,6 +680,25 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
mess with the controller from the second cpu -- Cort */
goto out;
}
+
+ {
+ unsigned int loops = MAXCOUNT;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
#endif /* __SMP__ */
switch ( _machine )
@@ -799,9 +832,13 @@ apus_out:
}
if (irq < 0) {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
+ /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */
+ if ( irq != second_irq )
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ spurious_interrupts++;
+ }
goto out;
}
@@ -809,7 +846,7 @@ apus_out:
/* For MPC8xx, read the SIVEC register and shift the bits down
* to get the irq number.
*/
- bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec;
+ bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
irq = bits >> 26;
#endif /* CONFIG_8xx */
mask_and_ack_irq(irq);
@@ -1089,17 +1126,6 @@ __initfunc(void init_IRQ(void))
*/
if ( _prep_type == _PREP_IBM )
irq_mode2 |= 0xa0;
- /*
- * Sound on the Powerstack reportedly needs to be edge triggered
- */
- if ( _prep_type == _PREP_Motorola )
- {
- irq_mode2 &= ~0x04L;
- irq_mode2 = 0xca;
- outb( irq_mode1 , 0x4d0 );
- outb( irq_mode2 , 0x4d1 );
- }
-
}
break;
#ifdef CONFIG_APUS
@@ -1116,8 +1142,7 @@ __initfunc(void init_IRQ(void))
/* This routine will fix some missing interrupt values in the device tree
* on the gatwick mac-io controller used by some PowerBooks
*/
-__pmac
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
{
struct device_node *node;
static struct interrupt_info int_pool[4];
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
index 9d26e27d1..90647dcd9 100644
--- a/arch/ppc/kernel/mbx_setup.c
+++ b/arch/ppc/kernel/mbx_setup.c
@@ -1,4 +1,6 @@
/*
+ * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ *
* linux/arch/ppc/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
@@ -51,17 +53,27 @@ extern int rd_image_start; /* starting block # of image */
extern char saved_command_line[256];
extern unsigned long find_available_memory(void);
-extern void mbx_cpm_reset(uint);
-
+extern void m8xx_cpm_reset(uint);
-void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+/* this really does make things cleaner -- Cort */
+void __init powermac_init(void)
{
+}
- *p = 0;
- *irq = 0;
+void __init adbdev_init(void)
+{
+}
- if (base != 0) /* Only map the first ATA flash drive */
- return;
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
#ifdef ATA_FLASH
base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
for (i = 0; i < 8; ++i)
@@ -88,7 +100,7 @@ mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
/* Reset the Communication Processor Module.
*/
- mbx_cpm_reset(cpm_page);
+ m8xx_cpm_reset(cpm_page);
#ifdef notdef
ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index f13508d96..e4589b1e0 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -383,6 +383,177 @@ _GLOBAL(_set_THRM3)
mtspr THRM3,r3
blr
+_GLOBAL(_get_PVR)
+ mfspr r3,PVR
+ blr
+/*
+ L2CR functions
+ Copyright © 1997-1998 by PowerLogix R & D, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ Thur, Dec. 12, 1998.
+ - First public release, contributed by PowerLogix.
+
+ Author: Terry Greeniaus (tgree@phys.ualberta.ca)
+ Please e-mail updates to this file to me, thanks!
+*/
+
+_GLOBAL(_set_L2CR)
+ /* Usage:
+
+ When setting the L2CR register, you must do a few special things. If you are enabling the
+ cache, you must perform a global invalidate. If you are disabling the cache, you must
+ flush the cache contents first. This routine takes care of doing these things. When first
+ enabling the cache, make sure you pass in the L2CR you want, as well as passing in the
+ global invalidate bit set. A global invalidate will only be performed if the L2I bit is set
+ in applyThis. When enabling the cache, you should also set the L2E bit in applyThis. If you
+ want to modify the L2CR contents after the cache has been enabled, the recommended
+ procedure is to first call __setL2CR(0) to disable the cache and then call it again with
+ the new values for L2CR. Examples:
+
+ _setL2CR(0) - disables the cache
+ _setL2CR(0xB3A04000) - enables my G3 upgrade card:
+ - L2E set to turn on the cache
+ - L2SIZ set to 1MB
+ - L2CLK set to 1:1
+ - L2RAM set to pipelined syncronous late-write
+ - L2I set to perform a global invalidation
+ - L2OH set to 0.5 nS
+ - L2DF set because this upgrade card requires it
+
+ A similar call should work for your card. You need to know the correct setting for your
+ card and then place them in the fields I have outlined above. Other fields support optional
+ features, such as L2DO which caches only data, or L2TS which causes cache pushes from
+ the L1 cache to go to the L2 cache instead of to main memory.
+ */
+
+ /* Make sure this is a 750 chip */
+ mfspr r4,PVR
+ rlwinm r4,r4,16,16,31
+ cmplwi r4,0x0008
+ beq thisIs750
+ li r3,-1
+ blr
+
+thisIs750:
+ /* Get the current enable bit of the L2CR into r4 */
+ mfspr r4,L2CR
+ rlwinm r4,r4,0,0,0
+
+ /* See if we want to perform a global inval this time. */
+ rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */
+ rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */
+ rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */
+ rlwinm r3,r3,0,1,31 /* Turn off the enable bit */
+ or r3,r3,r4 /* Keep the enable bit the same as it was for now. */
+ bne dontDisableCache /* Only disable the cache if L2CRApply has the enable bit off */
+
+disableCache:
+ /* Disable the cache. First, we turn off data relocation. */
+ mfmsr r7
+ rlwinm r4,r7,0,28,26 /* Turn off DR bit */
+ rlwinm r4,r4,0,17,15 /* Turn off EE bit - an external exception while we are flushing
+ the cache is fatal (comment this line and see!) */
+ sync
+ mtmsr r4
+ sync
+
+ /*
+ Now, read the first 2MB of memory to put new data in the cache.
+ (Actually we only need the size of the L2 cache plus
+ the size of the L1 cache, but 2MB will cover everything just to be safe).
+ */
+ lis r4,0x0001
+ mtctr r4
+ li r4,0
+loadLoop:
+ lwzx r0,r0,r4
+ addi r4,r4,0x0020 /* Go to start of next cache line */
+ bdnz loadLoop
+
+ /* Now, flush the first 2MB of memory */
+ lis r4,0x0001
+ mtctr r4
+ li r4,0
+ sync
+flushLoop:
+ dcbf r0,r4
+ addi r4,r4,0x0020 /* Go to start of next cache line */
+ bdnz flushLoop
+
+ /* Turn off the L2CR enable bit. */
+ rlwinm r3,r3,0,1,31
+
+ /* Reenable data relocation. */
+ sync
+ mtmsr r7
+ sync
+
+dontDisableCache:
+ /* Set up the L2CR configuration bits */
+ sync
+ mtspr L2CR,r3
+ sync
+ cmplwi r6,0
+ beq noInval
+
+ /* Perform a global invalidation */
+ oris r3,r3,0x0020
+ sync
+ mtspr 1017,r3
+ sync
+invalCompleteLoop: /* Wait for the invalidation to complete */
+ mfspr r3,1017
+ rlwinm. r4,r3,0,31,31
+ bne invalCompleteLoop
+
+ rlwinm r3,r3,0,11,9; /* Turn off the L2I bit */
+ sync
+ mtspr L2CR,r3
+ sync
+
+noInval:
+ /* See if we need to enable the cache */
+ cmplwi r5,0
+ beqlr
+
+enableCache:
+ /* Enable the cache */
+ oris r3,r3,0x8000
+ mtspr L2CR,r3
+ sync
+ blr
+
+_GLOBAL(_get_L2CR)
+ /* Make sure this is a 750 chip */
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmplwi r3,0x0008
+ li r3,0
+ bnelr
+
+ /* Return the L2CR contents */
+ mfspr r3,L2CR
+ blr
+
+/* --- End of PowerLogix code ---
+ */
+
+/*
_GLOBAL(_get_L2CR)
mfspr r3,L2CR
blr
@@ -391,9 +562,7 @@ _GLOBAL(_set_L2CR)
mtspr L2CR,r3
blr
-_GLOBAL(_get_PVR)
- mfspr r3,PVR
- blr
+*/
/*
* These are used in the alignment trap handler when emulating
@@ -441,16 +610,6 @@ _GLOBAL(__kernel_thread)
bnelr /* return if parent */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
-#if 0/*def __SMP__*/
- /* drop scheduler_lock since schedule() called us */
- lis r4,scheduler_lock@ha
- li r5,0
- stw r5,scheduler_lock@l+4(r4) /* owner_pc */
- stw r5,scheduler_lock@l+8(r4) /* owner_cpu */
- stw r5,scheduler_lock@l(r4)
- sync
- isync
-#endif /* __SMP__ */
blrl
li r0,__NR_exit /* exit after child exits */
li r3,0
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 359446f4f..1dfa3a6c8 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $
+ * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
@@ -123,8 +123,8 @@ __initfunc(void pcibios_init(void))
__initfunc(void
setup_pci_ptrs(void))
{
- PPC_DEVICE *hostbridge;
#ifndef CONFIG_MBX
+ PPC_DEVICE *hostbridge;
switch (_machine) {
case _MACH_prep:
hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
@@ -188,13 +188,8 @@ __initfunc(void pcibios_fixup(void))
extern struct bridge_data **bridges;
extern unsigned char *Motherboard_map;
extern unsigned char *Motherboard_routes;
-
- /*
- * FIXME: This is broken: We should not assign IRQ's to IRQless
- * devices (look at PCI_INTERRUPT_PIN) and we also should
- * honor the existence of multi-function devices where
- * different functions have different interrupt pins. [mj]
- */
+ unsigned char i;
+#ifndef CONFIG_MBX
switch (_machine )
{
case _MACH_prep:
@@ -208,6 +203,21 @@ __initfunc(void pcibios_fixup(void))
*/
unsigned char d = PCI_SLOT(dev->devfn);
dev->irq = Motherboard_routes[Motherboard_map[d]];
+ for ( i = 0 ; i <= 5 ; i++ )
+ {
+ if ( dev->base_address[i] > 0x10000000 )
+ {
+ printk("Relocating PCI address %x -> %x\n",
+ dev->base_address[i],
+ (dev->base_address[i] & 0x00FFFFFF)
+ | 0x01000000);
+ dev->base_address[i] =
+ (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(dev,
+ PCI_BASE_ADDRESS_0+(i*0x4),
+ dev->base_address[i] );
+ }
+ }
#if 0
/*
* If we have residual data and if it knows about this
@@ -255,6 +265,11 @@ __initfunc(void pcibios_fixup(void))
}
break;
}
+#else /* CONFIG_MBX */
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ }
+#endif /* CONFIG_MBX */
}
__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 3aa0534ea..30123c076 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -1,5 +1,5 @@
/*
- * $Id: ppc_htab.c,v 1.25 1998/08/26 10:28:26 davem Exp $
+ * $Id: ppc_htab.c,v 1.26 1998/12/10 00:24:23 cort Exp $
*
* PowerPC hash table management proc entry. Will show information
* about the current hash table and will allow changes to it.
@@ -569,6 +569,7 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
break;
buffer += len;
left -= len;
+ _set_L2CR(0);
_set_L2CR(val);
while ( _get_L2CR() & 0x1 )
/* wait for invalidate to finish */;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index ea5f6db0d..1b7753dd0 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -25,6 +25,7 @@
#include <asm/pci-bridge.h>
#include <asm/irq.h>
#include <asm/feature.h>
+#include <asm/spinlock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -32,7 +33,7 @@
extern void transfer_to_handler(void);
extern void int_return(void);
extern void syscall_trace(void);
-extern void do_IRQ(struct pt_regs *regs);
+extern void do_IRQ(struct pt_regs *regs, int isfake);
extern void MachineCheckException(struct pt_regs *regs);
extern void AlignmentException(struct pt_regs *regs);
extern void ProgramCheckException(struct pt_regs *regs);
@@ -156,6 +157,19 @@ EXPORT_SYMBOL(_get_PVR);
EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
+#ifdef __SMP__
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(spin_trylock);
+EXPORT_SYMBOL(_read_lock);
+EXPORT_SYMBOL(_read_unlock);
+EXPORT_SYMBOL(_write_lock);
+EXPORT_SYMBOL(_write_unlock);
+#endif
#ifndef CONFIG_MACH_SPECIFIC
EXPORT_SYMBOL(_machine);
@@ -180,12 +194,15 @@ EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
+#ifdef CONFIG_SCSI
EXPORT_SYMBOL(note_scsi_host);
+#endif
EXPORT_SYMBOL(kd_mksound);
#ifdef CONFIG_PMAC
EXPORT_SYMBOL(nvram_read_byte);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index b7d94d208..b48f7a1fc 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $
+ * $Id: prep_pci.c,v 1.24 1998/12/10 02:39:51 cort Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -107,7 +107,7 @@ static char Omaha_pci_IRQ_routes[] __prepdata =
};
/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] __prepdata =
+static char Blackhawk_pci_IRQ_map[19] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
@@ -125,6 +125,9 @@ static char Blackhawk_pci_IRQ_map[16] __prepdata =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
+ 1, /* Slot P7 */
+ 2, /* Slot P6 */
+ 3, /* Slot P5 */
};
static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -132,7 +135,7 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata =
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
- 14, /* Line 3 */
+ 15, /* Line 3 */
15 /* Line 4 */
};
@@ -226,6 +229,7 @@ static char ibm8xx_pci_IRQ_map[23] __prepdata = {
0, /* Slot 21 - unused */
2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
};
+
static char ibm8xx_pci_IRQ_routes[] __prepdata = {
0, /* Line 0 - unused */
13, /* Line 1 */
@@ -440,6 +444,8 @@ __initfunc(unsigned long route_pci_interrupts(void))
if ( _prep_type == _PREP_Motorola)
{
+ unsigned short irq_mode;
+
switch (inb(0x800) & 0xF0)
{
case 0x10: /* MVME16xx */
@@ -474,6 +480,14 @@ __initfunc(unsigned long route_pci_interrupts(void))
Motherboard_routes = Blackhawk_pci_IRQ_routes;
break;
}
+ /* AJF adjust level/edge control according to routes */
+ irq_mode = 0;
+ for (i = 1; i <= 4; i++)
+ {
+ irq_mode |= ( 1 << Motherboard_routes[i] );
+ }
+ outb( irq_mode & 0xff, 0x4d0 );
+ outb( (irq_mode >> 8) & 0xff, 0x4d1 );
} else if ( _prep_type == _PREP_IBM )
{
unsigned char pl_id;
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index e596f9ea5..72752e11f 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -189,11 +189,6 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
/* Enable L2. Assume we don't need to flush -- Cort*/
*(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3;
- /* make the serial port the console */
- /* strcat(cmd_line,"console=ttyS0,9600n8"); */
- /* use the normal console but send output to the serial port, too */
- /*strcat(cmd_line,"console=tty0 console=ttyS0,9600n8");*/
- sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line);
printk("Boot arguments: %s\n", cmd_line);
#ifdef CONFIG_SOUND_CS4232
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 5ea55cee9..ebe64a429 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,4 +1,6 @@
/*
+ * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $
+ *
* linux/arch/ppc/kernel/process.c
*
* Derived from "arch/i386/kernel/process.c"
@@ -180,13 +182,6 @@ switch_to(struct task_struct *prev, struct task_struct *new)
if ( prev->tss.regs->msr & MSR_FP )
smp_giveup_fpu(prev);
- /* be noisy about processor changes for debugging -- Cort */
- if ( (new->last_processor != NO_PROC_ID) &&
- (new->last_processor != new->processor) )
- printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
- new->last_processor,new->processor,
- new->comm,new->pid);
-
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
@@ -236,6 +231,19 @@ void show_regs(struct pt_regs * regs)
out:
}
+void instruction_dump (unsigned long *pc)
+{
+ int i;
+
+ if((((unsigned long) pc) & 3))
+ return;
+
+ printk("Instruction DUMP:");
+ for(i = -3; i < 6; i++)
+ printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+ printk("\n");
+}
+
void exit_thread(void)
{
if (last_task_used_math == current)
@@ -450,6 +458,7 @@ print_backtrace(unsigned long *sp)
printk("\n");
}
+#if 0
/*
* Low level print for debugging - Cort
*/
@@ -537,3 +546,4 @@ __initfunc(void ll_puts(const char *s))
orig_x = x;
orig_y = y;
}
+#endif
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 62b2b03af..e2c6b13a0 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -362,7 +362,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
ret = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (ret < 0)
goto out;
ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
@@ -410,7 +412,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* If I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
ret = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 706c1dde2..50cd70889 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $
+ * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $
* Common prep/pmac/chrp boot and setup code.
*/
@@ -35,7 +35,7 @@ extern unsigned long m68k_machtype;
extern int parse_bootinfo(const struct bi_record *);
extern char _end[];
#ifdef CONFIG_APUS
-struct mem_info ramdisk;
+extern struct mem_info ramdisk;
unsigned long isa_io_base;
unsigned long isa_mem_base;
unsigned long pci_dram_offset;
@@ -259,6 +259,9 @@ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
break;
}
#endif
+#if defined(CONFIG_MBX)
+ mbx_ide_init_hwif_ports(p,base,irq);
+#endif
}
EXPORT_SYMBOL(ide_init_hwif_ports);
#endif
@@ -464,9 +467,9 @@ int get_cpuinfo(char *buffer)
* Find out what kind of machine we're on and save any data we need
* from the early boot process (devtree is copied on pmac by prom_init() )
*/
-__initfunc(unsigned long
+unsigned long __init
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7))
+ unsigned long r6, unsigned long r7)
{
extern void setup_pci_ptrs(void);
@@ -491,6 +494,9 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
char *model;
have_of = 1;
+
+ /* prom_init has already been called from __start */
+ finish_device_tree();
/* ask the OF info if we're a chrp or pmac */
model = get_property(find_path_device("/"), "device_type", NULL);
if ( model && !strncmp("chrp",model,4) )
@@ -510,8 +516,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
if ( have_of )
{
+#ifdef CONFIG_MACH_SPECIFIC
/* prom_init has already been called from __start */
finish_device_tree();
+#endif /* CONFIG_MACH_SPECIFIC */
/*
* If we were booted via quik, r3 points to the physical
* address of the command-line parameters.
@@ -665,7 +673,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
#else /* CONFIG_MBX */
if ( r3 )
- memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
#ifdef CONFIG_PCI
setup_pci_ptrs();
@@ -693,9 +701,22 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
extern int __map_without_bats;
__map_without_bats = 1;
}
+
return 0;
}
+/* Checks "l2cr=xxxx" command-line option */
+void ppc_setup_l2cr(char *str, int *ints)
+{
+ if ( (_get_PVR() >> 16) == 8)
+ {
+ unsigned long val = simple_strtoul(str, NULL, 0);
+ printk(KERN_INFO "l2cr set to %lx\n", val);
+ _set_L2CR(0);
+ _set_L2CR(val);
+ }
+}
+
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 75445925f..ba505e133 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,5 +1,5 @@
/*
- * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $
+ * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
*
* Smp support for ppc.
*
@@ -43,6 +43,7 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
int first_cpu_booted = 0;
+cycles_t cacheflush_time;
/* all cpu mappings are 1-1 -- Cort */
int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
@@ -144,7 +145,14 @@ void smp_message_recv(void)
void smp_send_reschedule(int cpu)
{
- smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
+ /* This is only used if `cpu' is running an idle task,
+ so it will reschedule itself anyway... */
+ /*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+}
+
+void smp_send_stop(void)
+{
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
}
spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
@@ -152,7 +160,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
if ( _machine != _MACH_Pmac )
return;
- /*printk("SMP %d: sending smp message\n", current->processor);*/
+printk("SMP %d: sending smp message %x\n", current->processor, msg);
if (smp_processor_id() ) printk("pass from cpu 1\n");
spin_lock(&mesg_pass_lock);
#define OTHER (~smp_processor_id() & 1)
@@ -179,17 +187,18 @@ if (smp_processor_id() ) printk("pass from cpu 1\n");
spin_unlock(&mesg_pass_lock);
}
-__initfunc(void smp_boot_cpus(void))
+void __init smp_boot_cpus(void)
{
extern struct task_struct *current_set[NR_CPUS];
extern void __secondary_start(void);
int i;
struct task_struct *p;
-
+ unsigned long a;
+
printk("Entering SMP Mode...\n");
first_cpu_booted = 1;
- dcbf(&first_cpu_booted);
+ /*dcbf(&first_cpu_booted);*/
for (i = 0; i < NR_CPUS; i++) {
prof_counter[i] = 1;
@@ -200,7 +209,13 @@ __initfunc(void smp_boot_cpus(void))
smp_store_cpu_info(0);
active_kernel_processor = 0;
current->processor = 0;
-
+
+ /*
+ * XXX very rough, assumes 20 bus cycles to read a cache line,
+ * timebase increments every 4 bus cycles, 32kB L1 data cache.
+ */
+ cacheflush_time = 5 * 1024;
+
if ( _machine != _MACH_Pmac )
{
printk("SMP not supported on this machine.\n");
@@ -213,10 +228,16 @@ __initfunc(void smp_boot_cpus(void))
if ( !p )
panic("No idle task for secondary processor\n");
p->processor = 1;
+ p->has_cpu = 1;
current_set[1] = p;
/* need to flush here since secondary bat's aren't setup */
- dcbf((void *)&current_set[1]);
+ /* XXX ??? */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+ asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+ asm volatile("sync");
+
+ /*dcbf((void *)&current_set[1]);*/
/* setup entry point of secondary processor */
*(volatile unsigned long *)(0xf2800000) =
(unsigned long)__secondary_start-KERNELBASE;
@@ -238,7 +259,7 @@ __initfunc(void smp_boot_cpus(void))
if(cpu_callin_map[1]) {
printk("Processor %d found.\n", smp_num_cpus);
smp_num_cpus++;
-#if 0 /* this sync's the decr's, but we don't want this now -- Cort */
+#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
set_dec(decrementer_count);
#endif
} else {
@@ -251,19 +272,17 @@ __initfunc(void smp_boot_cpus(void))
smp_message_pass(1,0xf0f0, 0, 0);
}
-__initfunc(void smp_commence(void))
+void __init smp_commence(void)
{
printk("SMP %d: smp_commence()\n",current->processor);
/*
* Lets the callin's below out of their loop.
*/
- local_flush_tlb_all();
smp_commenced = 1;
- local_flush_tlb_all();
}
/* intel needs this */
-__initfunc(void initialize_secondary(void))
+void __init initialize_secondary(void)
{
}
@@ -275,33 +294,34 @@ asmlinkage int __init start_secondary(void *unused)
return cpu_idle(NULL);
}
-__initfunc(void smp_callin(void))
+void __init smp_callin(void)
{
printk("SMP %d: smp_callin()\n",current->processor);
smp_store_cpu_info(current->processor);
set_dec(decrementer_count);
-
+#if 0
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;
-
- cpu_callin_map[current->processor] = current->processor;
+#endif
+ cpu_callin_map[current->processor] = 1;
while(!smp_commenced)
barrier();
__sti();
+ printk("SMP %d: smp_callin done\n", current->processor);
}
-__initfunc(void smp_setup(char *str, int *ints))
+void __init smp_setup(char *str, int *ints)
{
printk("SMP %d: smp_setup()\n",current->processor);
}
-__initfunc(int setup_profiling_timer(unsigned int multiplier))
+int __init setup_profiling_timer(unsigned int multiplier)
{
return 0;
}
-__initfunc(void smp_store_cpu_info(int id))
+void __init smp_store_cpu_info(int id)
{
struct cpuinfo_PPC *c = &cpu_data[id];
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 8bada0e69..32f60a236 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,5 +1,5 @@
/*
- * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $
+ * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -17,6 +17,9 @@
* This is then divided by 4, providing a 8192 Hz clock into the PIT.
* Since it is not possible to get a nice 100 Hz clock out of this, without
* creating a software PLL, I have set HZ to 128. -- Dan
+ *
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
@@ -78,6 +81,26 @@ void timer_interrupt(struct pt_regs * regs)
unsigned dcache_locked = unlock_dcache();
hardirq_enter(cpu);
+#ifdef __SMP__
+ {
+ unsigned int loops = 100000000;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
while ((dval = get_dec()) < 0) {
/*
@@ -133,9 +156,9 @@ void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
static int
mbx_set_rtc_time(unsigned long time)
{
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
return(0);
}
#endif /* CONFIG_MBX */
@@ -150,12 +173,15 @@ void do_gettimeofday(struct timeval *tv)
save_flags(flags);
cli();
*tv = xtime;
+ /* XXX we don't seem to have the decrementers synced properly yet */
+#ifndef __SMP__
tv->tv_usec += (decrementer_count - get_dec())
* count_period_num / count_period_den;
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
+#endif
restore_flags(flags);
}
@@ -172,6 +198,11 @@ void do_settimeofday(struct timeval *tv)
xtime.tv_sec = tv->tv_sec;
xtime.tv_usec = tv->tv_usec - frac_tick;
set_dec(frac_tick * count_period_den / count_period_num);
+ 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;
restore_flags(flags);
}
@@ -227,13 +258,13 @@ __initfunc(void time_init(void))
* modify these registers we have to write the key value to
* the key location associated with the register.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
/* Disable the RTC one second and alarm interrupts.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
~(RTCSC_SIE | RTCSC_ALE);
/* Enabling the decrementer also enables the timebase interrupts
@@ -241,7 +272,7 @@ __initfunc(void time_init(void))
* we have to enable the timebase). The decrementer interrupt
* is wired into the vector table, nothing to do here for that.
*/
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+ ((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
((mk_int_int_mask(DEC_INTERRUPT) << 8) |
(TBSCR_TBF | TBSCR_TBE));
if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
@@ -249,7 +280,7 @@ __initfunc(void time_init(void))
/* Get time from the RTC.
*/
- xtime.tv_sec = ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+ xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
xtime.tv_usec = 0;
#endif /* CONFIG_MBX */
@@ -343,10 +374,10 @@ __initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *
*/
__initfunc(void mbx_calibrate_decr(void))
{
- bd_t *binfo = (bd_t *)&res;
+ bd_t *binfo = (bd_t *)res;
int freq, fp, divisor;
- if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+ if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
printk("WARNING: Wrong decrementer source clock.\n");
/* The manual says the frequency is in Hz, but it is really
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index af02252f9..fa5184af2 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -79,6 +79,7 @@ _exception(int signr, struct pt_regs *regs)
debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
@@ -126,6 +127,7 @@ MachineCheckException(struct pt_regs *regs)
debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("machine check");
}
_exception(SIGSEGV, regs);
@@ -219,6 +221,7 @@ StackOverflow(struct pt_regs *regs)
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
+ instruction_dump((unsigned long *)regs->nip);
panic("kernel stack overflow");
}
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 4cc49de17..8ca9a3cd5 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -8,7 +8,7 @@
O_TARGET = lib.o
O_OBJS = checksum.o string.o strcase.o
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += locks.o
endif
diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c
index 073e7076c..2d2a2d8c0 100644
--- a/arch/ppc/lib/locks.c
+++ b/arch/ppc/lib/locks.c
@@ -1,5 +1,5 @@
/*
- * $Id: locks.c,v 1.20 1998/10/08 01:17:32 cort Exp $
+ * $Id: locks.c,v 1.21 1998/12/28 10:28:53 paulus Exp $
*
* Locks for smp ppc
*
@@ -18,7 +18,7 @@
#define DEBUG_LOCKS 1
#undef INIT_STUCK
-#define INIT_STUCK 0xffffffff
+#define INIT_STUCK 200000000 /*0xffffffff*/
void _spin_lock(spinlock_t *lock)
{
@@ -76,9 +76,9 @@ void _spin_unlock(spinlock_t *lp)
lp->owner_pc,lp->lock);
#endif /* DEBUG_LOCKS */
lp->owner_pc = lp->owner_cpu = 0;
- eieio();
- lp->lock = 0;
- eieio();
+ eieio(); /* actually I believe eieio only orders */
+ lp->lock = 0; /* non-cacheable accesses (on 604 at least) */
+ eieio(); /* - paulus. */
}
/*
diff --git a/arch/ppc/mbx_defconfig b/arch/ppc/mbx_defconfig
index e0b94ce6a..54035b866 100644
--- a/arch/ppc/mbx_defconfig
+++ b/arch/ppc/mbx_defconfig
@@ -14,15 +14,17 @@ CONFIG_8xx=y
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
CONFIG_MBX=y
-CONFIG_SERIAL_CONSOLE=y
+CONFIG_SMP=n
CONFIG_MACH_SPECIFIC=y
+CONFIG_SERIAL_CONSOLE=y
#
# General setup
#
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
# CONFIG_MODULES is not set
CONFIG_PCI=y
+# CONFIG_PCI_QUIRKS is not set
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
# CONFIG_SYSCTL is not set
@@ -33,13 +35,19 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_BINFMT_JAVA is not set
# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_FB is not set
+# CONFIG_PMAC_PBOOK is not set
# CONFIG_MAC_KEYBOARD is not set
# CONFIG_MAC_FLOPPY is not set
# CONFIG_MAC_SERIAL is not set
+# CONFIG_ADBMOUSE is not set
+# CONFIG_BLK_DEV_IDE_PMAC is not set
# CONFIG_PROC_DEVICETREE is not set
# CONFIG_KGDB is not set
# CONFIG_XMON is not set
-CONFIG_VGA_CONSOLE=y
+# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
#
# Plug and Play support
@@ -47,7 +55,7 @@ CONFIG_VGA_CONSOLE=y
# CONFIG_PNP is not set
#
-# Floppy, IDE, and other block devices
+# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_IDE is not set
@@ -84,8 +92,19 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_RARP is not set
CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
+# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+# CONFIG_NET_SCHED is not set
#
# SCSI support
@@ -100,22 +119,26 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_EQUALIZER is not set
CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_EISA is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
# CONFIG_DLCI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
-# CONFIG_WAN_DRIVERS is not set
-# CONFIG_LAPBETHER is not set
-# CONFIG_X25_ASY is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
#
# Amateur Radio support
@@ -133,6 +156,32 @@ CONFIG_NET_ETHERNET=y
# CONFIG_CD_NO_IDESCSI is not set
#
+# Console drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
# Filesystems
#
# CONFIG_QUOTA is not set
@@ -159,31 +208,15 @@ CONFIG_LOCKD=y
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
# CONFIG_MAC_PARTITION is not set
# CONFIG_NLS is not set
#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
-# CONFIG_JOYSTICK is not set
-# CONFIG_MISC_RADIO is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-
-#
# Sound
#
# CONFIG_SOUND is not set
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index b45f4e6f4..42e2918b1 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -89,6 +89,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
+ instruction_dump((unsigned long *)regs->nip);
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_kernel_faults)
debugger(regs);
@@ -174,6 +175,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
/* kernel has accessed a bad area */
show_regs(regs);
print_backtrace( (unsigned long *)regs->gpr[1] );
+ instruction_dump((unsigned long *)regs->nip);
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_kernel_faults)
debugger(regs);
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 44104fd4e..b80d4c21c 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -1,5 +1,5 @@
/*
- * $Id: init.c,v 1.130 1998/11/10 10:09:20 paulus Exp $
+ * $Id: init.c,v 1.139 1998/12/29 19:53:49 cort Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -55,7 +55,7 @@
/* END APUS includes */
int prom_trashed;
-int next_mmu_context;
+atomic_t next_mmu_context;
unsigned long *end_of_DRAM;
int mem_init_done;
extern pgd_t swapper_pg_dir[];
@@ -71,7 +71,8 @@ unsigned long ioremap_base;
unsigned long ioremap_bot;
unsigned long avail_start;
struct pgtable_cache_struct quicklists;
-struct mem_info memory[NUM_MEMINFO];
+extern int num_memory;
+extern struct mem_info memory[NUM_MEMINFO];
extern boot_infos_t *boot_infos;
void MMU_init(void);
@@ -89,6 +90,27 @@ void map_page(struct task_struct *, unsigned long va,
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
+
+/*
+ * The following stuff defines a data structure for representing
+ * areas of memory as an array of (address, length) pairs, and
+ * procedures for manipulating them.
+ */
+#define MAX_MEM_REGIONS 32
+
+struct mem_pieces {
+ int n_regions;
+ struct reg_property regions[MAX_MEM_REGIONS];
+};
+struct mem_pieces phys_mem;
+struct mem_pieces phys_avail;
+struct mem_pieces prom_mem;
+
+static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+void *find_mem_piece(unsigned, unsigned);
+static void print_mem_pieces(struct mem_pieces *);
+static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
+
extern struct task_struct *current_set[NR_CPUS];
PTE *Hash, *Hash_end;
@@ -529,38 +551,19 @@ mmu_context_overflow(void)
}
read_unlock(&tasklist_lock);
flush_hash_segments(0x10, 0xffffff);
- next_mmu_context = 0;
+ atomic_set(&next_mmu_context, 0);
/* make sure current always has a context */
- current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+ current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));
set_context(current->mm->context);
#else
/* We set the value to -1 because it is pre-incremented before
* before use.
*/
- next_mmu_context = -1;
+ atomic_set(&next_mmu_context, -1);
#endif
}
/*
- * The following stuff defines a data structure for representing
- * areas of memory as an array of (address, length) pairs, and
- * procedures for manipulating them.
- */
-#define MAX_MEM_REGIONS 32
-
-struct mem_pieces {
- int n_regions;
- struct reg_property regions[MAX_MEM_REGIONS];
-};
-struct mem_pieces phys_mem;
-struct mem_pieces phys_avail;
-struct mem_pieces prom_mem;
-
-static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
-void *find_mem_piece(unsigned, unsigned);
-static void print_mem_pieces(struct mem_pieces *);
-
-/*
* Scan a region for a piece of a given size with the required alignment.
*/
__initfunc(void *
@@ -653,14 +656,26 @@ __initfunc(static void print_mem_pieces(struct mem_pieces *mp))
printk("\n");
}
+/*
+ * Add some memory to an array of pieces
+ */
+__initfunc(static void
+ append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size))
+{
+ struct reg_property *rp;
+ if (mp->n_regions >= MAX_MEM_REGIONS)
+ return;
+ rp = &mp->regions[mp->n_regions++];
+ rp->address = start;
+ rp->size = size;
+}
#ifndef CONFIG_8xx
static void hash_init(void);
static void get_mem_prop(char *, struct mem_pieces *);
static void sort_mem_pieces(struct mem_pieces *);
static void coalesce_mem_pieces(struct mem_pieces *);
-static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
__initfunc(static void sort_mem_pieces(struct mem_pieces *mp))
{
@@ -703,21 +718,6 @@ __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp))
}
/*
- * Add some memory to an array of pieces
- */
-__initfunc(static void
- append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size))
-{
- struct reg_property *rp;
-
- if (mp->n_regions >= MAX_MEM_REGIONS)
- return;
- rp = &mp->regions[mp->n_regions++];
- rp->address = start;
- rp->size = size;
-}
-
-/*
* Read in a property describing some pieces of memory.
*/
@@ -963,8 +963,10 @@ __initfunc(void MMU_init(void))
#ifndef CONFIG_8xx
if (have_of)
end_of_DRAM = pmac_find_end_of_memory();
+#ifdef CONFIG_APUS
else if (_machine == _MACH_apus )
end_of_DRAM = apus_find_end_of_memory();
+#endif
else /* prep */
end_of_DRAM = prep_find_end_of_memory();
@@ -1023,8 +1025,10 @@ __initfunc(void MMU_init(void))
*/
ioremap(NVRAM_ADDR, NVRAM_SIZE);
ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE);
- ioremap(MBX_IMAP_ADDR, MBX_IMAP_SIZE);
+ ioremap(IMAP_ADDR, IMAP_SIZE);
ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
+ /* ide needs to be able to get at PCI space -- Cort */
+ ioremap(0x80000000, 0x4000);
#endif /* CONFIG_8xx */
}
@@ -1189,7 +1193,7 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void))
volatile memctl8xx_t *mcp;
unsigned long *ret;
- binfo = (bd_t *)&res;
+ binfo = (bd_t *)res;
/*
* The MBX does weird things with the mmaps for ram.
@@ -1200,11 +1204,13 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void))
* In fact, it might be the best idea to just read the DRAM
* config registers and set the mem areas accordingly.
*/
- mcp = (memctl8xx_t *)(&(((immap_t *)MBX_IMAP_ADDR)->im_memctl));
+ mcp = (memctl8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_memctl));
+ append_mem_piece(&phys_mem, 0, binfo->bi_memsize);
+#if 0
phys_mem.regions[0].address = 0;
- phys_mem.regions[0].size = binfo->bi_memsize;
-
+ phys_mem.regions[0].size = binfo->bi_memsize;
phys_mem.n_regions = 1;
+#endif
ret = __va(phys_mem.regions[0].address+
phys_mem.regions[0].size);
@@ -1293,7 +1299,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
/*
* This finds the amount of physical ram and does necessary
* setup for prep. This is pretty architecture specific so
- * this will likely stay seperate from the pmac.
+ * this will likely stay separate from the pmac.
* -- Cort
*/
__initfunc(unsigned long *prep_find_end_of_memory(void))
@@ -1322,6 +1328,7 @@ __initfunc(unsigned long *prep_find_end_of_memory(void))
return (__va(total));
}
+#ifdef CONFIG_APUS
#define HARDWARE_MAPPED_SIZE (512*1024)
__initfunc(unsigned long *apus_find_end_of_memory(void))
{
@@ -1381,15 +1388,22 @@ __initfunc(unsigned long *apus_find_end_of_memory(void))
/* Remove the upper 512KB where the PPC exception
vectors are mapped. */
top -= HARDWARE_MAPPED_SIZE;
- remove_mem_piece(&phys_avail, top,
- HARDWARE_MAPPED_SIZE, 0);
+#if 0
+ /* This would be neat, but it breaks on A3000 machines!? */
+ remove_mem_piece(&phys_avail, top, 16384, 0);
+#else
+ remove_mem_piece(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0);
+#endif
+
}
- /* FIXME:APUS: Only handles one block of memory! Problem is
- that the VTOP/PTOV code in head.S would be a mess if it had
- to handle more than one block. */
+ /* Linux/APUS only handles one block of memory -- the one on
+ the PowerUP board. Other system memory is horrible slow in
+ comparison. The user can use other memory for swapping
+ using the z2ram device. */
return __va(memory[0].addr + memory[0].size);
}
+#endif /* CONFIG_APUS */
/*
* Initialize the hash table and patch the instructions in head.S.
@@ -1400,7 +1414,7 @@ __initfunc(static void hash_init(void))
unsigned long h, ramsize;
extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
- hash_page_patch_C[];
+ hash_page_patch_C[], hash_page[];
/*
* Allow 64k of hash table for every 16MB of memory,
@@ -1475,7 +1489,17 @@ __initfunc(static void hash_init(void))
flush_icache_range((unsigned long) b(hash_page_patch_A),
(unsigned long) b(hash_page_patch_C + 1));
}
- else
+ else {
Hash_end = 0;
+ /*
+ * Put a blr (procedure return) instruction at the
+ * start of hash_page, since we can still get DSI
+ * exceptions on a 603.
+ */
+ *b(hash_page) = 0x4e800020;
+ flush_icache_range((unsigned long) b(hash_page),
+ (unsigned long) b(hash_page + 1));
+ }
}
#endif /* ndef CONFIG_8xx */
+
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
index ae1303bb4..811d599c0 100644
--- a/arch/ppc/pmac_defconfig
+++ b/arch/ppc/pmac_defconfig
@@ -15,6 +15,7 @@ CONFIG_PMAC=y
# CONFIG_APUS is not set
# CONFIG_MBX is not set
CONFIG_MACH_SPECIFIC=y
+# CONFIG_SMP is not set
#
# General setup
@@ -137,6 +138,10 @@ CONFIG_ATALK=m
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -164,6 +169,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
@@ -174,14 +180,16 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
@@ -218,6 +226,7 @@ CONFIG_BMAC=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
@@ -225,7 +234,7 @@ CONFIG_NET_EISA=y
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
-CONFIG_DEC_ELCP=m
+# CONFIG_DEC_ELCP is not set
# CONFIG_DGRS is not set
# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_LNE390 is not set
@@ -253,6 +262,7 @@ CONFIG_PPP=y
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
#
# Amateur Radio support
@@ -282,6 +292,7 @@ CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
CONFIG_FBCON_CFB8=y
@@ -303,7 +314,7 @@ CONFIG_FONT_SUN12x22=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
@@ -311,9 +322,17 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-CONFIG_NVRAM=y
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -325,37 +344,47 @@ CONFIG_NVRAM=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
CONFIG_NFSD=y
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_NLS=y
#
@@ -386,6 +415,7 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
#
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
index 41db35a4a..14b4ea4a0 100644
--- a/arch/ppc/prep_defconfig
+++ b/arch/ppc/prep_defconfig
@@ -14,6 +14,7 @@ CONFIG_PREP=y
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
# CONFIG_MBX is not set
+# CONFIG_SMP is not set
CONFIG_MACH_SPECIFIC=y
#
diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds
index f5c61bd6e..e322d138b 100644
--- a/arch/ppc/vmlinux.lds
+++ b/arch/ppc/vmlinux.lds
@@ -64,6 +64,9 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
. = ALIGN(4096);
__init_begin = .;
.text.init : { *(.text.init) }
diff --git a/arch/sparc/ap1000/util.c b/arch/sparc/ap1000/util.c
index abb51426e..079c9f4c0 100644
--- a/arch/sparc/ap1000/util.c
+++ b/arch/sparc/ap1000/util.c
@@ -393,7 +393,7 @@ void ap_nfs_hook(unsigned long server)
unsigned end = jiffies + 20*HZ;
/* we are booting from another cell */
printk("waiting for the master cell\n");
- while (jiffies < end) ;
+ while (time_before(jiffies, end)) ;
printk("continuing\n");
}
}
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 97c970481..6220b2085 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -25,6 +25,7 @@ define_bool CONFIG_VT y
define_bool CONFIG_VT_CONSOLE y
bool 'Support for AP1000 multicomputer' CONFIG_AP1000
+bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_AP1000" = "y" ]; then
define_bool CONFIG_NO_KEYBOARD y
@@ -175,8 +176,6 @@ fi
source fs/Config.in
-source fs/nls/Config.in
-
mainmenu_option next_comment
comment 'Watchdog'
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 7ea12a128..8e6d9e2f5 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -20,6 +20,7 @@ CONFIG_KMOD=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_AP1000 is not set
+# CONFIG_SMP is not set
# CONFIG_SUN4 is not set
# CONFIG_PCI is not set
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 18e487d86..d5f65dda3 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -30,7 +30,7 @@ ifdef CONFIG_SUN4
O_OBJS += sun4setup.o
endif
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
endif
@@ -50,11 +50,17 @@ check_asm: dummy
@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
@echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#ifndef __SMP__" >> asm_offsets.h
+ @echo "#include <linux/config.h>" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#include <linux/sched.h>" > tmp.c
+ @echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef CONFIG_SMP" >> tmp.c
+ @echo "#include <linux/sched.h>" >> tmp.c
$(CC) -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef CONFIG_SMP" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@echo 'struct mm_struct _mm;' >> check_asm.c
@@ -69,11 +75,17 @@ check_asm: dummy
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
- @echo "#else /* __SMP__ */" >> asm_offsets.h
+ @echo "#else /* CONFIG_SMP */" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#include <linux/sched.h>" > tmp.c
+ @echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef CONFIG_SMP" >> tmp.c
+ @echo "#define CONFIG_SMP 1" >> tmp.c
+ @echo "#include <linux/sched.h>" >> tmp.c
$(CC) -D__SMP__ -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef CONFIG_SMP" >> check_asm.c
+ @echo "#define CONFIG_SMP 1" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@echo 'struct mm_struct _mm;' >> check_asm.c
@@ -88,7 +100,7 @@ check_asm: dummy
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
- @echo "#endif /* __SMP__ */" >> asm_offsets.h
+ @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
@echo "" >> asm_offsets.h
@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 40e23fa0e..ed8fe6a25 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -592,7 +592,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
res = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (res < 0) {
pt_error_return(regs, -res);
goto out;
@@ -619,8 +621,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
vma = find_extend_vma(child, addr);
res = write_long(child, addr, data);
+ up(&child->mm->mmap_sem);
if(res < 0)
pt_error_return(regs, -res);
else
@@ -761,7 +765,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
while(len) {
+ down(&child->mm->mmap_sem);
res = read_byte(child, src, &tmp);
+ up(&child->mm->mmap_sem);
if(res < 0) {
pt_error_return(regs, -res);
goto out;
@@ -788,7 +794,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long tmp;
__get_user(tmp, src);
+ down(&child->mm->mmap_sem);
res = write_byte(child, dest, tmp);
+ up(&child->mm->mmap_sem);
if(res < 0) {
pt_error_return(regs, -res);
goto out;
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index eac95ec98..9e5afcfcf 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -11,6 +11,9 @@
* Support for MicroSPARC-IIep, PCI CPU.
*
* This file handles the Sparc specific time handling details.
+ *
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -89,9 +92,10 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
do_timer(regs);
/* Determine when to update the Mostek clock. */
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1)) {
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
@@ -495,12 +499,18 @@ static void sbus_do_settimeofday(struct timeval *tv)
}
#endif
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();
}
+/*
+ * 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)
{
int real_seconds, real_minutes, mostek_minutes;
@@ -531,9 +541,13 @@ static int set_rtc_mmss(unsigned long nowtime)
iregs->clk.int_sec=real_seconds;
iregs->clk.int_min=real_minutes;
intersil_start(iregs);
- } else
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
return -1;
-
+ }
+
return 0;
}
#endif
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 9ce3a6630..0670ff273 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -7,7 +7,7 @@ OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
copy_user.o locks.o atomic.o bitops.o debuglocks.o
-ifdef SMP
+ifdef CONFIG_SMP
OBJS += irqlock.o
endif
@@ -54,7 +54,7 @@ atomic.o: atomic.S
bitops.o: bitops.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S
-ifdef SMP
+ifdef CONFIG_SMP
irqlock.o: irqlock.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S
endif
diff --git a/arch/sparc/lib/checksum.S b/arch/sparc/lib/checksum.S
index 2f0c78168..d02b6dfb2 100644
--- a/arch/sparc/lib/checksum.S
+++ b/arch/sparc/lib/checksum.S
@@ -535,7 +535,7 @@ C_LABEL(__csum_partial_copy_end):
/* %o1 is dst
* %o3 is # bytes to zero out
* %o4 is faulting address
- * %o5 is %pc where fault occured */
+ * %o5 is %pc where fault occurred */
clr %o2
31:
/* %o0 is src
@@ -543,7 +543,7 @@ C_LABEL(__csum_partial_copy_end):
* %o2 is # of bytes to copy from src to dst
* %o3 is # bytes to zero out
* %o4 is faulting address
- * %o5 is %pc where fault occured */
+ * %o5 is %pc where fault occurred */
save %sp, -104, %sp
mov %i5, %o0
mov %i7, %o1
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index a9e51c67f..ecb1943c3 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -14,7 +14,7 @@ O_OBJS += nosrmmu.o
else
O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
endif
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += nosun4c.o
else
O_OBJS += sun4c.o
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 69d40fa09..d94fd4083 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -470,7 +470,7 @@ static inline pte_t *srmmu_get_pte_fast(void)
(unsigned int)ret->pprev_hash = mask & ~tmp;
if (!(mask & ~tmp))
pte_quicklist = (unsigned long *)ret->next_hash;
- ret = (struct page *)(PAGE_OFFSET + (ret->map_nr << PAGE_SHIFT) + off);
+ ret = (struct page *)(page_address(ret) + off);
pgtable_cache_size--;
}
spin_unlock(&pte_spinlock);
@@ -508,7 +508,7 @@ static inline pgd_t *srmmu_get_pgd_fast(void)
(unsigned int)ret->pprev_hash = mask & ~tmp;
if (!(mask & ~tmp))
pgd_quicklist = (unsigned long *)ret->next_hash;
- ret = (struct page *)(PAGE_OFFSET + (ret->map_nr << PAGE_SHIFT) + off);
+ ret = (struct page *)(page_address(ret) + off);
pgd_cache_size--;
}
spin_unlock(&pgd_spinlock);
@@ -682,7 +682,7 @@ static void srmmu_set_pgdir(unsigned long address, pgd_t entry)
spin_lock(&pgd_spinlock);
address >>= SRMMU_PGDIR_SHIFT;
for (page = (struct page *)pgd_quicklist; page; page = page->next_hash) {
- pgd_t *pgd = (pgd_t *)(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ pgd_t *pgd = (pgd_t *)page_address(page);
unsigned int mask = (unsigned int)page->pprev_hash;
if (mask & 1)
@@ -2817,7 +2817,7 @@ static int srmmu_check_pgt_cache(int low, int high)
page->next_hash = NULL;
page->pprev_hash = NULL;
pgtable_cache_size -= 16;
- free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ __free_page(page);
freed++;
if (page2)
page = page2->next_hash;
@@ -2843,7 +2843,7 @@ static int srmmu_check_pgt_cache(int low, int high)
page->next_hash = NULL;
page->pprev_hash = NULL;
pgd_cache_size -= 4;
- free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ __free_page(page);
freed++;
if (page2)
page = page2->next_hash;
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 01d44a3fb..9df70fc36 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -51,7 +51,7 @@ endif
# Uncomment this to get spinlock/rwlock debugging on SMP.
# DEBUG_SPINLOCK = 1
-ifdef SMP
+ifdef CONFIG_SMP
ifdef DEBUG_SPINLOCK
CFLAGS += -DSPIN_LOCK_DEBUG
AFLAGS += -DSPIN_LOCK_DEBUG
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 103767d64..fa3539525 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -25,6 +25,7 @@ define_bool CONFIG_VT y
define_bool CONFIG_VT_CONSOLE y
bool 'Support for AP1000 multicomputer' CONFIG_AP1000
+bool 'Symmetric multi-processing support' CONFIG_SMP
mainmenu_option next_comment
comment 'Console drivers'
@@ -238,8 +239,6 @@ fi
source fs/Config.in
-source fs/nls/Config.in
-
mainmenu_option next_comment
comment 'Watchdog'
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 3b743920f..59b3b4618 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -20,6 +20,7 @@ CONFIG_KMOD=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_AP1000 is not set
+# CONFIG_SMP is not set
#
# Console drivers
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 4d1b1eb35..fbeb83126 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -27,7 +27,7 @@ ifdef CONFIG_PCI
O_OBJS += ebus.o
endif
-ifdef SMP
+ifdef CONFIG_SMP
O_OBJS += smp.o trampoline.o
endif
@@ -63,11 +63,17 @@ check_asm: dummy
@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
@echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#ifndef __SMP__" >> asm_offsets.h
+ @echo "#include <linux/config.h>" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#include <linux/sched.h>" > tmp.c
+ @echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef CONFIG_SMP" >> tmp.c
+ @echo "#include <linux/sched.h>" >> tmp.c
$(CC) -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef CONFIG_SMP" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@echo 'struct mm_struct _mm;' >> check_asm.c
@@ -87,13 +93,19 @@ check_asm: dummy
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
- @echo "#else /* __SMP__ */" >> asm_offsets.h
+ @echo "#else /* CONFIG_SMP */" >> asm_offsets.h
@echo "" >> asm_offsets.h
@echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#include <linux/sched.h>" > tmp.c
+ @echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef CONFIG_SMP" >> tmp.c
+ @echo "#define CONFIG_SMP 1" >> tmp.c
+ @echo "#include <linux/sched.h>" >> tmp.c
$(CC) -D__SMP__ -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef CONFIG_SMP" >> check_asm.c
+ @echo "#define CONFIG_SMP 1" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@echo 'struct mm_struct _mm;' >> check_asm.c
@@ -118,6 +130,9 @@ check_asm: dummy
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef CONFIG_SMP" >> check_asm.c
+ @echo "#define CONFIG_SMP 1" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@echo 'struct mm_struct _mm;' >> check_asm.c
@@ -138,7 +153,7 @@ check_asm: dummy
@rm -f check_asm check_asm.c
@echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
@echo "" >> asm_offsets.h
- @echo "#endif /* __SMP__ */" >> asm_offsets.h
+ @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
@echo "" >> asm_offsets.h
@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index e95bf0727..c826ce56d 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -53,9 +53,10 @@ static __inline__ void timer_check_rtc(void)
static long last_rtc_update=0;
/* Determine when to update the Mostek clock. */
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1)) {
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
@@ -458,10 +459,11 @@ void do_settimeofday(struct timeval *tv)
}
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();
}