summaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /arch/sparc64
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/Makefile15
-rw-r--r--arch/sparc64/config.in30
-rw-r--r--arch/sparc64/defconfig89
-rw-r--r--arch/sparc64/kernel/Makefile18
-rw-r--r--arch/sparc64/kernel/auxio.c10
-rw-r--r--arch/sparc64/kernel/central.c9
-rw-r--r--arch/sparc64/kernel/devices.c10
-rw-r--r--arch/sparc64/kernel/dtlb_backend.S69
-rw-r--r--arch/sparc64/kernel/dtlb_base.S98
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S83
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S98
-rw-r--r--arch/sparc64/kernel/ebus.c79
-rw-r--r--arch/sparc64/kernel/entry.S199
-rw-r--r--arch/sparc64/kernel/etrap.S166
-rw-r--r--arch/sparc64/kernel/head.S47
-rw-r--r--arch/sparc64/kernel/ioctl32.c444
-rw-r--r--arch/sparc64/kernel/ioport.c60
-rw-r--r--arch/sparc64/kernel/irq.c642
-rw-r--r--arch/sparc64/kernel/itlb_base.S69
-rw-r--r--arch/sparc64/kernel/itlb_miss.S49
-rw-r--r--arch/sparc64/kernel/process.c126
-rw-r--r--arch/sparc64/kernel/psycho.c314
-rw-r--r--arch/sparc64/kernel/ptrace.c95
-rw-r--r--arch/sparc64/kernel/rtrap.S170
-rw-r--r--arch/sparc64/kernel/setup.c61
-rw-r--r--arch/sparc64/kernel/signal.c224
-rw-r--r--arch/sparc64/kernel/signal32.c418
-rw-r--r--arch/sparc64/kernel/smp.c140
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c14
-rw-r--r--arch/sparc64/kernel/sys32.S4
-rw-r--r--arch/sparc64/kernel/sys_sparc.c44
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c440
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c32
-rw-r--r--arch/sparc64/kernel/systbls.S46
-rw-r--r--arch/sparc64/kernel/time.c19
-rw-r--r--arch/sparc64/kernel/trampoline.S38
-rw-r--r--arch/sparc64/kernel/traps.c15
-rw-r--r--arch/sparc64/kernel/ttable.S19
-rw-r--r--arch/sparc64/kernel/unaligned.c45
-rw-r--r--arch/sparc64/kernel/winfixup.S11
-rw-r--r--arch/sparc64/lib/Makefile4
-rw-r--r--arch/sparc64/lib/VISbzero.S14
-rw-r--r--arch/sparc64/lib/VIScopy.S115
-rw-r--r--arch/sparc64/lib/VIScsum.S15
-rw-r--r--arch/sparc64/lib/VIScsumcopy.S75
-rw-r--r--arch/sparc64/lib/VISmemset.S15
-rw-r--r--arch/sparc64/lib/VISsave.S122
-rw-r--r--arch/sparc64/lib/blockops.S94
-rw-r--r--arch/sparc64/lib/memscan.S203
-rw-r--r--arch/sparc64/math-emu/math.c38
-rw-r--r--arch/sparc64/math-emu/op-common.h13
-rw-r--r--arch/sparc64/mm/Makefile14
-rw-r--r--arch/sparc64/mm/asyncd.c4
-rw-r--r--arch/sparc64/mm/init.c510
-rw-r--r--arch/sparc64/mm/modutil.c28
-rw-r--r--arch/sparc64/mm/ultra.S155
-rw-r--r--arch/sparc64/prom/misc.c17
-rw-r--r--arch/sparc64/prom/p1275.c8
-rw-r--r--arch/sparc64/solaris/fs.c4
-rw-r--r--arch/sparc64/solaris/ipc.c3
-rw-r--r--arch/sparc64/solaris/misc.c6
-rw-r--r--arch/sparc64/solaris/signal.h3
-rw-r--r--arch/sparc64/vmlinux.lds13
63 files changed, 3481 insertions, 2551 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index e004359c3..d8cc0f76e 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.25 1998/04/06 16:10:31 jj Exp $
+# $Id: Makefile,v 1.27 1998/07/27 07:36:16 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -19,13 +19,20 @@ AR = sparc64-linux-ar
RANLIB = sparc64-linux-ranlib
ELFTOAOUT = elftoaout
+IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+
#
# Uncomment the first CFLAGS if you are doing kgdb source level
# debugging of the kernel to get the proper debugging information.
#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
-CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
- -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+ifneq ($(IS_EGCS),y)
+ CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
+ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+else
+ CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mcmodel=medlow \
+ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+endif
LINKFLAGS = -T arch/sparc64/vmlinux.lds
@@ -57,6 +64,8 @@ vmlinux.aout: vmlinux
archclean:
rm -f $(TOPDIR)/vmlinux.aout
+archmrproper:
+
archdep:
check_asm:
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 8cd86f9db..2caead01d 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.44 1998/04/06 16:10:35 jj Exp $
+# $Id: config.in,v 1.55 1998/08/03 15:28:38 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -26,6 +26,13 @@ define_bool CONFIG_VT_CONSOLE y
bool 'Support for AP1000 multicomputer' CONFIG_AP1000
+mainmenu_option next_comment
+comment 'Console drivers'
+bool 'PROM console' CONFIG_PROM_CONSOLE
+bool 'Support Frame buffer devices' CONFIG_FB
+source drivers/video/Config.in
+endmenu
+
if [ "$CONFIG_AP1000" = "y" ]; then
define_bool CONFIG_NO_KEYBOARD y
define_bool CONFIG_APFDDI y
@@ -45,7 +52,9 @@ else
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
define_bool CONFIG_PCI y
+ define_bool CONFIG_PCI_CONSOLE y
source drivers/sbus/char/Config.in
+ source drivers/sbus/audio/Config.in
fi
tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
@@ -67,12 +76,14 @@ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL
fi
-endmenu
if [ "$CONFIG_PCI" = "y" ]; then
tristate 'Parallel port support' CONFIG_PARPORT
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_AX" = "m" ]; then
+ define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y
+ fi
if [ "$CONFIG_PARPORT_AX" != "n" ]; then
bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
fi
@@ -83,6 +94,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
fi
tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
fi
+endmenu
mainmenu_option next_comment
comment 'Floppy, IDE, and other block devices'
@@ -115,6 +127,7 @@ if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
define_bool CONFIG_BLK_DEV_IDEPCI y
define_bool CONFIG_BLK_DEV_IDEDMA y
+ define_bool CONFIG_IDEDMA_AUTO y
define_bool CONFIG_BLK_DEV_NS87415 y
define_bool CONFIG_BLK_DEV_CMD646 y
fi
@@ -168,11 +181,11 @@ if [ "$CONFIG_SCSI" != "n" ]; then
fi
dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
- bool ' detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
- bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
- int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 12
+ int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+ int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
- if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then
+ bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+ if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -210,6 +223,7 @@ if [ "$CONFIG_NET" = "y" ]; then
tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
if [ "$CONFIG_PCI" = "y" ]; then
tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
fi
# bool 'FDDI driver support' CONFIG_FDDI
# if [ "$CONFIG_FDDI" = "y" ]; then
@@ -231,10 +245,6 @@ endmenu
mainmenu_option next_comment
comment 'Kernel hacking'
-bool 'Kernel profiling support' CONFIG_PROFILE
-if [ "$CONFIG_PROFILE" = "y" ]; then
- int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
-fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
endmenu
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 0a76f100f..35f1219fd 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -20,6 +20,30 @@ CONFIG_KMOD=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_AP1000 is not set
+
+#
+# Console drivers
+#
+CONFIG_PROM_CONSOLE=y
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_SBUS=y
+CONFIG_FB_CREATOR=y
+CONFIG_FB_CGSIX=y
+# CONFIG_FB_BWTWO is not set
+# CONFIG_FB_CGTHREE is not set
+# CONFIG_FB_LEO is not set
+CONFIG_FB_PCI=y
+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=y
+CONFIG_FONT_SUN8x16=y
+# CONFIG_FBCON_FONTS is not set
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
CONFIG_SUN_MOUSE=y
@@ -31,20 +55,7 @@ CONFIG_SUN_CONSOLE=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
-
-#
-# SBUS Frame Buffer support
-#
-SUN_FBS_IN_PROCFS=y
-CONFIG_SUN_FB_DISPLAY=y
-SUN_FB_CGSIX=y
-SUN_FB_TCX=y
-SUN_FB_CGTHREE=y
-SUN_FB_CGFOURTEEN=y
-SUN_FB_BWTWO=y
-SUN_FB_LEO=y
-TADPOLE_FB_WEITEK=y
-SUN_FB_CREATOR=y
+CONFIG_PCI_CONSOLE=y
#
# Misc Linux/SPARC drivers
@@ -55,6 +66,13 @@ CONFIG_SAB82532=y
CONFIG_OBP_FLASH=m
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
+
+#
+# Linux/SPARC audio subsystem (EXPERIMENTAL)
+#
+# CONFIG_SPARCAUDIO is not set
+# CONFIG_SPARCAUDIO_AMD7930 is not set
+# CONFIG_SPARCAUDIO_CS4231 is not set
CONFIG_SUN_OPENPROMFS=m
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
@@ -64,7 +82,7 @@ CONFIG_SYSCTL=y
CONFIG_SPARC32_COMPAT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_ELF32=y
-CONFIG_BINFMT_AOUT32=y
+# CONFIG_BINFMT_AOUT32 is not set
CONFIG_BINFMT_MISC=m
CONFIG_BINFMT_JAVA=m
CONFIG_SOLARIS_EMUL=m
@@ -96,6 +114,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=m
# CONFIG_BLK_DEV_IDESCSI is not set
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_IDEDMA_AUTO=y
CONFIG_BLK_DEV_NS87415=y
CONFIG_BLK_DEV_CMD646=y
@@ -103,7 +122,9 @@ CONFIG_BLK_DEV_CMD646=y
# Networking options
#
CONFIG_PACKET=y
-# CONFIG_NETLINK is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
@@ -112,11 +133,11 @@ CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
CONFIG_IP_ALIAS=y
+# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
#
@@ -132,29 +153,30 @@ CONFIG_IPV6=m
#
#
CONFIG_IPX=m
-
-#
-# IPX options
-#
# CONFIG_IPX_INTERN is not set
+# CONFIG_SPX is not set
CONFIG_ATALK=m
# 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=y
-CONFIG_NET_SCH_CBQ=y
-CONFIG_NET_SCH_CSZ=y
-CONFIG_NET_SCH_RED=y
-CONFIG_NET_SCH_SFQ=y
-CONFIG_NET_SCH_TBF=y
-CONFIG_NET_SCH_PFIFO=y
-CONFIG_NET_SCH_PRIO=y
-# CONFIG_NET_PROFILE is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+# CONFIG_NET_QOS is not set
+# CONFIG_NET_CLS is not set
#
# SCSI support
@@ -188,10 +210,10 @@ CONFIG_SCSI_AIC7XXX=y
# CONFIG_AIC7XXX_PROC_STATS is not set
CONFIG_AIC7XXX_RESET_DELAY=5
CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT=y
-CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=12
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=10
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
#
@@ -228,6 +250,7 @@ CONFIG_HAPPYMEAL=y
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
CONFIG_DE4X5=y
+CONFIG_VORTEX=m
#
# Filesystems
@@ -269,6 +292,7 @@ CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
# CONFIG_ADFS_FS is not set
+# CONFIG_DEVPTS_FS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
@@ -310,6 +334,5 @@ CONFIG_NLS=y
#
# Kernel hacking
#
-# CONFIG_PROFILE is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_EC_FLUSH_TRAP is not set
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 1c3f459bc..ac61935c8 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.36 1998/02/01 11:15:55 ecd Exp $
+# $Id: Makefile,v 1.38 1998/07/26 03:02:47 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -7,24 +7,12 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-ifdef SMP
-
.S.s:
$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
-else
-
-.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-
-.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
-endif
-
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
@@ -51,8 +39,8 @@ ifdef CONFIG_BINFMT_AOUT32
O_OBJS += binfmt_aout32.o
endif
-head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
- winfixup.S entry.S
+head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
+ etrap.S rtrap.S winfixup.S entry.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
#
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 91365af85..a674399e4 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -42,9 +42,13 @@ __initfunc(void auxio_probe(void))
struct linux_ebus_device *edev = 0;
unsigned long led_auxio;
- for_all_ebusdev(edev, ebus)
- if (!strcmp(edev->prom_name, "auxio"))
- break;
+ for_each_ebus(ebus) {
+ for_each_ebusdev(edev, ebus) {
+ if (!strcmp(edev->prom_name, "auxio"))
+ goto ebus_done;
+ }
+ }
+ ebus_done:
if (edev) {
if (check_region(edev->base_address[0],
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index a54e89f2d..1d1cb25e1 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,4 +1,4 @@
-/* $Id: central.c,v 1.5 1998/02/12 15:57:59 jj Exp $
+/* $Id: central.c,v 1.6 1998/05/14 13:35:45 jj Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -29,13 +29,10 @@ unsigned long central_probe(unsigned long memory_start)
char namebuf[128];
int cnode, fnode, err;
- printk("CENTRAL: ");
cnode = prom_finddevice("/central");
- if(cnode == 0 || cnode == -1) {
- printk("no central found.\n");
+ if(cnode == 0 || cnode == -1)
return memory_start;
- }
- printk("found central PROM node.\n");
+ printk("CENTRAL: found central PROM node %08x.\n", cnode);
/* Ok we got one, grab some memory for software state. */
memory_start = long_align(memory_start);
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 8d3aca325..93ea8ca4f 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -48,19 +48,23 @@ device_scan(unsigned long mem_start))
prom_getproperty(scan, "upa-portid",
(char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
- prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
+#ifdef __SMP__
+ prom_printf("Found CPU %d (node=%08x,mid=%d)\n",
cpu_ctr, (unsigned) scan,
thismid);
- printk("Found CPU %d <node=%08x,mid=%d>\n",
+ printk("Found CPU %d (node=%08x,mid=%d)\n",
cpu_ctr, (unsigned) scan, thismid);
+#endif
cpu_ctr++;
}
};
if(cpu_ctr == 0) {
- printk("No CPU nodes found, cannot continue.\n");
+ prom_printf("No CPU nodes found, cannot continue.\n");
prom_halt();
}
+#ifdef __SMP__
printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+#endif
};
prom_node_cpu = cpu_nds[0];
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
new file mode 100644
index 000000000..b3d0a1eb7
--- /dev/null
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -0,0 +1,69 @@
+/* $Id: dtlb_backend.S,v 1.4 1998/06/15 16:59:34 jj Exp $
+ * dtlb_backend.S: Back end to DTLB miss replacement strategy.
+ * This is included directly into the trap table.
+ *
+ * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define TAG_CONTEXT_BITS 0x3ff
+#define VPTE_SHIFT (PAGE_SHIFT - 3)
+#define PMD_SHIFT (23 - PAGE_SHIFT + 3)
+#define PGD_SHIFT (34 - PAGE_SHIFT + 3)
+#define VPTE_BITS (_PAGE_CP | _PAGE_P | _PAGE_W)
+
+/* Ways we can get here:
+ *
+ * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1.
+ * 2) Nucleus loads and stores to/from user/kernel window save areas.
+ * 3) VPTE misses from dtlb_base, dtlb_prot, and itlb_base. But this only
+ * happens for non-nucleus contexts. Nucleus VPTE's cannot work because
+ * of how OBP uses the same part of the address space in ctx 0.
+ */
+
+/* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss */
+ ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
+ add %g3, %g3, %g5 ! Compute VPTE base
+ cmp %g4, %g5 ! VPTE miss?
+ blu,pn %xcc, .-0x4004 ! Fall to tl0 miss
+ andcc %g4, TAG_CONTEXT_BITS, %g5 ! From Nucleus? (for tl0 miss)
+ sllx %g6, VPTE_SHIFT, %g4 ! Position TAG_ACCESS
+ or %g4, %g5, %g4 ! Prepare TAG_ACCESS
+ mov TSB_REG, %g1 ! Grab TSB reg
+
+/* TLB1 ** ICACHE line 2: Quick VPTE miss */
+ ldxa [%g1] ASI_DMMU, %g5 ! Doing PGD caching?
+ srlx %g6, (PMD_SHIFT - 1), %g1 ! Position PMD offset
+ be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus?
+ and %g1, 0xffe, %g1 ! Mask PMD offset bits
+ brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke
+ nop ! Pipe bubble...
+ srlx %g6, (PGD_SHIFT - 2), %g5 ! Position PGD offset
+ and %g5, 0xffc, %g5 ! Mask PGD offset
+
+/* TLB1 ** ICACHE line 3: Quick VPTE miss */
+ lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
+ brz,pn %g5, 2f ! Valid?
+sparc64_vpte_continue:
+ add %g1, %g1, %g1 ! Position PMD offset once again
+ lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
+ brz,pn %g5, 2f ! Valid?
+ sllx %g2, 62, %g1 ! Put _PAGE_VALID into %g1
+ or %g5, VPTE_BITS, %g5 ! Prepare VPTE data
+ or %g5, %g1, %g5 ! ...
+
+/* TLB1 ** ICACHE line 4: Quick VPTE miss */
+ mov TLB_SFSR, %g1 ! Restore %g1 value
+ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB
+ membar #Sync ! Synchronize ASI stores
+ stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS
+ retry ! Load PTE once again
+2: mov TLB_SFSR, %g1 ! Restore %g1 value
+ stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS
+ done ! Slick trick
+
+#undef TAG_CONTEXT_BITS
+#undef VPTE_SHIFT
+#undef PMD_SHIFT
+#undef PGD_SHIFT
+#undef VPTE_BITS
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
new file mode 100644
index 000000000..71e5b14d7
--- /dev/null
+++ b/arch/sparc64/kernel/dtlb_base.S
@@ -0,0 +1,98 @@
+/* $Id: dtlb_base.S,v 1.4 1998/06/15 16:59:30 jj Exp $
+ * dtlb_base.S: Front end to DTLB miss replacement strategy.
+ * This is included directly into the trap table.
+ *
+ * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define TAG_CONTEXT_BITS 0x3ff
+#define VPTE_SHIFT (PAGE_SHIFT - 3)
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W)
+#define KERN_IOBITS (KERN_LOWBITS ^ KERN_LOWBITS_IO)
+
+/* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS)
+ * %g2 (KERN_HIGHBITS | KERN_LOWBITS)
+ * %g3 VPTE base (0xfffffffe00000000) Spitfire/Blackbird (44-bit VA space)
+ * (0xffe0000000000000) Cheetah (64-bit VA space)
+ * %g7 __pa(current->mm->pgd)
+ *
+ * The VPTE base value is completely magic, but note that
+ * nothing else in the kernel other than these TLB miss
+ * handlers know anything about the VPTE mechanism or
+ * how it works. Consider the 44-bit VADDR Ultra-I/II
+ * case as an example:
+ *
+ * VA[0 : (1<<43)] produce VPTE index [%g3 : 0]
+ * VA[0 : -(1<<43)] produce VPTE index [%g3-(1<<(43-PAGE_SHIFT+3)) : %g3]
+ *
+ * For Cheetah's 64-bit VADDR space this is:
+ *
+ * VA[0 : (1<<63)] produce VPTE index [%g3 : 0]
+ * VA[0 : -(1<<63)] produce VPTE index [%g3-(1<<(63-PAGE_SHIFT+3)) : %g3]
+ *
+ * If you're paying attention you'll notice that this means half of
+ * the VPTE table is above %g3 and half is below, low VA addresses
+ * map progressively upwards from %g3, and high VA addresses map
+ * progressively downwards from %g3. This trick was needed to make
+ * the same 8 instruction handler work both for Spitfire/Blackbird's
+ * peculiar VA space hole configuration and the full 64-bit VA space
+ * one of Cheetah at the same time.
+ */
+
+/* Ways we can get here:
+ *
+ * 1) Nucleus loads and stores to/from PA-->VA direct mappings.
+ * 2) Nucleus loads and stores to/from vmalloc() areas.
+ * 3) User loads and stores.
+ * 4) User space accesses by nucleus at tl0
+ */
+
+/* DTLB ** ICACHE line 1: Quick user TLB misses */
+ ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
+ andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus?
+ be,pn %xcc, 3f ! Yep, special processing
+ srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
+ ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
+1: brlz,pt %g5, 2f ! Valid, load into TLB
+ and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits
+ ba,a,pt %xcc, 4f ! Invalid, branch out
+
+/* DTLB ** ICACHE line 2: Quick kernel TLB misses */
+3: brgez,a,pn %g4, 1b ! Kernel virtual map?
+ ldxa [%g3 + %g6] ASI_N, %g5 ! Yep, load k-vpte
+ srlx %g4, 40, %g5 ! Else compute phys-kpte
+ andcc %g5, 1, %g0 ! I/O area?
+ be,pt %xcc, 2f ! Nope, go and load TLB
+ xor %g2, %g4, %g5 ! Finish bit twiddles
+ ba,pt %xcc, 2f ! Yes, I/O space, back back
+ xor %g5, (KERN_IOBITS), %g5 ! After set E, clear CP/CV
+
+/* DTLB ** ICACHE line 3: winfixups+real_faults */
+4: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
+ be,pn %xcc, 5f ! Yep, refbit update
+ sllx %g1, 60, %g4 ! Get valid bit
+ rdpr %pstate, %g5 ! Move into alternate globals
+ wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g4 ! See where we came from.
+ cmp %g4, 1 ! Is etrap/rtrap window fault?
+ mov TLB_TAG_ACCESS, %g4 ! Prepare for fault processing
+
+/* DTLB ** ICACHE line 4: padding */
+ be,pt %xcc, sparc64_realfault_common ! Jump to normal fault handling
+ ldxa [%g4] ASI_DMMU, %g5 ! And load faulting VA page
+ ba,a,pt %xcc, winfix_trampoline ! Call window fixup code
+5: or %g5, _PAGE_ACCESSED, %g5 ! Indicate reference
+ or %g5, %g4, %g5 ! Set valid
+ stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table (cant trap)
+2: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
+ retry ! Trap return
+
+#undef TAG_CONTEXT_BITS
+#undef VPTE_SHIFT
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
+#undef KERN_LOWBITS_IO
+#undef KERN_IOBITS
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
deleted file mode 100644
index e5606cf33..000000000
--- a/arch/sparc64/kernel/dtlb_miss.S
+++ /dev/null
@@ -1,83 +0,0 @@
-/* $Id: dtlb_miss.S,v 1.15 1998/01/14 17:14:44 jj Exp $
- * dtlb_miss.S: Data TLB miss code, this is included directly
- * into the trap table.
- *
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-/* The basic algorithm is:
- *
- * if(faulting_context != 0) {
- * pgd = pgd_offset(current->mm.pgd, fault_address);
- * page_table_walk_continue:
- * pmd = pmd_offset(pgd, fault_address);
- * pte = pte_offset(pmd, fault_address);
- * if(pte & _PAGE_V) {
- * tlb_load(pte, fault_address);
- * return_from_trap();
- * }
- * goto longer_processing;
- * } else {
- * if(fault_address >= PAGE_OFFSET) {
- * pte_val = PAGE_KERNEL;
- * if (fault_address & 0x10000000000)
- * pte_val = PAGE_KERNEL_IO;
- * tlb_load(__pa(fault_address) | pte_val);
- * return_from_trap();
- * } else {
- * pgd = pgd_offset(swapper_pg_dir, fault_address);
- * goto page_table_walk_continue;
- * }
- * }
- *
- * This is optimized for user TLB misses on purpose.
- */
-
-#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
-#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W)
-
- /* ICACHE line 1 */
- /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
- /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits
- /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
- /*0x18*/ and %g1, 0xffe, %g4 ! Mask PMD offset
- /*0x14*/ be,pn %xcc, 3f ! Context 0 == kernel
- /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset
- /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
-
- /* ICACHE line 2 */
- /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
- /*0x24*/ srlx %g1, 1, %g1 ! PTE offset
-2:/*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
- /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
- /*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set?
- /*0x34*/ nop ! delay
- /*0x38*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x3c*/ retry ! Trap return
-
-3: /* ICACHE line 3 */
- /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
- /*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables
- /*0x48*/ or %g2, (KERN_LOWBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
- /*0x4c*/ andcc %g3, 0x100, %g0 ! Slick trick...
- /*0x50*/ bne,a,pn %icc, 5f ! Is it an IO page?
- /*0x54*/ or %g2, (KERN_LOWBITS_IO), %g1 ! Aha, it is IO...
-5:/*0x58*/ xor %g1, %g5, %g1 ! Slick trick II...
- /*0x5c*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load
-
- /* ICACHE line 4 */
- /*0x60*/ retry ! Trap return
- /*0x64*/ nop
- /*0x68*/ nop
- /*0x6c*/ nop
-4:/*0x70*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
- /*0x74*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
- /*0x78*/ ba,pt %xcc, 2b ! Go back up top
- /*0x7c*/ srlx %g1, 1, %g1
-
-#undef KERN_HIGHBITS
-#undef KERN_LOWBITS
-#undef KERN_LOWBITS_IO
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 86cbfdc52..c4ce36502 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,56 +1,62 @@
-/* $Id: dtlb_prot.S,v 1.15 1998/01/14 17:14:46 jj Exp $
- * dtlb_prot.S: Data TLB protection code, this is included directly
- * into the trap table.
+/* $Id: dtlb_prot.S,v 1.17 1998/05/25 16:59:11 davem Exp $
+ * dtlb_prot.S: DTLB protection trap strategy.
+ * This is included directly into the trap table.
*
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
- /* We know kernel never takes protection trap,
- * this makes this routine a lot easier than it
- * would be otherwise.
- */
+#define TAG_CONTEXT_BITS 0x3ff
+#define VPTE_SHIFT (PAGE_SHIFT - 3)
+#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
-#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
+/* Ways we can get here:
+ *
+ * [TL == 0] 1) User stores to readonly pages.
+ * [TL == 0] 2) Nucleus stores to user readonly pages.
+ * [TL > 0] 3) Nucleus stores to user readonly stack frame.
+ */
- /* ICACHE line 1 */
- /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
- /*0x08*/ and %g1, 0xffe, %g4 ! Mask PMD offset
- /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
- /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset
- /*0x14*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
- /*0x18*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD
- /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+/* PROT ** ICACHE line 1: User DTLB protection trap */
+ ldxa [%g1] ASI_DMMU, %g6 ! Primary or Secondary ctx?
+ and %g6, 0x10, %g6 ! Get pri/sec ctx bit
+ stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit
+ membar #Sync ! Synchronize ASI stores
+ ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Load TAG_ACCESS
+ andn %g4, TAG_CONTEXT_BITS, %g4 ! Clear CTX bits
+ stxa %g0, [%g4 + %g6] ASI_DMMU_DEMAP ! Perform TLB flush of page
+ membar #Sync ! Synchronize ASI stores
- /* ICACHE line 2 */
- /*0x20*/ srlx %g1, 1, %g1 ! PTE offset
- /*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE
- /*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable?
- /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! Nope...
- /*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is
- /*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page
- /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg
- /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU
+/* PROT ** ICACHE line 2: Further normal processing */
+ srax %g4, VPTE_SHIFT, %g6 ! Compute VPTE offset
+ ldxa [%g3 + %g6] ASI_S, %g5 ! Load PTE entry
+ andcc %g5, _PAGE_WRITE, %g0 ! Writable page?
+ be,pt %xcc, 1f ! Nope, real fault
+ or %g5, (MODIFIED_BITS), %g5 ! Mark as writable/modified
+ stxa %g5, [%g3 + %g6] ASI_S ! Update PTE entry
+ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load PTE into TLB
+ retry ! Trap return
- /* ICACHE line 3 */
- /*0x40*/ mov TLB_SFSR, %g5 ! read SFSR
- /*0x44*/ srlx %g4, 13, %g4 ! Prepare...
- /*0x48*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
- /*0x4c*/ sllx %g4, 13, %g4 ! ...and mask page
- /*0x50*/ and %g5, 0x10, %g5 ! context bit
- /*0x54*/ or %g4, %g5, %g4 ! for prot trap
-1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
- /*0x5c*/ membar #Sync ! Synchronize
+/* PROT ** ICACHE line 3: Real user faults */
+1: rdpr %pstate, %g5 ! Move into alternate globals
+ wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g4 ! Need to do a winfixup?
+ cmp %g4, 1 ! Trap level >1?
+ mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr
+ bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
+ ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5
+ sethi %hi(1f), %g7 ! Nope, normal fault
- /* ICACHE line 4 */
- /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE
- /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x68*/ retry ! Trap return
- /*0x6c*/ nop
- /*0x70*/ nop
- /*0x74*/ nop
- /*0x78*/ nop
- /*0x7c*/ nop
+/* PROT ** ICACHE line 4: More real fault processing */
+ ba,pt %xcc, etrap ! Save state
+1: or %g7, %lo(1b), %g7 ! ...
+ ba,pt %xcc, sparc64_realfault_continue! Now call the fault handler
+ mov 1, %o2 ! Indicate this was a write
+ nop
+ nop
+ nop
+ nop
+#undef TAG_CONTEXT_BITS
+#undef VPTE_SHIFT
#undef MODIFIED_BITS
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 954cfd4bc..70465afbd 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.23 1998/03/29 16:27:24 ecd Exp $
+/* $Id: ebus.c,v 1.29 1998/07/01 15:39:44 jj Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/malloc.h>
#include <linux/string.h>
#include <asm/system.h>
@@ -30,7 +31,7 @@ struct linux_ebus *ebus_chain = 0;
extern void prom_ebus_ranges_init(struct linux_ebus *);
extern void prom_ebus_intmap_init(struct linux_ebus *);
-extern unsigned long pci_console_init(unsigned long memory_start);
+extern void pci_console_init(void);
#ifdef CONFIG_SUN_OPENPROMIO
extern int openprom_init(void);
@@ -48,18 +49,14 @@ extern int flash_init(void);
extern int envctrl_init(void);
#endif
-extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
- unsigned int full_ino);
-
-static inline unsigned long
-ebus_alloc(unsigned long *memory_start, size_t size)
+static inline unsigned long ebus_alloc(size_t size)
{
unsigned long mem;
- *memory_start = (*memory_start + 7) & ~(7);
- mem = *memory_start;
- *memory_start += size;
- memset((void *)mem, 0, size);
+ mem = (unsigned long)kmalloc(size, GFP_ATOMIC);
+ if (!mem)
+ panic(__FUNCTION__ ": out of memory");
+ memset((char *)mem, 0, size);
return mem;
}
@@ -117,11 +114,27 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
dev->num_irqs = 0;
+ /*
+ * Oh, well, some PROMs don't export interrupts
+ * property to children of EBus devices...
+ *
+ * Be smart about PS/2 keyboard and mouse.
+ */
+ if (!strcmp(dev->parent->prom_name, "8042")) {
+ if (!strcmp(dev->prom_name, "kb_ps2")) {
+ dev->num_irqs = 1;
+ dev->irqs[0] = dev->parent->irqs[0];
+ } else {
+ dev->num_irqs = 1;
+ dev->irqs[0] = dev->parent->irqs[1];
+ }
+ }
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++) {
ebus_intmap_match(dev->bus, preg, &irqs[i]);
- dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+ dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+ dev->bus->self, irqs[i]);
}
}
@@ -133,15 +146,13 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
if (dev->num_irqs) {
dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
for (i = 0; i < dev->num_irqs; i++)
- dprintf(" %08x", dev->irqs[i]);
+ dprintf(" %s", __irq_itoa(dev->irqs[i]));
dprintf("\n");
}
#endif
}
-__initfunc(unsigned long fill_ebus_device(int node,
- struct linux_ebus_device *dev,
- unsigned long memory_start))
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_ebus_child *child;
@@ -176,7 +187,8 @@ __initfunc(unsigned long fill_ebus_device(int node,
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++) {
ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
- dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+ dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+ dev->bus->self, irqs[i]);
}
}
@@ -188,13 +200,13 @@ __initfunc(unsigned long fill_ebus_device(int node,
if (dev->num_irqs) {
dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
for (i = 0; i < dev->num_irqs; i++)
- dprintf(" %08x", dev->irqs[i]);
+ dprintf(" %s", __irq_itoa(dev->irqs[i]));
dprintf("\n");
}
#endif
if ((node = prom_getchild(node))) {
dev->children = (struct linux_ebus_child *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+ ebus_alloc(sizeof(struct linux_ebus_child));
child = dev->children;
child->next = 0;
@@ -204,7 +216,7 @@ __initfunc(unsigned long fill_ebus_device(int node,
while ((node = prom_getsibling(node))) {
child->next = (struct linux_ebus_child *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+ ebus_alloc(sizeof(struct linux_ebus_child));
child = child->next;
child->next = 0;
@@ -213,15 +225,12 @@ __initfunc(unsigned long fill_ebus_device(int node,
fill_ebus_child(node, &regs[0], child);
}
}
-
- return memory_start;
}
extern void sun4u_start_timers(void);
extern void clock_probe(void);
-__initfunc(unsigned long ebus_init(unsigned long memory_start,
- unsigned long memory_end))
+__initfunc(void ebus_init(void))
{
struct linux_prom_pci_registers regs[PROMREG_MAX];
struct linux_pbm_info *pbm;
@@ -237,7 +246,7 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
int num_ebus = 0;
if (!pci_present())
- return memory_start;
+ return;
pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
if (!pdev) {
@@ -245,14 +254,14 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
#ifdef PROM_DEBUG
dprintf("ebus: No EBus's found.\n");
#endif
- return memory_start;
+ return;
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
ebus_chain = ebus = (struct linux_ebus *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus_alloc(sizeof(struct linux_ebus));
ebus->next = 0;
while (ebusnd) {
@@ -323,24 +332,23 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
goto next_ebus;
ebus->devices = (struct linux_ebus_device *)
- ebus_alloc(&memory_start,
- sizeof(struct linux_ebus_device));
+ ebus_alloc(sizeof(struct linux_ebus_device));
dev = ebus->devices;
dev->next = 0;
dev->children = 0;
dev->bus = ebus;
- memory_start = fill_ebus_device(nd, dev, memory_start);
+ fill_ebus_device(nd, dev);
while ((nd = prom_getsibling(nd))) {
dev->next = (struct linux_ebus_device *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+ ebus_alloc(sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = 0;
dev->children = 0;
dev->bus = ebus;
- memory_start = fill_ebus_device(nd, dev, memory_start);
+ fill_ebus_device(nd, dev);
}
next_ebus:
@@ -353,13 +361,15 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
ebusnd = cookie->prom_node;
ebus->next = (struct linux_ebus *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
ebus->next = 0;
++num_ebus;
}
- memory_start = pci_console_init(memory_start);
+#ifndef CONFIG_FB
+ pci_console_init();
+#endif
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
@@ -381,5 +391,4 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
#endif
sun4u_start_timers();
clock_probe();
- return memory_start;
}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 76f913ade..774839af6 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,10 +1,10 @@
-/* $Id: entry.S,v 1.76 1998/01/05 17:00:13 jj Exp $
+/* $Id: entry.S,v 1.87 1998/07/29 16:32:28 jj Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/config.h>
@@ -18,6 +18,7 @@
#include <asm/signal.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
+#include <asm/visasm.h>
/* #define SYSCALL_TRACING */
@@ -26,117 +27,23 @@
#define NR_SYSCALLS 256 /* Each OS is different... */
.text
- .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch
- .globl sparc64_itlb_refbit_catch
-
- /* Note, DMMU SFAR not updated for fast tlb data access miss
- * traps, so we must use tag access to find the right page.
- * However for DMMU fast protection traps it is updated so
- * we use, but we must also clear it _before_ we enable interrupts
- * and save state because there is a race where we can push a user
- * window right now in etrap, a protection fault happens (for example
- * to update the dirty bit) and since we left crap in the sfsr
- * it will not get updated properly.
- */
- .align 32
-sparc64_dtlb_prot_catch:
- wr %g0, ASI_DMMU, %asi
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
- rdpr %tl, %g3
- ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
- stxa %g0, [%g0 + TLB_SFSR] %asi
- membar #Sync
- cmp %g3, 1
-
- bgu,a,pn %icc, winfix_trampoline
- rdpr %tpc, %g3
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- b,pt %xcc, 1f
- mov 1, %o2
- .align 32
-sparc64_dtlb_refbit_catch:
- srlx %g5, 9, %g4
- and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
- cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
- be,a,pt %xcc, 2f
- mov 1, %g4
- wr %g0, ASI_DMMU, %asi
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
-
- rdpr %tl, %g3
- ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5
- cmp %g3, 1
- bgu,pn %icc, winfix_trampoline
- rdpr %tpc, %g3
- sethi %hi(109f), %g7
- b,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
-
- clr %o2
-1: srlx %l5, PAGE_SHIFT, %o1
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- call do_sparc64_fault
- sllx %o1, PAGE_SHIFT, %o1
- b,pt %xcc, rtrap
- clr %l6
.align 32
-sparc64_itlb_refbit_catch:
- srlx %g5, 9, %g4
- and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
- cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
- be,a,pt %xcc, 3f
- mov 1, %g4
- rdpr %pstate, %g1
- wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate
- rdpr %tpc, %g5
- sethi %hi(109f), %g7
- b,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- b,pt %xcc, 1b
- clr %o2
-
- .align 32
-2: sllx %g4, 63, %g4 ! _PAGE_VALID
- or %g5, _PAGE_ACCESSED, %g5
- or %g5, %g4, %g5
- stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
- stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
- retry
-
- .align 32
-3: sllx %g4, 63, %g4 ! _PAGE_VALID
- or %g5, _PAGE_ACCESSED, %g5
- or %g5, %g4, %g5
- stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE
- stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
- retry
-
-#define FPDIS_OFF (((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))
/* This is trivial with the new code... */
.align 32
.globl do_fpdis
do_fpdis:
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group
sethi %hi(TSTATE_PEF), %g4 ! IEU0
- sethi %hi(FPDIS_OFF), %g3 ! IEU1
wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles
- andcc %g5, SPARC_FLAG_USEDFPU, %g0 ! IEU1 Group
- or %g3, %lo(FPDIS_OFF), %g2 ! IEU0
- sethi %hi(empty_zero_page), %g1 ! IEU0 Group
- add %g6, %g2, %g2 ! IEU1
- be,a,pn %icc, 1f ! CTI
- clr %g7 ! IEU0 Group
- add %g2, 0x100, %g1 ! IEU1
- ldx [%g2 + 0x108], %g7 ! Load
-1: andcc %g5, SPARC_FLAG_USEDFPUL, %g0 ! IEU1 Group
+ andcc %g5, FPRS_FEF, %g0 ! IEU1 Group
+ be,a,pt %icc, 1f ! CTI
+ clr %g7 ! IEU0
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_gsr], %g7 ! Load Group
+1: andcc %g5, FPRS_DL, %g0 ! IEU1
bne,pn %icc, 2f ! CTI
fzero %f0 ! FPA
- andcc %g5, SPARC_FLAG_USEDFPUU, %g0 ! IEU1 Group
+ andcc %g5, FPRS_DU, %g0 ! IEU1 Group
bne,pn %icc, 1f ! CTI
fzero %f2 ! FPA
faddd %f0, %f2, %f4
@@ -170,17 +77,18 @@ do_fpdis:
b,pt %xcc, fpdis_exit2
faddd %f0, %f2, %f60
1: mov SECONDARY_CONTEXT, %g3
+ add %g6, AOFF_task_fpregs + 0x80, %g1
faddd %f0, %f2, %f4
fmuld %f0, %f2, %f6
ldxa [%g3] ASI_DMMU, %g5
+ add %g6, AOFF_task_fpregs + 0xc0, %g2
stxa %g0, [%g3] ASI_DMMU
faddd %f0, %f2, %f8
fmuld %f0, %f2, %f10
- flush %g2
- wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ flush %g6
membar #StoreLoad | #LoadLoad
- ldda [%g2 + 0x080] %asi, %f32
- ldda [%g2 + 0x0c0] %asi, %f48
+ ldda [%g1] ASI_BLK_S, %f32 ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ ldda [%g2] ASI_BLK_S, %f48
faddd %f0, %f2, %f12
fmuld %f0, %f2, %f14
faddd %f0, %f2, %f16
@@ -193,20 +101,21 @@ do_fpdis:
fmuld %f0, %f2, %f30
b,pt %xcc, fpdis_exit
membar #Sync
-2: andcc %g5, SPARC_FLAG_USEDFPUU, %g0
+2: andcc %g5, FPRS_DU, %g0
bne,pt %icc, 3f
fzero %f32
mov SECONDARY_CONTEXT, %g3
fzero %f34
ldxa [%g3] ASI_DMMU, %g5
+ add %g6, AOFF_task_fpregs, %g1
stxa %g0, [%g3] ASI_DMMU
+ add %g6, AOFF_task_fpregs + 0x40, %g2
faddd %f32, %f34, %f36
fmuld %f32, %f34, %f38
- flush %g2
- wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ flush %g6
membar #StoreLoad | #LoadLoad
- ldda [%g2 + 0x000] %asi, %f0
- ldda [%g2 + 0x040] %asi, %f16
+ ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ ldda [%g2] ASI_BLK_S, %f16
faddd %f32, %f34, %f40
fmuld %f32, %f34, %f42
faddd %f32, %f34, %f44
@@ -222,22 +131,24 @@ do_fpdis:
b,pt %xcc, fpdis_exit
membar #Sync
3: mov SECONDARY_CONTEXT, %g3
+ add %g6, AOFF_task_fpregs, %g1
ldxa [%g3] ASI_DMMU, %g5
+ mov 0x40, %g2
stxa %g0, [%g3] ASI_DMMU
- flush %g2
- wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ flush %g6
membar #StoreLoad | #LoadLoad
- ldda [%g2 + 0x000] %asi, %f0
- ldda [%g2 + 0x040] %asi, %f16
- ldda [%g2 + 0x080] %asi, %f32
- ldda [%g2 + 0x0c0] %asi, %f48
+ ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-(
+ ldda [%g1 + %g2] ASI_BLK_S, %f16
+ add %g1, 0x80, %g1
+ ldda [%g1] ASI_BLK_S, %f32
+ ldda [%g1 + %g2] ASI_BLK_S, %f48
membar #Sync
fpdis_exit:
stxa %g5, [%g3] ASI_DMMU
- flush %g2
+ flush %g6
fpdis_exit2:
wr %g7, 0, %gsr
- ldx [%g1], %fsr
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_xfsr], %fsr
rdpr %tstate, %g3
or %g3, %g4, %g3 ! anal...
wrpr %g3, %tstate
@@ -300,8 +211,10 @@ do_ivec_xcall:
add %g2, 0x10, %g2
ldxa [%g2] ASI_UDB_INTR_R, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
jmpl %g3, %g0
- membar #Sync
+ nop
+
do_ivec_spurious:
srl %g3, 3, %g3
sethi %hi(ivec_spurious_cookie), %g2
@@ -588,6 +501,8 @@ sunos_execv:
.globl sys_sigreturn, sys_rt_sigreturn
.globl sys32_sigreturn, sys32_rt_sigreturn
.globl sys32_execve, sys_ptrace
+ .globl sys_sigaltstack, sys32_sigaltstack
+ .globl sys32_sigstack
.align 32
sys_pipe: sethi %hi(sparc_pipe), %g1
add %sp, STACK_BIAS + REGWIN_SZ, %o0
@@ -611,6 +526,19 @@ sys_memory_ordering:
add %sp, STACK_BIAS + REGWIN_SZ, %o1
jmpl %g1 + %lo(sparc_memory_ordering), %g0
nop
+sys_sigaltstack:sethi %hi(do_sigaltstack), %g1
+ add %i6, STACK_BIAS, %o2
+ jmpl %g1 + %lo(do_sigaltstack), %g1
+ nop
+sys32_sigstack: sethi %hi(do_sys32_sigstack), %g1
+ mov %i6, %o2
+ jmpl %g1 + %lo(do_sys32_sigstack), %g1
+ nop
+sys32_sigaltstack:
+ sethi %hi(do_sys32_sigaltstack), %g1
+ mov %i6, %o2
+ jmpl %g1 + %lo(do_sys32_sigaltstack), %g1
+ nop
.align 32
sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0
@@ -666,7 +594,7 @@ sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
- /* This is how fork() was meant to be done, 12 instruction entry.
+ /* This is how fork() was meant to be done, 8 instruction entry.
*
* I questioned the following code briefly, let me clear things
* up so you must not reason on it like I did.
@@ -689,26 +617,43 @@ sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0
* In fact we should take advantage of that fact for other things
* during system calls...
*/
- .globl sys_fork, sys_vfork, sys_clone
- .globl ret_from_syscall, ret_from_smpfork
+ .globl sys_fork, sys_vfork, sys_clone, sparc_exit
+ .globl ret_from_syscall
.align 32
sys_fork:
sys_vfork: mov SIGCHLD, %o0
clr %o1
-sys_clone: mov %o7, %l5
+sys_clone: flushw
+ mov %o7, %l5
add %sp, STACK_BIAS + REGWIN_SZ, %o2
movrz %o1, %fp, %o1
call do_fork
mov %l5, %o7
+ret_from_syscall:
+ /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
+ * %o7 for us.
+ */
+ andn %o7, 0x100, %o7
+ sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags]
#ifdef __SMP__
-ret_from_smpfork:
sethi %hi(scheduler_lock), %o4
membar #StoreStore | #LoadStore
stb %g0, [%o4 + %lo(scheduler_lock)]
#endif
-ret_from_syscall:
b,pt %xcc, ret_sys_call
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+sparc_exit: rdpr %otherwin, %g1
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IE, %pstate
+ rdpr %cansave, %g3
+ add %g3, %g1, %g3
+ wrpr %g3, 0x0, %cansave
+ wrpr %g0, 0x0, %otherwin
+ wrpr %g2, 0x0, %pstate
+ mov %o7, %l5
+ sth %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+ call sys_exit
+ mov %l5, %o7
linux_sparc_ni_syscall:
sethi %hi(sys_ni_syscall), %l7
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 9e7c9e374..1b6a1e2b0 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,8 +1,8 @@
-/* $Id: etrap.S,v 1.39 1997/10/24 11:57:47 jj Exp $
+/* $Id: etrap.S,v 1.40 1998/06/12 14:54:03 jj Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <asm/asi.h>
@@ -12,41 +12,32 @@
#include <asm/spitfire.h>
#include <asm/head.h>
-#define FPUREG_SZ ((64 * 4) + (2 * 8))
-#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
- TRACEREG_SZ-REGWIN_SZ)
-#define FPU_OFF (STACK_BIAS + REGWIN_SZ + TRACEREG_SZ)
+#define TASK_REGOFF ((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ)
/*
* On entry, %g7 is return address - 0x4.
* %g4 and %g5 will be preserved %l4 and %l5 respectively.
*/
- .text
- .align 32
-etrap_priv: or %g1, %g3, %g1 ! IEU0 Group
- rd %fprs, %g3 ! Single Group+4bubbles
- sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU0 Group
- andcc %g3, FPRS_FEF, %g0 ! IEU1
- add %g2, REGWIN_SZ + TRACEREG_SZ - FPUREG_SZ, %g3 ! IEU0 Group
- be,pt %icc, 1f ! CTI
- andcc %g1, TSTATE_PRIV, %g0 ! IEU1
- andn %g3, (64 - 1), %g3 ! IEU0 Group
- ba,pt %xcc, 1f ! CTI
- sub %g3, REGWIN_SZ + TRACEREG_SZ, %g2 ! IEU0 Group
-
+ .text
.align 32
.globl etrap, etrap_irq, etraptl1
+ .globl scetrap
etrap: rdpr %pil, %g2 ! Single Group
etrap_irq: rdpr %tstate, %g1 ! Single Group
sllx %g2, 20, %g3 ! IEU0 Group
andcc %g1, TSTATE_PRIV, %g0 ! IEU1
- bne,pn %xcc, etrap_priv ! CTI
- sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
- or %g1, %g3, %g1 ! IEU1
+ or %g1, %g3, %g1 ! IEU0 Group
+ bne,a,pn %xcc, 1f ! CTI
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
+ sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
+ sethi %hi(TSTATE_PEF), %g3 ! IEU1
or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
- add %g6, %g2, %g2 ! IEU0 Group
+ and %g1, %g3, %g3 ! IEU1
+ brnz,pn %g3, 1f ! CTI+IEU1 Group
+ add %g6, %g2, %g2 ! IEU0
+ wr %g0, 0, %fprs ! Single Group+4bubbles
1: rdpr %tpc, %g3 ! Single Group
stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
rdpr %tnpc, %g1 ! Single Group
@@ -56,62 +47,27 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
- bne,pn %xcc, 2f ! CTI Group
- sethi %hi(TSTATE_PEF), %l2 ! IEU0
- mov PRIMARY_CONTEXT, %l4 ! IEU1
+ andn %g6, 0x1f, %l6 ! IEU0 Group
+ bne,pn %xcc, 3f ! CTI
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
rdpr %canrestore, %g3 ! Single Group+4bubbles
rdpr %wstate, %g2 ! Single Group+4bubbles
wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
wrpr %g0, 0, %canrestore ! Single Group+4bubbles
sll %g2, 3, %g2 ! IEU0 Group
- mov SECONDARY_CONTEXT, %l5 ! IEU1
+ mov 1, %l5 ! IEU1
+ stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store
wrpr %g3, 0, %otherwin ! Single Group+4bubbles
wrpr %g2, 0, %wstate ! Single Group+4bubbles
- rdpr %tstate, %l3 ! Single Group
ldxa [%l4] ASI_DMMU, %g2 ! Load Group
stxa %g0, [%l4] ASI_DMMU ! Store Group
- stxa %g2, [%l5] ASI_DMMU ! Store Group
- flush %g6 ! Single Group+9bubbles
- andcc %l3, %l2, %g0 ! IEU1 Group
- be,a,pt %icc, 6f ! CTI
- st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
- rd %fprs, %l0 ! Single Group+4bubbles
- andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
- be,pn %icc, 6f ! CTI
- st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group
- stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
- or %l4, %l0, %l4 ! IEU0 Group
- ba,pt %xcc, 3f ! CTI
- sth %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store
-2: rd %fprs, %l0 ! Single Group+4bubbles
- andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
- be,pn %icc, 6f ! CTI
- st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
- stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
-3: rd %gsr, %l7 ! Single Group+4bubbles
- cmp %l0, FPRS_FEF ! IEU1 Group
- be,pn %icc, 6f ! CTI
- stx %l7, [%sp + FPU_OFF + 0x108] ! Store
- wr %g0, ASI_BLK_P, %asi ! Singe Group+4bubbles
- andcc %l0, FPRS_DL, %g0 ! IEU1 Group
- be,pn %icc, 4f ! CTI
- membar #StoreStore | #LoadStore ! Memory
- stda %f0, [%sp + FPU_OFF + 0x000] %asi ! Store Group
- stda %f16, [%sp + FPU_OFF + 0x040] %asi ! Store Group
- andcc %l0, FPRS_DU, %g0 ! IEU1
- be,pn %icc, 5f ! CTI
- nop ! IEU0 Group
-4: stda %f32, [%sp + FPU_OFF + 0x080] %asi ! Store Group
- stda %f48, [%sp + FPU_OFF + 0x0c0] %asi ! Store Group
-5: membar #Sync ! Memory
-6: wr %g0, 0x0, %fprs ! Single Group+4bubbles
- wrpr %g0, 0x0, %tl ! Single Group+4bubbles
+ stxa %g2, [%l4 + %l4] ASI_DMMU ! Store Group
+ flush %l6 ! Single Group+9bubbles
+2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles
andn %g1, PSTATE_MM, %l1 ! IEU0 Group
mov %g4, %l4 ! IEU1
mov %g5, %l5 ! IEU0 Group
mov %g7, %l2 ! IEU1
- mov %g6, %l6 ! IEU0 Group
wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
@@ -134,8 +90,80 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
jmpl %l2 + 0x4, %g0 ! CTI Group
mov %l6, %g6 ! IEU0
+3: ldub [%l6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5 ! Load Group
+ add %l6, AOFF_task_tss + AOFF_thread_fpsaved + 1, %l4 ! IEU0
+ srl %l5, 1, %l3 ! IEU0 Group
+ add %l5, 2, %l5 ! IEU1
+ stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store
+ ba,pt %xcc, 2b ! CTI
+ stb %g0, [%l4 + %l3] ! Store Group
+
etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles
- ba,pt %xcc, etrap_priv ! CTI Group
- clr %g3 ! IEU0
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
+ ba,pt %xcc, 1b ! CTI Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU0
+
+scetrap: rdpr %pil, %g2 ! Single Group
+ rdpr %tstate, %g1 ! Single Group
+ sllx %g2, 20, %g3 ! IEU0 Group
+ andcc %g1, TSTATE_PRIV, %g0 ! IEU1
+ or %g1, %g3, %g1 ! IEU0 Group
+ bne,a,pn %xcc, 1f ! CTI
+ sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1
+ sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group
+ sethi %hi(TSTATE_PEF), %g3 ! IEU1
+ or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group
+ and %g1, %g3, %g3 ! IEU1
+ brnz,pn %g3, 1f ! CTI+IEU1 Group
+ add %g6, %g2, %g2 ! IEU0
+ wr %g0, 0, %fprs ! Single Group+4bubbles
+1: rdpr %tpc, %g3 ! Single Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group
+ rdpr %tnpc, %g1 ! Single Group
+ stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group
+ stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group
+ st %g0, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group
+ save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group
+ rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles
+ andn %g6, 0x1f, %l6 ! IEU0 Group
+ bne,pn %xcc, 2f ! CTI
+ mov PRIMARY_CONTEXT, %l4 ! IEU1
+ rdpr %canrestore, %g3 ! Single Group+4bubbles
+ rdpr %wstate, %g2 ! Single Group+4bubbles
+ wrpr %g0, 7, %cleanwin ! Single Group+4bubbles
+ wrpr %g0, 0, %canrestore ! Single Group+4bubbles
+ sll %g2, 3, %g2 ! IEU0 Group
+ wrpr %g3, 0, %otherwin ! Single Group+4bubbles
+ wrpr %g2, 0, %wstate ! Single Group+4bubbles
+ ldxa [%l4] ASI_DMMU, %g2 ! Load Group
+ stxa %g0, [%l4] ASI_DMMU ! Store Group
+ stxa %g2, [%l4 + %l4] ASI_DMMU ! Store Group
+ flush %l6 ! Single Group+9bubbles
+2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles
+ andn %g1, PSTATE_MM, %l1 ! IEU0 Group
+ mov %g4, %l4 ! IEU1
+ mov %g5, %l5 ! IEU0 Group
+ mov %g7, %l2 ! IEU1
+ wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group
+ stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group
+ stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group
+ stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group
+ stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group
+ stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group
+ stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group
+ stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group
+ stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group
+ stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group
+ stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group
+ stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group
+ stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group
+ sllx %g4, 32, %g4 ! IEU0
+ stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group
+ wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles
+ jmpl %l2 + 0x4, %g0 ! CTI Group
+ mov %l6, %g6 ! IEU0
+
#undef TASK_REGOFF
-#undef FPUREG_SZ
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c0531f30a..f1e9c62fd 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.49 1998/03/03 12:31:17 jj Exp $
+/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -89,6 +89,7 @@ sparc64_boot:
* (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
*/
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+ wr %g0, 0, %fprs
#ifdef __SMP__
/* Ugly but necessary... */
@@ -348,17 +349,30 @@ setup_tba:
/* Set up MMU globals */
wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate
- /* Set KERN_HIGHBITS used by dTLB miss handler. */
-#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+ /* Set fixed globals used by dTLB miss handler. */
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+#ifdef THIS_IS_CHEETAH
+#error Dave, make sure you took care of other issues in rest of sparc64 code...
+#define VPTE_BASE 0xffe0000000000000
+#else /* Spitfire/Blackbird */
+#define VPTE_BASE 0xfffffffe00000000
+#endif
+ mov TSB_REG, %g1
+ stxa %g0, [%g1] ASI_DMMU
+ membar #Sync
+ mov TLB_SFSR, %g1
sethi %uhi(KERN_HIGHBITS), %g2
+ or %g2, %ulo(KERN_HIGHBITS), %g2
sllx %g2, 32, %g2
-#undef KERN_HIGHBITS
-
- /* Kernel PGDIR used by TLB miss handlers. */
- mov %i0, %g6
-
- /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */
+ or %g2, KERN_LOWBITS, %g2
+ sethi %uhi(VPTE_BASE), %g3
+ or %g3, %ulo(VPTE_BASE), %g3
+ sllx %g3, 32, %g3
clr %g7
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
+#undef VPTE_BASE
/* Setup Interrupt globals */
wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
@@ -372,14 +386,6 @@ setup_tba:
wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate
- /* Zap TSB BASE to zero with TSB_size==1. */
- mov TSB_REG, %o4
- mov 1, %o5
- stxa %o5, [%o4] ASI_DMMU
- stxa %o5, [%o4] ASI_IMMU
-
- membar #Sync
-
sethi %hi(sparc64_ttable_tl0), %g5
call prom_set_trap_table
mov %g5, %o0
@@ -403,6 +409,12 @@ empty_bad_page:
#include "ttable.S"
#include "systbls.S"
+
+ .align 1024
+ .globl swapper_pg_dir
+swapper_pg_dir:
+ .word 0
+
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
@@ -420,3 +432,4 @@ prom_tba: .xword 0
__ret_efault:
ret
restore %g0, -EFAULT, %o0
+
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 17e904f25..51fbd6ce5 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,7 +1,8 @@
-/* $Id: ioctl32.c,v 1.35 1998/04/10 02:01:46 davem Exp $
+/* $Id: ioctl32.c,v 1.48 1998/08/03 23:58:04 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
@@ -28,6 +29,11 @@
#include <linux/if_ppp.h>
#include <linux/mtio.h>
#include <linux/cdrom.h>
+#include <linux/loop.h>
+#include <linux/auto_fs.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/fb.h>
#include <scsi/scsi.h>
/* Ugly hack. */
@@ -42,6 +48,8 @@
#include <asm/vuid_event.h>
#include <asm/rtc.h>
#include <asm/openpromio.h>
+#include <asm/envctrl.h>
+#include <asm/audioio.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
@@ -66,6 +74,22 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
return err;
}
+static int rw_long(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ int err;
+ unsigned long val;
+
+ if(get_user(val, (u32 *)A(arg)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&val);
+ set_fs (old_fs);
+ if (!err && put_user(val, (u32 *)A(arg)))
+ return -EFAULT;
+ return err;
+}
+
struct timeval32 {
int tv_sec;
int tv_usec;
@@ -374,7 +398,7 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg)
}
f.red = red; f.green = green; f.blue = blue;
set_fs (KERNEL_DS);
- ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP : FBIOGETCMAP, (long)&f);
+ ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f);
set_fs (old_fs);
if (!ret && cmd == FBIOGETCMAP32) {
if (copy_to_user ((char *)A(r), red, f.count) ||
@@ -440,7 +464,162 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
set_fs (old_fs);
return ret;
}
-
+
+struct fb_fix_screeninfo32 {
+ char id[16];
+ __kernel_caddr_t32 smem_start;
+ __u32 smem_len;
+ __u32 type;
+ __u32 type_aux;
+ __u32 visual;
+ __u16 xpanstep;
+ __u16 ypanstep;
+ __u16 ywrapstep;
+ __u32 line_length;
+ __kernel_caddr_t32 mmio_start;
+ __u32 mmio_len;
+ __u32 accel;
+ __u16 reserved[3];
+};
+
+struct fb_cmap32 {
+ __u32 start;
+ __u32 len;
+ __kernel_caddr_t32 red;
+ __kernel_caddr_t32 green;
+ __kernel_caddr_t32 blue;
+ __kernel_caddr_t32 transp;
+};
+
+static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ u32 red = 0, green = 0, blue = 0, transp = 0;
+ struct fb_fix_screeninfo fix;
+ struct fb_cmap cmap;
+ void *karg;
+ int err = 0;
+
+ switch (cmd) {
+ case FBIOGET_FSCREENINFO:
+ karg = &fix;
+ break;
+ case FBIOGETCMAP:
+ case FBIOPUTCMAP:
+ karg = &cmap;
+ if (__get_user(cmap.start, &((struct fb_cmap32 *)A(arg))->start) ||
+ __get_user(cmap.len, &((struct fb_cmap32 *)A(arg))->len) ||
+ __get_user(red, &((struct fb_cmap32 *)A(arg))->red) ||
+ __get_user(green, &((struct fb_cmap32 *)A(arg))->green) ||
+ __get_user(blue, &((struct fb_cmap32 *)A(arg))->blue) ||
+ __get_user(transp, &((struct fb_cmap32 *)A(arg))->transp))
+ return -EFAULT;
+ cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+ if (!cmap.red)
+ return -ENOMEM;
+ cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+ if (!cmap.green) {
+ kfree(cmap.red);
+ return -ENOMEM;
+ }
+ cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+ if (!cmap.blue) {
+ kfree(cmap.red);
+ kfree(cmap.green);
+ return -ENOMEM;
+ }
+ if (transp) {
+ cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
+ if (!cmap.transp) {
+ kfree(cmap.red);
+ kfree(cmap.green);
+ kfree(cmap.blue);
+ return -ENOMEM;
+ }
+ } else {
+ cmap.transp = NULL;
+ }
+ if (cmd == FBIOGETCMAP)
+ break;
+
+ if (__copy_from_user(cmap.red, (char *)A(((struct fb_cmap32 *)A(arg))->red),
+ cmap.len * sizeof(__u16)) ||
+ __copy_from_user(cmap.green, (char *)A(((struct fb_cmap32 *)A(arg))->green),
+ cmap.len * sizeof(__u16)) ||
+ __copy_from_user(cmap.blue, (char *)A(((struct fb_cmap32 *)A(arg))->blue),
+ cmap.len * sizeof(__u16)) ||
+ (cmap.transp &&
+ __copy_from_user(cmap.transp, (char *)A(((struct fb_cmap32 *)A(arg))->transp),
+ cmap.len * sizeof(__u16)))) {
+ kfree(cmap.red);
+ kfree(cmap.green);
+ kfree(cmap.blue);
+ if (cmap.transp)
+ kfree(cmap.transp);
+ return -EFAULT;
+ }
+ break;
+ default:
+ printk("%s: Unknown fb ioctl cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ __FUNCTION__, fd, cmd, arg);
+ return -ENOSYS;
+ }
+ set_fs(KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)karg);
+ set_fs(old_fs);
+ if (err)
+ return err;
+ switch (cmd) {
+ case FBIOGET_FSCREENINFO:
+ if (__copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->id,
+ (char *)fix.id, sizeof(fix.id)) ||
+ __put_user((__u32)(unsigned long)fix.smem_start,
+ &((struct fb_fix_screeninfo32 *)A(arg))->smem_start) ||
+ __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)A(arg))->smem_len) ||
+ __put_user(fix.type, &((struct fb_fix_screeninfo32 *)A(arg))->type) ||
+ __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)A(arg))->type_aux) ||
+ __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)A(arg))->visual) ||
+ __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)A(arg))->xpanstep) ||
+ __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)A(arg))->ypanstep) ||
+ __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)A(arg))->ywrapstep) ||
+ __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)A(arg))->line_length) ||
+ __put_user((__u32)(unsigned long)fix.mmio_start,
+ &((struct fb_fix_screeninfo32 *)A(arg))->mmio_start) ||
+ __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)A(arg))->mmio_len) ||
+ __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)A(arg))->accel) ||
+ __copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->reserved,
+ (char *)fix.reserved, sizeof(fix.reserved)))
+ return -EFAULT;
+ break;
+ case FBIOGETCMAP:
+ if (__copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->red), cmap.red,
+ cmap.len * sizeof(__u16)) ||
+ __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->green), cmap.blue,
+ cmap.len * sizeof(__u16)) ||
+ __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->blue), cmap.blue,
+ cmap.len * sizeof(__u16)) ||
+ (cmap.transp &&
+ __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->transp), cmap.transp,
+ cmap.len * sizeof(__u16)))) {
+ kfree(cmap.red);
+ kfree(cmap.green);
+ kfree(cmap.blue);
+ if (cmap.transp)
+ kfree(cmap.transp);
+ return -EFAULT;
+ }
+ /* fall through */
+ case FBIOPUTCMAP:
+ kfree(cmap.red);
+ kfree(cmap.green);
+ kfree(cmap.blue);
+ if (cmap.transp)
+ kfree(cmap.transp);
+ break;
+ }
+ return 0;
+}
+
static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
{
mm_segment_t old_fs = get_fs();
@@ -1059,6 +1238,190 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
return 0;
}
+struct loop_info32 {
+ int lo_number; /* ioctl r/o */
+ __kernel_dev_t32 lo_device; /* ioctl r/o */
+ unsigned int lo_inode; /* ioctl r/o */
+ __kernel_dev_t32 lo_rdevice; /* ioctl r/o */
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size; /* ioctl w/o */
+ int lo_flags; /* ioctl r/o */
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+ unsigned int lo_init[2];
+ char reserved[4];
+};
+
+static int loop_status(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ struct loop_info l;
+ int err = 0;
+
+ switch(cmd) {
+ case LOOP_SET_STATUS:
+ if ((get_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) ||
+ __get_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) ||
+ __get_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) ||
+ __get_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) ||
+ __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)A(arg))->lo_offset,
+ 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset)))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&l);
+ set_fs (old_fs);
+ break;
+ case LOOP_GET_STATUS:
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&l);
+ set_fs (old_fs);
+ if (!err &&
+ (put_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) ||
+ __put_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) ||
+ __put_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) ||
+ __put_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) ||
+ __copy_to_user((char *)&((struct loop_info32 *)A(arg))->lo_offset,
+ (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset)))
+ err = -EFAULT;
+ break;
+ }
+ return err;
+}
+
+extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+
+static int vt_check(struct file *file)
+{
+ struct tty_struct *tty;
+ struct inode *inode = file->f_dentry->d_inode;
+
+ if (file->f_op->ioctl != tty_ioctl)
+ return -EINVAL;
+
+ tty = (struct tty_struct *)file->private_data;
+ if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+ return -EINVAL;
+
+ if (tty->driver.ioctl != vt_ioctl)
+ return -EINVAL;
+
+ /*
+ * To have permissions to do most of the vt ioctls, we either have
+ * to be the owner of the tty, or super-user.
+ */
+ if (current->tty == tty || suser())
+ return 1;
+ return 0;
+}
+
+struct consolefontdesc32 {
+ unsigned short charcount; /* characters in font (256 or 512) */
+ unsigned short charheight; /* scan lines per character (1-32) */
+ u32 chardata; /* font data in expanded form */
+};
+
+static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 *user_cfd)
+{
+ struct consolefontdesc cfdarg;
+ struct console_font_op op;
+ int i, perm;
+
+ perm = vt_check(file);
+ if (perm < 0) return perm;
+
+ if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32)))
+ return -EFAULT;
+
+ cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata);
+
+ switch (cmd) {
+ case PIO_FONTX:
+ if (!perm)
+ return -EPERM;
+ op.op = KD_FONT_OP_SET;
+ op.flags = 0;
+ op.width = 8;
+ op.height = cfdarg.charheight;
+ op.charcount = cfdarg.charcount;
+ op.data = cfdarg.chardata;
+ return con_font_op(fg_console, &op);
+ case GIO_FONTX:
+ if (!cfdarg.chardata)
+ return 0;
+ op.op = KD_FONT_OP_GET;
+ op.flags = 0;
+ op.width = 8;
+ op.height = cfdarg.charheight;
+ op.charcount = cfdarg.charcount;
+ op.data = cfdarg.chardata;
+ i = con_font_op(fg_console, &op);
+ if (i)
+ return i;
+ cfdarg.charheight = op.height;
+ cfdarg.charcount = op.charcount;
+ ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata;
+ if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+struct console_font_op32 {
+ unsigned int op; /* operation code KD_FONT_OP_* */
+ unsigned int flags; /* KD_FONT_FLAG_* */
+ unsigned int width, height; /* font size */
+ unsigned int charcount;
+ u32 data; /* font data with height fixed to 32 */
+};
+
+static int do_kdfontop_ioctl(struct file *file, struct console_font_op32 *fontop)
+{
+ struct console_font_op op;
+ int perm = vt_check(file), i;
+ struct vt_struct *vt;
+
+ if (perm < 0) return perm;
+
+ if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32)))
+ return -EFAULT;
+ if (!perm && op.op != KD_FONT_OP_GET)
+ return -EPERM;
+ op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data);
+ op.flags |= KD_FONT_FLAG_OLD;
+ vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data;
+ i = con_font_op(vt->vc_num, &op);
+ if (i) return i;
+ ((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
+ if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32)))
+ return -EFAULT;
+ return 0;
+}
+
+struct unimapdesc32 {
+ unsigned short entry_ct;
+ u32 entries;
+};
+
+static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user_ud)
+{
+ struct unimapdesc32 tmp;
+ int perm = vt_check(file);
+
+ if (perm < 0) return perm;
+ if (copy_from_user(&tmp, user_ud, sizeof tmp))
+ return -EFAULT;
+ switch (cmd) {
+ case PIO_UNIMAP:
+ if (!perm) return -EPERM;
+ return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries));
+ case GIO_UNIMAP:
+ return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries));
+ }
+ return 0;
+}
+
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file * filp;
@@ -1131,6 +1494,10 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case BLKRAGET:
case BLKGETSIZE:
+ case 0x1260:
+ /* The mkswap binary hard codes it to Intel value :-((( */
+ if(cmd == 0x1260)
+ cmd = BLKGETSIZE;
error = w_long(fd, cmd, arg);
goto out;
@@ -1143,6 +1510,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = fbiogscursor(fd, cmd, arg);
goto out;
+ case FBIOGET_FSCREENINFO:
+ case FBIOGETCMAP:
+ case FBIOPUTCMAP:
+ error = fb_ioctl_trans(fd, cmd, arg);
+ goto out;
+
case HDIO_GET_KEEPSETTINGS:
case HDIO_GET_UNMASKINTR:
case HDIO_GET_DMA:
@@ -1185,7 +1558,30 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case CDROMREADALL:
error = cdrom_ioctl_trans(fd, cmd, arg);
goto out;
+
+ case LOOP_SET_STATUS:
+ case LOOP_GET_STATUS:
+ error = loop_status(fd, cmd, arg);
+ goto out;
+
+ case AUTOFS_IOC_SETTIMEOUT:
+ error = rw_long(fd, cmd, arg);
+ goto out;
+
+ case PIO_FONTX:
+ case GIO_FONTX:
+ error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)A(arg));
+ goto out;
+
+ case PIO_UNIMAP:
+ case GIO_UNIMAP:
+ error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)A(arg));
+ goto out;
+ case KDFONTOP:
+ error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)A(arg));
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
@@ -1237,6 +1633,17 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case FBIOGCURPOS:
case FBIOGCURMAX:
+ case FBIOGET_VSCREENINFO:
+ case FBIOPUT_VSCREENINFO:
+ case FBIOPAN_DISPLAY:
+ case FBIOGET_FCURSORINFO:
+ case FBIOGET_VCURSORINFO:
+ case FBIOPUT_VCURSORINFO:
+ case FBIOGET_CURSORSTATE:
+ case FBIOPUT_CURSORSTATE:
+ case FBIOGET_CON2FBMAP:
+ case FBIOPUT_CON2FBMAP:
+
/* Little f */
case FIOCLEX:
case FIONCLEX:
@@ -1319,6 +1726,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case KDSKBLED:
case KDGETLED:
case KDSETLED:
+ case GIO_SCRNMAP:
+ case PIO_SCRNMAP:
+ case GIO_UNISCRNMAP:
+ case PIO_UNISCRNMAP:
+ case PIO_FONTRESET:
+ case PIO_UNIMAPCLR:
/* Little k */
case KIOCTYPE:
@@ -1360,9 +1773,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case VUIDSFORMAT:
case VUIDGFORMAT:
- /* Little p (/dev/rtc etc.) */
+ /* Little p (/dev/rtc, /dev/envctrl, etc.) */
case RTCGET:
case RTCSET:
+ case I2CIOCSADR:
+ case I2CIOCGADR:
/* Little m */
case MTIOCTOP:
@@ -1455,6 +1870,25 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case CDROM_DRIVE_STATUS:
case CDROM_DISC_STATUS:
case CDROM_CHANGER_NSLOTS:
+
+ /* Big L */
+ case LOOP_SET_FD:
+ case LOOP_CLR_FD:
+
+ /* Big A */
+ case AUDIO_GETINFO:
+ case AUDIO_SETINFO:
+ case AUDIO_DRAIN:
+ case AUDIO_GETDEV:
+ case AUDIO_GETDEV_SUNOS:
+ case AUDIO_FLUSH:
+
+ /* AUTOFS */
+ case AUTOFS_IOC_READY:
+ case AUTOFS_IOC_FAIL:
+ case AUTOFS_IOC_CATATONIC:
+ case AUTOFS_IOC_PROTOVER:
+ case AUTOFS_IOC_EXPIRE:
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
index 7ae12df11..84b097d3f 100644
--- a/arch/sparc64/kernel/ioport.c
+++ b/arch/sparc64/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.13 1997/08/18 01:20:22 davem Exp $
+/* $Id: ioport.c,v 1.14 1998/05/11 06:23:36 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -20,7 +20,6 @@
/* This points to the next to use virtual memory for io mappings */
static unsigned long dvma_next_free = DVMA_VADDR;
-unsigned long sparc_iobase_vaddr = IOBASE_VADDR;
extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
@@ -33,7 +32,9 @@ extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
* Input:
* address: Physical address to map
* virtual: if non zero, specifies a fixed virtual address where
- * the mapping should take place.
+ * the mapping should take place, not supported on Ultra
+ * and this feature is scheduled to be removed as nobody
+ * uses it. -DaveM
* len: the length of the mapping
* bus_type: Optional high word of physical address.
*
@@ -44,59 +45,24 @@ extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
u32 bus_type, int rdonly)
{
- unsigned long vaddr, base_address;
unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
- unsigned long offset = (addr & (~PAGE_MASK));
-
- if (virtual) {
- vaddr = (unsigned long) virtual;
-
- len += offset;
- if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
- prom_printf("alloc_io: Mapping outside IOBASE area\n");
- prom_halt();
- }
- if(check_region ((vaddr | offset), len)) {
- prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
- prom_halt();
- }
-
- /* Tell Linux resource manager about the mapping */
- request_region ((vaddr | offset), len, name);
- } else {
- unsigned long vaddr = (unsigned long) __va(addr);
-
- if(!check_region(vaddr, len))
- request_region(vaddr, len, name);
-
- return (void *) vaddr;
- }
+ unsigned long vaddr = (unsigned long) __va(addr);
- base_address = vaddr;
- /* Do the actual mapping */
- for (; len > 0; len -= PAGE_SIZE) {
- mapioaddr(addr, vaddr, bus_type, rdonly);
- vaddr += PAGE_SIZE;
- addr += PAGE_SIZE;
- }
+ if(virtual)
+ panic("sparc_alloc_io: Fixed virtual mappings unsupported on Ultra.");
- return (void *) (base_address | offset);
+ if(!check_region(vaddr, len))
+ request_region(vaddr, len, name);
+
+ return (void *) vaddr;
}
void sparc_free_io (void *virtual, int len)
{
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
- unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
-
+ unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) +
+ len + PAGE_SIZE-1) & PAGE_MASK;
release_region(vaddr, plen);
-
- if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
- return;
-
- for (; plen != 0;) {
- plen -= PAGE_SIZE;
- unmapioaddr(vaddr + plen);
- }
}
/* Does DVMA allocations with PAGE_SIZE granularity. How this basically
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 176079643..eaa7ad7d4 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,8 +1,9 @@
-/* $Id: irq.c,v 1.52 1998/03/19 00:22:54 ecd Exp $
+/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <linux/config.h>
@@ -36,6 +37,7 @@
/* Internal flag, should not be visible elsewhere at all. */
#define SA_IMAP_MASKED 0x100
+#define SA_DMA_SYNC 0x200
#ifdef __SMP__
void distribute_irqs(void);
@@ -53,35 +55,6 @@ static int irqs_have_been_distributed = 0;
unsigned long ivector_to_mask[NUM_IVECS];
-struct ino_bucket {
- struct ino_bucket *next;
- unsigned int ino;
- unsigned int *imap;
- unsigned int *iclr;
- unsigned char *imap_refcnt;
-};
-
-#define INO_HASHSZ (NUM_HARD_IVECS >> 2)
-#define NUM_INO_STATIC 4
-static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
-static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
-static int static_ino_bucket_count = 0;
-
-static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
-{
- struct ino_bucket *ret = ino_hash[hash];
-
- for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
- ;
-
- return ret;
-}
-
-static inline struct ino_bucket *ino_lookup(unsigned int ino)
-{
- return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
-}
-
/* This is based upon code in the 32-bit Sparc kernel written mostly by
* David Redman (djhr@tadpole.co.uk).
*/
@@ -95,6 +68,24 @@ struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
+#define IBF_DMA_SYNC 0x01
+#define IBF_PCI 0x02
+#define IBF_ACTIVE 0x04
+
+#define __imap(bucket) ((bucket)->iclr + (bucket)->imap_off)
+#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
+#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
+
+static struct ino_bucket *bucket_base, *buckets, *endbuckets;
+
+__initfunc(unsigned long irq_init(unsigned long start_mem, unsigned long end_mem))
+{
+ start_mem = (start_mem + 15) & ~15;
+ bucket_base = buckets = (struct ino_bucket *)start_mem;
+ endbuckets = buckets + 2048;
+ return (unsigned long)endbuckets;
+}
+
int get_irq_list(char *buf)
{
int i, len = 0;
@@ -187,22 +178,6 @@ offset(imap_pmgmt),
#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
-/* XXX Old compatability cruft, get rid of me when all drivers have been
- * XXX converted to dcookie registry calls... -DaveM
- */
-static unsigned int *sysio_irq_to_imap(unsigned int irq)
-{
- unsigned long offset;
- struct sysio_regs *sregs;
-
- if((irq >= NUM_SYSIO_OFFSETS) ||
- ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
- return NULL;
- sregs = SBus_chain->iommu->sysio_regs;
- offset += ((unsigned long) sregs);
- return ((unsigned int *)offset);
-}
-
/* Convert Interrupt Mapping register pointer to assosciated
* Interrupt Clear register pointer, SYSIO specific version.
*/
@@ -219,10 +194,10 @@ static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
#ifdef CONFIG_PCI
/* PCI PSYCHO INO number to Sparc PIL level. */
unsigned char psycho_ino_to_pil[] = {
- 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */
- 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */
- 7, 5, 5, 2, /* PCI A slot 2 Int A, B, C, D */
- 7, 5, 5, 2, /* PCI A slot 3 Int A, B, C, D */
+ 7, 5, 4, 2, /* PCI A slot 0 Int A, B, C, D */
+ 7, 5, 4, 2, /* PCI A slot 1 Int A, B, C, D */
+ 7, 5, 4, 2, /* PCI A slot 2 Int A, B, C, D */
+ 7, 5, 4, 2, /* PCI A slot 3 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
@@ -263,21 +238,14 @@ unsigned char psycho_ino_to_pil[] = {
#endif
/* Now these are always passed a true fully specified sun4u INO. */
-void enable_irq(unsigned int ino)
+void enable_irq(unsigned int irq)
{
- struct ino_bucket *bucket;
+ struct ino_bucket *bucket = __bucket(irq);
unsigned long tid;
unsigned int *imap;
-#ifdef CONFIG_PCI
- if(PCI_IRQ_P(ino))
- ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
-#endif
- bucket = ino_lookup(ino);
- if(!bucket)
- return;
-
- imap = bucket->imap;
+ imap = __imap(bucket);
+ if (!imap) return;
/* We send it to our UPA MID, for SMP this will be different. */
__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -289,26 +257,19 @@ void enable_irq(unsigned int ino)
* However for Graphics and UPA Slave devices the full
* SYSIO_IMAP_INR field can be set by the programmer here.
*
- * Things like FFB can now be handled via the dcookie mechanism.
+ * Things like FFB can now be handled via the new IRQ mechanism.
*/
*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
}
/* This now gets passed true ino's as well. */
-void disable_irq(unsigned int ino)
+void disable_irq(unsigned int irq)
{
- struct ino_bucket *bucket;
+ struct ino_bucket *bucket = __bucket(irq);
unsigned int *imap;
-#ifdef CONFIG_PCI
- if(PCI_IRQ_P(ino))
- ino &= (PCI_IRQ_IGN | PCI_IRQ_INO);
-#endif
- bucket = ino_lookup(ino);
- if(!bucket)
- return;
-
- imap = bucket->imap;
+ imap = __imap(bucket);
+ if (!imap) return;
/* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call
@@ -318,265 +279,156 @@ void disable_irq(unsigned int ino)
*imap &= ~(SYSIO_IMAP_VALID);
}
-static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
- unsigned int **imap, unsigned int **iclr,
- void *busp, unsigned long flags,
- unsigned int irq)
+unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap)
{
- if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
- return;
-
- if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
- printk("get_irq_translations: Partial specification, this is bad.\n");
- printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
- *cpu_irq, *imap, *iclr, busp);
- panic("Bad IRQ translations...");
+ if (buckets == endbuckets)
+ panic("Out of IRQ buckets. Should not happen.\n");
+ buckets->pil = pil;
+ if (pil && (!iclr || !imap)) {
+ prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap);
+ prom_halt();
}
+ if (imap)
+ buckets->ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
+ else
+ buckets->ino = 0;
+
+ buckets->iclr = iclr;
+ buckets->flags = 0;
+ buckets->imap_off = imap - iclr;
+ return __irq(buckets++);
+}
- if(SA_BUS(flags) == SA_SBUS) {
- struct linux_sbus *sbusp = busp;
- struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
- unsigned long offset;
-
- *cpu_irq = sysio_ino_to_pil[irq];
- if(*cpu_irq == 0) {
- printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
- panic("Bad SYSIO IRQ translations...");
- }
- offset = sysio_irq_offsets[irq];
- if(offset == ((unsigned long)-1)) {
- printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
- irq, *cpu_irq);
- panic("BAD SYSIO IRQ offset...");
- }
- offset += ((unsigned long)sregs);
- *imap = ((unsigned int *)offset);
-
- /* SYSIO inconsistancy. For external SLOTS, we have to select
- * the right ICLR register based upon the lower SBUS irq level
- * bits.
- */
- if(irq >= 0x20) {
- *iclr = sysio_imap_to_iclr(*imap);
- } else {
- unsigned long iclraddr;
- int sbus_slot = (irq & 0x18)>>3;
- int sbus_level = irq & 0x7;
-
- switch(sbus_slot) {
- case 0:
- *iclr = &sregs->iclr_slot0;
- break;
- case 1:
- *iclr = &sregs->iclr_slot1;
- break;
- case 2:
- *iclr = &sregs->iclr_slot2;
- break;
- case 3:
- *iclr = &sregs->iclr_slot3;
- break;
- };
-
- iclraddr = (unsigned long) *iclr;
- iclraddr += ((sbus_level - 1) * 8);
- *iclr = (unsigned int *) iclraddr;
-
-#if 0 /* DEBUGGING */
- printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
- sbus_slot, sbus_level, *iclr);
-#endif
+unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+{
+ struct linux_sbus *sbus = (struct linux_sbus *)buscookie;
+ struct sysio_regs *sregs = sbus->iommu->sysio_regs;
+ unsigned long offset;
+ int pil;
+ unsigned int *imap, *iclr;
+ int sbus_level = 0;
- /* Also, make sure this is accounted for in ivindex
- * computations done by the caller.
- */
- *ivindex_fixup = sbus_level;
- }
- return;
+ pil = sysio_ino_to_pil[ino];
+ if(!pil) {
+ printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
+ panic("Bad SYSIO IRQ translations...");
}
-#ifdef CONFIG_PCI
- if(SA_BUS(flags) == SA_PCI) {
- struct pci_bus *pbusp = busp;
- struct linux_pbm_info *pbm = pbusp->sysdata;
- struct psycho_regs *pregs = pbm->parent->psycho_regs;
- unsigned long offset;
-
- *cpu_irq = psycho_ino_to_pil[irq & 0x3f];
- if(*cpu_irq == 0) {
- printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
- panic("Bad PSYCHO IRQ translations...");
- }
- offset = psycho_imap_offset(irq);
- if(offset == ((unsigned long)-1)) {
- printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
- irq, *cpu_irq);
- panic("Bad PSYCHO IRQ offset...");
- }
- offset += ((unsigned long)pregs);
- *imap = ((unsigned int *)offset) + 1;
- *iclr = (unsigned int *)
- (((unsigned long)pregs) + psycho_iclr_offset(irq));
- return;
+ offset = sysio_irq_offsets[ino];
+ if(offset == ((unsigned long)-1)) {
+ printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+ ino, pil);
+ panic("BAD SYSIO IRQ offset...");
}
-#endif
-#if 0 /* XXX More to do before we can use this. -DaveM */
- if(SA_BUS(flags) == SA_FHC) {
- struct fhc_bus *fbusp = busp;
- struct fhc_regs *fregs = fbusp->regs;
- unsigned long offset;
-
- *cpu_irq = fhc_ino_to_pil[irq];
- if(*cpu_irq == 0) {
- printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
- panic("Bad FHC IRQ translations...");
- }
- offset = fhc_irq_offset[*cpu_irq];
- if(offset == ((unsigned long)-1)) {
- printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
- irq, *cpu_irq);
- panic("Bad FHC IRQ offset...");
- }
- offset += ((unsigned long)pregs);
- *imap = (((unsigned int *)offset)+1);
- *iclr = fhc_imap_to_iclr(*imap);
- return;
+ offset += ((unsigned long)sregs);
+ imap = ((unsigned int *)offset);
+
+ /* SYSIO inconsistancy. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if(ino >= 0x20) {
+ iclr = sysio_imap_to_iclr(imap);
+ } else {
+ unsigned long iclraddr;
+ int sbus_slot = (ino & 0x18)>>3;
+
+ sbus_level = ino & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ iclr = &sregs->iclr_slot0;
+ break;
+ case 1:
+ iclr = &sregs->iclr_slot1;
+ break;
+ case 2:
+ iclr = &sregs->iclr_slot2;
+ break;
+ default:
+ case 3:
+ iclr = &sregs->iclr_slot3;
+ break;
+ };
+
+ iclraddr = (unsigned long) iclr;
+ iclraddr += ((sbus_level - 1) * 8);
+ iclr = (unsigned int *) iclraddr;
}
-#endif
- printk("get_irq_translations: IRQ register for unknown bus type.\n");
- printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
- SA_BUS(flags), irq);
- panic("Bad IRQ bus type...");
+ return build_irq(pil, sbus_level, iclr, imap);
}
#ifdef CONFIG_PCI
-static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup,
- unsigned int **imap, unsigned int **iclr,
- unsigned int irq)
+unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync)
{
- struct linux_psycho *psycho;
- struct psycho_regs *pregs;
- unsigned long addr, imoff;
-
- psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT);
- if (!psycho) {
- printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq);
- panic("Bad PSYCHO IRQ frobnication...");
- }
- pregs = psycho->psycho_regs;
+ struct linux_psycho *psycho = (struct linux_psycho *)buscookie;
+ struct psycho_regs *pregs = psycho->psycho_regs;
+ unsigned long addr;
+ struct ino_bucket *bucket;
+ int pil;
+ unsigned int *imap, *iclr;
+ int inofixup = 0;
+ pil = psycho_ino_to_pil[ino & PCI_IRQ_INO];
+
addr = (unsigned long) &pregs->imap_a_slot0;
- imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT;
- addr = addr + imoff;
-
- *imap = ((unsigned int *)addr) + 1;
+ addr = addr + imap_off;
+ imap = ((unsigned int *)addr) + 1;
addr = (unsigned long) pregs;
- addr += psycho_iclr_offset(irq & (PCI_IRQ_INO));
- *iclr = ((unsigned int *)addr) + 1;
+ addr += psycho_iclr_offset(ino & (PCI_IRQ_INO));
+ iclr = ((unsigned int *)addr) + 1;
- *cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)];
- if(*cpu_irq == 0) {
- printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq);
- panic("Bad PSYCHO IRQ frobnication...");
- }
+ if(!(ino & 0x20))
+ inofixup = ino & 0x03;
- /* IVINDEX fixup only needed for PCI slot irq lines. */
- if(!(irq & 0x20))
- *ivindex_fixup = irq & 0x03;
+ bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+
+ if (need_dma_sync)
+ bucket->flags |= IBF_DMA_SYNC;
+
+ bucket->flags |= IBF_PCI;
+ return __irq(bucket);
}
#endif
-/* Once added, they are never removed. */
-static struct ino_bucket *add_ino_hash(unsigned int ivindex,
- unsigned int *imap, unsigned int *iclr,
- unsigned long flags)
-{
- struct ino_bucket *new = NULL, **hashp;
- unsigned int hash = (ivindex & (INO_HASHSZ - 1));
-
- new = __ino_lookup(hash, ivindex);
- if(new)
- return new;
- if(flags & SA_STATIC_ALLOC) {
- if(static_ino_bucket_count < NUM_INO_STATIC)
- new = &static_ino_buckets[static_ino_bucket_count++];
- else
- printk("Request for ino bucket SA_STATIC_ALLOC failed "
- "using kmalloc\n");
- }
- if(new == NULL)
- new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
- if(new) {
- hashp = &ino_hash[hash];
- new->imap = imap;
- new->iclr = iclr;
- new->ino = ivindex;
- new->next = *hashp;
- *hashp = new;
- }
- return new;
-}
-
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action, *tmp = NULL;
- struct devid_cookie *dcookie = NULL;
- struct ino_bucket *bucket = NULL;
+ struct ino_bucket *bucket = __bucket(irq);
unsigned long flags;
- unsigned int *imap, *iclr;
- void *bus_id = NULL;
- int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0;
+ int pending = 0;
+
+ if (irq < 0x400000 || (irq & 0x80000000)) {
+ prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
+ prom_halt();
+ }
if(!handler)
return -EINVAL;
- imap = iclr = NULL;
-
- ivindex_fixup = 0;
-
- if (irq == 0) {
- cpu_irq = irq;
- irqflags &= ~(SA_IMAP_MASKED);
- } else {
+ if (!bucket->pil)
+ irqflags &= ~SA_IMAP_MASKED;
+ else {
irqflags |= SA_IMAP_MASKED;
-#ifdef CONFIG_PCI
- if(PCI_IRQ_P(irq)) {
- pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
- } else
-#endif
- if(irqflags & SA_DCOOKIE) {
- if(!dev_id) {
- printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
- panic("Bogus irq registry.");
- }
- dcookie = dev_id;
- dev_id = dcookie->real_dev_id;
- cpu_irq = dcookie->pil;
- imap = dcookie->imap;
- iclr = dcookie->iclr;
- bus_id = dcookie->bus_cookie;
- get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
- &iclr, bus_id, irqflags, irq);
- } else {
- /* XXX NOTE: This code is maintained for compatability until I can
- * XXX verify that all drivers sparc64 will use are updated
- * XXX to use the new IRQ registry dcookie interface. -DaveM
+ if (bucket->flags & IBF_PCI) {
+ /*
+ * PCI IRQs should never use SA_INTERRUPT.
*/
- cpu_irq = sysio_ino_to_pil[irq];
- imap = sysio_irq_to_imap(irq);
- if(!imap) {
- printk("request_irq: BAD, null imap for old style "
- "irq registry IRQ[%x].\n", irq);
- panic("Bad IRQ registery...");
- }
- iclr = sysio_imap_to_iclr(imap);
+ irqflags &= ~(SA_INTERRUPT);
+
+ /*
+ * Check wether we _should_ use DMA Write Sync
+ * (for devices behind bridges behind APB).
+ *
+ * XXX: Not implemented, yet.
+ */
+ if (bucket->flags & IBF_DMA_SYNC)
+ irqflags |= SA_DMA_SYNC;
}
- ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
- ivindex += ivindex_fixup;
}
- action = *(cpu_irq + irq_action);
+ action = *(bucket->pil + irq_action);
if(action) {
if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
for (tmp = action; tmp->next; tmp = tmp->next)
@@ -586,7 +438,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
printk("Attempt to mix fast and slow interrupts on IRQ%d "
- "denied\n", irq);
+ "denied\n", bucket->pil);
return -EBUSY;
}
action = NULL; /* Or else! */
@@ -614,22 +466,11 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
}
if (irqflags & SA_IMAP_MASKED) {
- bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
- if(!bucket) {
- kfree(action);
- restore_flags(flags);
- return -ENOMEM;
- }
-
- pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
- ivector_to_mask[ivindex] = (1 << cpu_irq);
+ pending = ((ivector_to_mask[bucket->ino] & 0x80000000) != 0);
+ ivector_to_mask[bucket->ino] = (1 << bucket->pil);
if(pending)
- ivector_to_mask[ivindex] |= 0x80000000;
-
- if(dcookie) {
- dcookie->ret_ino = ivindex;
- dcookie->ret_pil = cpu_irq;
- }
+ ivector_to_mask[bucket->ino] |= 0x80000000;
+ bucket->flags |= IBF_ACTIVE;
}
action->mask = (unsigned long) bucket;
@@ -642,13 +483,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
if(tmp)
tmp->next = action;
else
- *(cpu_irq + irq_action) = action;
+ *(bucket->pil + irq_action) = action;
- enable_irq(ivindex);
+ enable_irq(irq);
/* We ate the IVEC already, this makes sure it does not get lost. */
if(pending)
- set_softint(1 << cpu_irq);
+ set_softint(1 << bucket->pil);
restore_flags(flags);
#ifdef __SMP__
@@ -663,23 +504,16 @@ void free_irq(unsigned int irq, void *dev_id)
struct irqaction *action;
struct irqaction *tmp = NULL;
unsigned long flags;
- unsigned int *imap = NULL;
- unsigned int cpu_irq;
- int ivindex = -1;
+ struct ino_bucket *bucket = __bucket(irq), *bp;
- if(irq == 0) {
- cpu_irq = irq;
- } else {
-#ifdef CONFIG_PCI
- if(PCI_IRQ_P(irq))
- cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO];
- else
-#endif
- cpu_irq = sysio_ino_to_pil[irq];
+ if (irq < 0x400000 || (irq & 0x80000000)) {
+ prom_printf("free_irq with old style irq %08x\n", irq);
+ prom_halt();
}
- action = *(cpu_irq + irq_action);
+
+ action = *(bucket->pil + irq_action);
if(!action->handler) {
- printk("Freeing free IRQ %d\n", irq);
+ printk("Freeing free IRQ %d\n", bucket->pil);
return;
}
if(dev_id) {
@@ -689,17 +523,17 @@ void free_irq(unsigned int irq, void *dev_id)
tmp = action;
}
if(!action) {
- printk("Trying to free free shared IRQ %d\n", irq);
+ printk("Trying to free free shared IRQ %d\n", bucket->pil);
return;
}
} else if(action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
+ printk("Trying to free shared IRQ %d with NULL device ID\n", bucket->pil);
return;
}
if(action->flags & SA_STATIC_ALLOC) {
printk("Attempt to free statically allocated IRQ %d (%s)\n",
- irq, action->name);
+ bucket->pil, action->name);
return;
}
@@ -707,43 +541,35 @@ void free_irq(unsigned int irq, void *dev_id)
if(action && tmp)
tmp->next = action->next;
else
- *(cpu_irq + irq_action) = action->next;
+ *(bucket->pil + irq_action) = action->next;
if(action->flags & SA_IMAP_MASKED) {
- struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+ unsigned int *imap = __imap(bucket);
- imap = bucket->imap;
- if(imap != NULL) {
- ivindex = bucket->ino;
- ivector_to_mask[ivindex] = 0;
- }
- else
- printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
- }
-
- kfree(action);
+ /*
+ * Only free when no other shared irq uses this bucket.
+ */
+ tmp = *(bucket->pil + irq_action);
+ for( ; tmp; tmp = tmp->next)
+ if ((struct ino_bucket *)tmp->mask == bucket)
+ goto out;
- if(ivindex != -1) {
- struct ino_bucket *bp;
- int i, count = 0;
+ ivector_to_mask[bucket->ino] = 0;
- /* The trick is that we can't turn the thing off when there
- * are potentially other sub-irq level references.
+ bucket->flags &= ~IBF_ACTIVE;
+ for (bp = bucket_base; bp < endbuckets; bp++)
+ if (__imap(bp) == imap && (bp->flags & IBF_ACTIVE))
+ break;
+ /*
+ * Only disable when no other sub-irq levels of
+ * the same imap are active.
*/
- if(imap != NULL) {
- for(i = 0; i < INO_HASHSZ; i++) {
- bp = ino_hash[i];
- while(bp) {
- if(bp->imap == imap)
- count++;
- bp = bp->next;
- }
- }
- }
- if(count < 2)
- disable_irq(ivindex);
+ if (bp == endbuckets)
+ disable_irq(irq);
}
+out:
+ kfree(action);
restore_flags(flags);
}
@@ -979,7 +805,7 @@ void handler_irq(int irq, struct pt_regs *regs)
if(!(ivector_to_mask[bucket->ino] & 0x80000000))
continue;
}
- act->handler(irq, act->dev_id, regs);
+ act->handler(__irq(bucket), act->dev_id, regs);
} while((act = act->next) != NULL);
act = action;
do {
@@ -1044,61 +870,23 @@ int request_fast_irq(unsigned int irq,
unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action;
- struct devid_cookie *dcookie = NULL;
- struct ino_bucket *bucket = NULL;
+ struct ino_bucket *bucket = __bucket(irq);
unsigned long flags;
- unsigned int *imap, *iclr;
- void *bus_id = NULL;
- int ivindex = -1, ivindex_fixup, cpu_irq = -1;
+ if (irq < 0x400000 || (irq & 0x80000000)) {
+ prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
+ prom_halt();
+ }
+
if(!handler)
return -EINVAL;
- imap = iclr = NULL;
- ivindex_fixup = 0;
-
- if ((irq == 0) || (irq == 14)) {
+ if ((bucket->pil == 0) || (bucket->pil == 14)) {
printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
return -EBUSY;
}
-#ifdef CONFIG_PCI
- if(PCI_IRQ_P(irq)) {
- pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
- } else
-#endif
- if(irqflags & SA_DCOOKIE) {
- if(!dev_id) {
- printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n");
- panic("Bogus irq registry.");
- }
- dcookie = dev_id;
- dev_id = dcookie->real_dev_id;
- cpu_irq = dcookie->pil;
- imap = dcookie->imap;
- iclr = dcookie->iclr;
- bus_id = dcookie->bus_cookie;
- get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
- &iclr, bus_id, irqflags, irq);
- } else {
- /* XXX NOTE: This code is maintained for compatability until I can
- * XXX verify that all drivers sparc64 will use are updated
- * XXX to use the new IRQ registry dcookie interface. -DaveM
- */
- cpu_irq = sysio_ino_to_pil[irq];
- imap = sysio_irq_to_imap(irq);
- if(!imap) {
- printk("request_irq: BAD, null imap for old style "
- "irq registry IRQ[%x].\n", irq);
- panic("Bad IRQ registery...");
- }
- iclr = sysio_imap_to_iclr(imap);
- }
-
- ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
- ivindex += ivindex_fixup;
-
- action = *(cpu_irq + irq_action);
+ action = *(bucket->pil + irq_action);
if(action) {
if(action->flags & SA_SHIRQ)
panic("Trying to register fast irq when already shared.\n");
@@ -1113,7 +901,7 @@ int request_fast_irq(unsigned int irq,
action = &static_irqaction[static_irq_count++];
else
printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
- "using kmalloc\n", irq, name);
+ "using kmalloc\n", bucket->pil, name);
}
if(action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -1122,21 +910,9 @@ int request_fast_irq(unsigned int irq,
restore_flags(flags);
return -ENOMEM;
}
- install_fast_irq(cpu_irq, handler);
-
- bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
- if(!bucket) {
- kfree(action);
- restore_flags(flags);
- return -ENOMEM;
- }
+ install_fast_irq(bucket->pil, handler);
- ivector_to_mask[ivindex] = (1 << cpu_irq);
-
- if(dcookie) {
- dcookie->ret_ino = ivindex;
- dcookie->ret_pil = cpu_irq;
- }
+ ivector_to_mask[bucket->ino] = (1 << bucket->pil);
action->mask = (unsigned long) bucket;
action->handler = handler;
@@ -1145,8 +921,8 @@ int request_fast_irq(unsigned int irq,
action->name = name;
action->next = NULL;
- *(cpu_irq + irq_action) = action;
- enable_irq(ivindex);
+ *(bucket->pil + irq_action) = action;
+ enable_irq(irq);
restore_flags(flags);
#ifdef __SMP__
@@ -1174,15 +950,21 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
unsigned long *clock)
{
unsigned long flags;
- unsigned long timer_tick_offset;
+ extern unsigned long timer_tick_offset;
int node, err;
+#ifdef __SMP__
+ extern void smp_tick_init(void);
+#endif
node = linux_cpus[0].prom_node;
*clock = prom_getint(node, "clock-frequency");
timer_tick_offset = *clock / HZ;
+#ifdef __SMP__
+ smp_tick_init();
+#endif
/* Register IRQ handler. */
- err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
+ err = request_irq(build_irq(0, 0, NULL, NULL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
"timer", NULL);
if(err) {
@@ -1236,7 +1018,7 @@ void distribute_irqs(void)
while(p) {
if(p->flags & SA_IMAP_MASKED) {
struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
- unsigned int *imap = bucket->imap;
+ unsigned int *imap = __imap(bucket);
unsigned int val;
unsigned long tid = __cpu_logical_map[cpu] << 9;
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S
new file mode 100644
index 000000000..34a542ac5
--- /dev/null
+++ b/arch/sparc64/kernel/itlb_base.S
@@ -0,0 +1,69 @@
+/* $Id: itlb_base.S,v 1.5 1998/06/15 16:59:32 jj Exp $
+ * itlb_base.S: Front end to ITLB miss replacement strategy.
+ * This is included directly into the trap table.
+ *
+ * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define TAG_CONTEXT_BITS 0x3ff
+#define VPTE_SHIFT (PAGE_SHIFT - 3)
+
+/* Ways we can get here:
+ *
+ * 1) Nucleus instruction misses from module code.
+ * 2) All user instruction misses.
+ *
+ * All real page faults merge their code paths to the
+ * sparc64_realfault_* labels below.
+ */
+
+ .globl sparc64_vpte_patchme
+
+/* ITLB ** ICACHE line 1: Quick user TLB misses */
+ ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS
+ srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
+ ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE
+1: brgez,pn %g5, 3f ! Not valid, branch out
+ and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits
+2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB
+ retry ! Trap return
+3: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
+
+/* ITLB ** ICACHE line 2: Quick user ref updates */
+ bne,pn %xcc, 4f ! Nope, real missing page
+ sllx %g1, 60, %g4 ! Sliiickkk...
+ or %g5, _PAGE_ACCESSED, %g5 ! Mark as touched
+ or %g5, %g4, %g5 ! Allow user to see it
+ ba,pt %xcc, 2b ! Branch to load TLB
+ stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table
+4: rdpr %pstate, %g4 ! Move into alternate globals
+ wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate
+
+/* ITLB ** ICACHE line 3: Real faults */
+ rdpr %tpc, %g5 ! And load faulting VA
+sparc64_realfault_common: ! Called by TL0 dtlb_miss too
+ sethi %hi(1f), %g7 ! Save state
+ ba,pt %xcc, etrap ! ...
+1: or %g7, %lo(1b), %g7 ! ...
+ clr %o2 ! It was read
+sparc64_realfault_continue: ! Called by dtlb_prot handler
+ srlx %l5, PAGE_SHIFT, %o1 ! Page align faulting VA
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
+ call do_sparc64_fault ! Call fault handler
+
+/* ITLB ** ICACHE line 4: Call fault processing code */
+ sllx %o1, PAGE_SHIFT, %o1 ! Finish page alignment
+ ba,a,pt %xcc, rtrap_clr_l6 ! Restore cpu state
+winfix_trampoline:
+ rdpr %tpc, %g3 ! Prepare winfixup TNPC
+ or %g3, 0x7c, %g3 ! Compute offset to branch
+ wrpr %g3, %tnpc ! Write it into TNPC
+ done ! Do it to it
+sparc64_vpte_nucleus:
+ ba,pt %xcc, sparc64_vpte_continue ! Part of dtlb_backend
+sparc64_vpte_patchme:
+ sethi %hi(0), %g5 ! This has to be patched
+
+#undef TAG_CONTEXT_BITS
+#undef VPTE_SHIFT
diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S
deleted file mode 100644
index 94e3f44f6..000000000
--- a/arch/sparc64/kernel/itlb_miss.S
+++ /dev/null
@@ -1,49 +0,0 @@
-/* $Id: itlb_miss.S,v 1.12 1998/01/14 17:14:47 jj Exp $
- * itlb_miss.S: Instruction TLB miss code, this is included directly
- * into the trap table.
- *
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-/* Gratuitous comment. */
-
- /* ICACHE line 1 */
- /*0x00*/ ldxa [%g0] ASI_IMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
- /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits
- /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
- /*0x10*/ and %g1, 0xffe, %g4 ! Mask PMD offset
- /*0x14*/ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset
- /*0x18*/ be,pn %xcc, 3f ! Context 0 == kernel
- /*0x1c*/ add %g4, %g4, %g4 ! Position PMD offset
-
- /* ICACHE line 2 */
- /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD
- /*0x24*/ srlx %g1, 1, %g1 ! PTE offset
- /*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
- /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
- /*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set?
- /*0x34*/ nop ! delay
- /*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
- /*0x3c*/ retry ! Trap return
-
-3: /* ICACHE line 3 */
- /*0x40*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
- /*0x44*/ srlx %g1, 1, %g1 ! PTE offset
- /*0x48*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
- /*0x4c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
- /*0x50*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set?
- /*0x54*/ nop ! delay
- /*0x58*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
- /*0x5c*/ retry ! Trap return
-
- /* ICACHE line 4 */
- /*0x60*/ nop
- /*0x64*/ nop
- /*0x68*/ nop
- /*0x6c*/ nop
- /*0x70*/ nop
- /*0x74*/ nop
- /*0x78*/ nop
- /*0x7c*/ nop
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index c0058afd9..373d122c3 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,9 +1,9 @@
-/* $Id: process.c,v 1.52 1998/03/29 12:57:53 ecd Exp $
+/* $Id: process.c,v 1.70 1998/08/04 20:49:15 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/*
@@ -52,8 +52,8 @@ asmlinkage int sys_idle(void)
return -EPERM;
/* endless idle loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
+ current->priority = 0;
+ current->counter = 0;
for (;;) {
check_pgt_cache();
run_task_queue(&tq_scheduler);
@@ -69,17 +69,13 @@ asmlinkage int sys_idle(void)
*/
asmlinkage int cpu_idle(void)
{
- current->priority = -100;
+ current->priority = 0;
while(1) {
check_pgt_cache();
- if(tq_scheduler) {
- lock_kernel();
- run_task_queue(&tq_scheduler);
- unlock_kernel();
- }
+ run_task_queue(&tq_scheduler);
barrier();
- current->counter = -100;
- if(need_resched)
+ current->counter = 0;
+ if(current->need_resched)
schedule();
barrier();
}
@@ -99,18 +95,18 @@ asmlinkage int sys_idle(void)
extern char reboot_command [];
#ifdef CONFIG_SUN_CONSOLE
-extern void console_restore_palette (void);
+extern void (*prom_palette)(int);
extern int serial_console;
#endif
void machine_halt(void)
{
sti();
- udelay(8000);
+ mdelay(8);
cli();
#ifdef CONFIG_SUN_CONSOLE
- if (!serial_console)
- console_restore_palette ();
+ if (!serial_console && prom_palette)
+ prom_palette (1);
#endif
prom_halt();
panic("Halt failed!");
@@ -121,14 +117,14 @@ void machine_restart(char * cmd)
char *p;
sti();
- udelay(8000);
+ mdelay(8);
cli();
p = strchr (reboot_command, '\n');
if (p) *p = 0;
#ifdef CONFIG_SUN_CONSOLE
- if (!serial_console)
- console_restore_palette ();
+ if (!serial_console && prom_palette)
+ prom_palette (1);
#endif
if (cmd)
prom_reboot(cmd);
@@ -272,7 +268,7 @@ void __show_regs(struct pt_regs * regs)
smp_processor_id(), local_irq_count,
atomic_read(&global_irq_count));
#endif
- printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
+ printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
regs->tpc, regs->tnpc, regs->y);
printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
@@ -295,22 +291,22 @@ void __show_regs(struct pt_regs * regs)
#ifdef VERBOSE_SHOWREGS
static void idump_from_user (unsigned int *pc)
{
- int i;
- int code;
-
- if((((unsigned long) pc) & 3))
- return;
-
- pc -= 3;
- for(i = -3; i < 6; i++) {
- get_user(code, pc);
- printk("%c%08x%c",i?' ':'<',code,i?' ':'>');
- pc++;
- }
- printk("\n");
+ int i;
+ int code;
+
+ if((((unsigned long) pc) & 3))
+ return;
+
+ pc -= 3;
+ for(i = -3; i < 6; i++) {
+ get_user(code, pc);
+ printk("%c%08x%c",i?' ':'<',code,i?' ':'>');
+ pc++;
+ }
+ printk("\n");
}
#endif
-
+
void show_regs(struct pt_regs *regs)
{
#ifdef VERBOSE_SHOWREGS
@@ -339,7 +335,7 @@ void show_regs(struct pt_regs *regs)
void show_regs32(struct pt_regs32 *regs)
{
- printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
+ printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
regs->pc, regs->npc, regs->y);
printk("g0: %08x g1: %08x g2: %08x g3: %08x\n",
regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
@@ -366,7 +362,6 @@ void show_thread(struct thread_struct *tss)
printk("sig_address: 0x%016lx\n", tss->sig_address);
printk("sig_desc: 0x%016lx\n", tss->sig_desc);
printk("ksp: 0x%016lx\n", tss->ksp);
- printk("kpc: 0x%08x\n", tss->kpc);
if (tss->w_saved) {
for (i = 0; i < NSWINS; i++) {
@@ -378,10 +373,6 @@ void show_thread(struct thread_struct *tss)
printk("w_saved: 0x%04x\n", tss->w_saved);
}
- printk("sstk_info.stack: 0x%016lx\n",
- (unsigned long)tss->sstk_info.the_stack);
- printk("sstk_info.status: 0x%016lx\n",
- (unsigned long)tss->sstk_info.cur_status);
printk("flags: 0x%08x\n", tss->flags);
printk("current_ds: 0x%016lx\n", tss->current_ds.seg);
}
@@ -400,13 +391,10 @@ void exit_thread(void)
void flush_thread(void)
{
current->tss.w_saved = 0;
- current->tss.sstk_info.cur_status = 0;
- current->tss.sstk_info.the_stack = 0;
/* No new signal delivery by default. */
current->tss.new_signal = 0;
- current->tss.flags &= ~(SPARC_FLAG_USEDFPU | SPARC_FLAG_USEDFPUL |
- SPARC_FLAG_USEDFPUU);
+ current->tss.fpsaved[0] = 0;
/* Now, this task is no longer a kernel thread. */
current->tss.current_ds = USER_DS;
@@ -422,7 +410,9 @@ void flush_thread(void)
get_mmu_context(current);
spin_unlock(&scheduler_lock);
}
- current->tss.ctx = current->mm->context & 0x1fff;
+ if (current->tss.flags & SPARC_FLAG_32BIT)
+ __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r"(TSB_REG), "i"(ASI_DMMU));
+ current->tss.ctx = current->mm->context & 0x3ff;
spitfire_set_secondary_context (current->tss.ctx);
__asm__ __volatile__("flush %g6");
}
@@ -438,6 +428,13 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
} else
__get_user(fp, &(((struct reg_window32 *)psp)->ins[6]));
+
+ /* Now 8-byte align the stack as this is mandatory in the
+ * Sparc ABI due to how register windows work. This hides
+ * the restriction from thread libraries etc. -DaveM
+ */
+ csp &= ~7UL;
+
distance = fp - psp;
rval = (csp - distance);
if(copy_in_user(rval, psp, distance))
@@ -537,38 +534,21 @@ barf:
* allocate the task_struct and kernel stack in
* do_fork().
*/
-#ifdef __SMP__
-extern void ret_from_smpfork(void);
-#else
-extern void ret_from_syscall(void);
-#endif
-
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
{
- unsigned long stack_offset;
char *child_trap_frame;
- int tframe_size;
/* Calculate offset to stack_frame & pt_regs */
- stack_offset = (((PAGE_SIZE << 1) -
- ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) &
- ~(64 - 1)) - (TRACEREG_SZ+REGWIN_SZ);
- tframe_size = (TRACEREG_SZ + REGWIN_SZ) +
- (sizeof(unsigned int) * 64) + (2 * sizeof(unsigned long));
- child_trap_frame = ((char *)p) + stack_offset;
- memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
+ child_trap_frame = ((char *)p) + ((PAGE_SIZE << 1) - (TRACEREG_SZ+REGWIN_SZ));
+ memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
-#ifdef __SMP__
- p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_smpfork)) - 0x8;
-#else
- p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_syscall)) - 0x8;
-#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
+ p->tss.fpsaved[0] = 0;
if(regs->tstate & TSTATE_PRIV) {
p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
- p->tss.flags |= SPARC_FLAG_KTHREAD;
+ p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
p->tss.current_ds = KERNEL_DS;
p->tss.ctx = 0;
__asm__ __volatile__("flushw");
@@ -578,13 +558,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
if(current->tss.flags & SPARC_FLAG_32BIT) {
- sp &= 0x00000000ffffffff;
- regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+ sp &= 0x00000000ffffffffUL;
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
}
p->tss.kregs->u_regs[UREG_FP] = sp;
- p->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ p->tss.flags = (p->tss.flags & ~SPARC_FLAG_KTHREAD) |
+ SPARC_FLAG_NEWCHILD;
p->tss.current_ds = USER_DS;
- p->tss.ctx = (p->mm->context & 0x1fff);
+ p->tss.ctx = (p->mm->context & 0x3ff);
if (sp != regs->u_regs[UREG_FP]) {
unsigned long csp;
@@ -667,7 +648,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
putname(filename);
if(!error) {
fprs_write(0);
- regs->fprs = 0;
+ current->tss.xfsr[0] = 0;
+ current->tss.fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
index bec1e9fef..32d9b13c1 100644
--- a/arch/sparc64/kernel/psycho.c
+++ b/arch/sparc64/kernel/psycho.c
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.50 1998/04/10 12:29:47 ecd Exp $
+/* $Id: psycho.c,v 1.63 1998/08/02 05:55:42 ecd Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -9,14 +9,19 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
#include <asm/ebus.h>
#include <asm/sbus.h> /* for sanity check... */
+#include <asm/irq.h>
+#include <asm/io.h>
#undef PROM_DEBUG
#undef FIXUP_REGS_DEBUG
#undef FIXUP_IRQ_DEBUG
#undef FIXUP_VMA_DEBUG
+#undef PCI_COOKIE_DEBUG
#ifdef PROM_DEBUG
#define dprintf prom_printf
@@ -24,8 +29,13 @@
#define dprintf printk
#endif
+
unsigned long pci_dvma_offset = 0x00000000UL;
-unsigned long pci_dvma_mask = 0xffffffffUL;
+unsigned long pci_dvma_mask = 0xffffffffUL;
+
+unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
+unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+
#ifndef CONFIG_PCI
@@ -94,19 +104,22 @@ static int pbm_write_config_dword(struct linux_pbm_info *pbm,
*/
static int pci_probe_enable = 0;
-static inline unsigned long long_align(unsigned long addr)
+static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr)
{
- return ((addr + (sizeof(unsigned long) - 1)) &
- ~(sizeof(unsigned long) - 1));
+ unsigned long dvma_addr = pci_dvma_offset + daddr;
+ unsigned long vaddr = (unsigned long)__va(paddr);
+
+ pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
+ pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
}
-__initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
- int tsbsize,
- unsigned long memory_start))
+__initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsize))
{
- unsigned long tsbbase = PAGE_ALIGN(memory_start);
- unsigned long control, i;
+ struct linux_mlist_p1275 *mlist;
+ unsigned long tsbbase;
+ unsigned long control, i, n;
unsigned long *iopte;
+ unsigned long order;
/*
* Invalidate TLB Entries.
@@ -120,15 +133,42 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
control &= ~(IOMMU_CTRL_DENAB);
psycho->psycho_regs->iommu_control = control;
- memory_start = (tsbbase + ((tsbsize * 1024) * 8));
+ for(order = 0;; order++) {
+ if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
+ break;
+ }
+ tsbbase = __get_free_pages(GFP_DMA, order);
iopte = (unsigned long *)tsbbase;
- for(i = 0; i < (tsbsize * 1024); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K |
- IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= (i << 16);
- iopte++;
+ memset(pci_dvma_v2p_hash, 0, sizeof(pci_dvma_v2p_hash));
+ memset(pci_dvma_p2v_hash, 0, sizeof(pci_dvma_p2v_hash));
+
+ n = 0;
+ mlist = *prom_meminfo()->p1275_totphys;
+ while (mlist) {
+ unsigned long paddr = mlist->start_adr;
+
+ for (i = 0; i < (mlist->num_bytes >> 16); i++) {
+
+ *iopte = (IOPTE_VALID | IOPTE_64K |
+ IOPTE_CACHE | IOPTE_WRITE);
+ *iopte |= paddr;
+
+ if (!(n & 0xff))
+ set_dvma_hash(paddr, (n << 16));
+
+ if (++n > (tsbsize * 1024))
+ goto out;
+
+ paddr += (1 << 16);
+ iopte++;
+ }
+
+ mlist = mlist->theres_more;
}
+out:
+ if (mlist)
+ printk("WARNING: not all physical memory mapped in IOMMU\n");
psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
@@ -137,15 +177,15 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
switch(tsbsize) {
case 8:
- pci_dvma_mask = 0x1fffffffUL;
+ pci_dvma_mask = 0x1fffffffUL;
control |= IOMMU_TSBSZ_8K;
break;
case 16:
- pci_dvma_mask = 0x3fffffffUL;
+ pci_dvma_mask = 0x3fffffffUL;
control |= IOMMU_TSBSZ_16K;
break;
case 32:
- pci_dvma_mask = 0x7fffffffUL;
+ pci_dvma_mask = 0x7fffffffUL;
control |= IOMMU_TSBSZ_32K;
break;
default:
@@ -154,8 +194,6 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
break;
}
psycho->psycho_regs->iommu_control = control;
-
- return memory_start;
}
extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
@@ -164,7 +202,7 @@ extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
/*
* Poor man's PCI...
*/
-__initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
+__initfunc(void sabre_init(int pnode))
{
struct linux_prom64_registers pr_regs[2];
struct linux_psycho *sabre;
@@ -175,8 +213,7 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
u32 portid;
int bus;
- sabre = (struct linux_psycho *)memory_start;
- memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+ sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
portid = prom_getintdefault(pnode, "upa-portid", 0xff);
@@ -262,8 +299,8 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
prom_halt();
}
- memory_start = psycho_iommu_init(sabre, tsbsize, memory_start);
pci_dvma_offset = vdma[0];
+ psycho_iommu_init(sabre, tsbsize);
printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
#ifdef PROM_DEBUG
@@ -338,11 +375,15 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
if (!node)
break;
}
+}
- return memory_start;
+static __inline__ int
+apb_present(struct linux_psycho *psycho)
+{
+ return psycho->pci_bus ? 1 : 0;
}
-__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+__initfunc(void pcibios_init(void))
{
struct linux_prom64_registers pr_regs[3];
struct linux_psycho *psycho;
@@ -355,7 +396,6 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
dprintf("PCI: Probing for controllers.\n");
#endif
- memory_start = long_align(memory_start);
node = prom_getchild(prom_root_node);
while((node = prom_searchsiblings(node, "pci")) != 0) {
struct linux_psycho *search;
@@ -365,11 +405,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
- memory_start = sabre_init(node, memory_start);
+ sabre_init(node);
goto next_pci;
}
- psycho = (struct linux_psycho *)memory_start;
+ psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
portid = prom_getintdefault(node, "upa-portid", 0xff);
for(search = psycho_root; search; search = search->next) {
@@ -385,9 +425,6 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
}
}
- memory_start = long_align(memory_start +
- sizeof(struct linux_psycho));
-
memset(psycho, 0, sizeof(*psycho));
psycho->next = psycho_root;
@@ -452,8 +489,8 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
psycho->pci_config_space);
#endif
- memory_start = psycho_iommu_init(psycho, 32, memory_start);
pci_dvma_offset = 0x80000000UL;
+ psycho_iommu_init(psycho, 32);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
@@ -504,14 +541,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long
prom_halt();
}
- psycho_index_map = (struct linux_psycho **)long_align(memory_start);
- memory_start = long_align(memory_start + linux_num_psycho
- * sizeof(struct linux_psycho *));
+ psycho_index_map = kmalloc(sizeof(struct linux_psycho *) * linux_num_psycho,
+ GFP_ATOMIC);
for (psycho = psycho_root; psycho; psycho = psycho->next)
psycho_index_map[psycho->index] = psycho;
-
- return memory_start;
}
int pcibios_present(void)
@@ -577,40 +611,14 @@ static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new,
}
}
-static unsigned long *pci_alloc_arena = NULL;
-
-static inline void pci_init_alloc_init(unsigned long *mstart)
-{
- pci_alloc_arena = mstart;
-}
-
-static inline void pci_init_alloc_fini(void)
-{
- pci_alloc_arena = NULL;
-}
-
-__initfunc(static void *pci_init_alloc(int size))
-{
- unsigned long start = long_align(*pci_alloc_arena);
- void *mp = (void *)start;
-
- if(!pci_alloc_arena) {
- prom_printf("pci_init_alloc: pci_vma arena not init'd\n");
- prom_halt();
- }
- start += size;
- *pci_alloc_arena = start;
- return mp;
-}
-
static inline struct pci_vma *pci_vma_alloc(void)
{
- return pci_init_alloc(sizeof(struct pci_vma));
+ return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC);
}
static inline struct pcidev_cookie *pci_devcookie_alloc(void)
{
- return pci_init_alloc(sizeof(struct pcidev_cookie));
+ return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
}
@@ -694,6 +702,14 @@ __initfunc(static void apb_init(struct linux_psycho *sabre))
unsigned short stmp;
unsigned int itmp;
+ for(pdev = pci_devices; pdev; pdev = pdev->next) {
+ if(pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
+ /* Increase latency timer on top level bridge. */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
+ break;
+ }
+ }
for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
@@ -732,12 +748,14 @@ __initfunc(static void apb_init(struct linux_psycho *sabre))
pci_write_config_byte(pdev, APB_PIO_TARGET_LATENCY_TIMER, 0);
pci_write_config_byte(pdev, APB_DMA_TARGET_RETRY_LIMIT, 0x80);
pci_write_config_byte(pdev, APB_DMA_TARGET_LATENCY_TIMER, 0);
+
+ /* Increase primary latency timer. */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
}
}
}
-__initfunc(static void sabre_probe(struct linux_psycho *sabre,
- unsigned long *mstart))
+__initfunc(static void sabre_probe(struct linux_psycho *sabre))
{
struct pci_bus *pbus = sabre->pci_bus;
static unsigned char busno = 0;
@@ -745,7 +763,7 @@ __initfunc(static void sabre_probe(struct linux_psycho *sabre,
pbus->number = pbus->secondary = busno;
pbus->sysdata = sabre;
- pbus->subordinate = pci_scan_bus(pbus, mstart);
+ pbus->subordinate = pci_scan_bus(pbus);
busno = pbus->subordinate + 1;
for(pbus = pbus->children; pbus; pbus = pbus->next) {
@@ -759,8 +777,7 @@ __initfunc(static void sabre_probe(struct linux_psycho *sabre,
}
-__initfunc(static void pbm_probe(struct linux_pbm_info *pbm,
- unsigned long *mstart))
+__initfunc(static void pbm_probe(struct linux_pbm_info *pbm))
{
static struct pci_bus *pchain = NULL;
struct pci_bus *pbus = &pbm->pci_bus;
@@ -777,7 +794,7 @@ __initfunc(static void pbm_probe(struct linux_pbm_info *pbm,
pbm_fixup_busno(pbm, busno);
- pbus->subordinate = pci_scan_bus(pbus, mstart);
+ pbus->subordinate = pci_scan_bus(pbus);
/*
* Set the maximum subordinate bus of this pbm.
@@ -801,22 +818,15 @@ __initfunc(static void pbm_probe(struct linux_pbm_info *pbm,
__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
struct pci_dev *pdev,
- int node))
+ int pnode))
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ int node;
int err;
- while(node) {
- int child;
-
- child = prom_getchild(node);
- if(child != 0 && child != -1) {
- int res;
+ node = prom_getchild(pnode);
+ while (node) {
- res = pdev_to_pnode_sibtraverse(pbm, pdev, child);
- if(res != 0 && res != -1)
- return res;
- }
err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
if(err != 0 && err != -1) {
u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
@@ -830,32 +840,45 @@ __initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
return 0;
}
-__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev))
+__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev, int pnode))
{
struct pcidev_cookie *pcp;
- int node = prom_getchild(pbm->prom_node);
+ int node;
- node = pdev_to_pnode_sibtraverse(pbm, pdev, node);
+ node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode);
if(node == 0)
node = -1;
pcp = pci_devcookie_alloc();
pcp->pbm = pbm;
pcp->prom_node = node;
pdev->sysdata = pcp;
+#ifdef PCI_COOKIE_DEBUG
+ dprintf("pdev_cookie_fillin: pdev [%02x.%02x]: pbm %p, node %x\n",
+ pdev->bus->number, pdev->devfn, pbm, node);
+#endif
}
__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
- struct linux_pbm_info *pbm))
+ struct linux_pbm_info *pbm,
+ int node))
{
struct pci_dev *pdev;
pbus->sysdata = pbm;
+#ifdef PCI_COOKIE_DEBUG
+ dprintf("fill_in_pbm_cookies: pbus [%02x]: pbm %p\n",
+ pbus->number, pbm);
+#endif
+
for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_cookie_fillin(pbm, pdev);
+ pdev_cookie_fillin(pbm, pdev, node);
- for(pbus = pbus->children; pbus; pbus = pbus->next)
- fill_in_pbm_cookies(pbus, pbm);
+ for(pbus = pbus->children; pbus; pbus = pbus->next) {
+ struct pcidev_cookie *pcp = pbus->self->sysdata;
+ fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
+ }
}
__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
@@ -864,9 +887,11 @@ __initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
for(pbus = pbus->children; pbus; pbus = pbus->next) {
if (pbus->number == sabre->pbm_A.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_A, pbus->self);
+ pdev_cookie_fillin(&sabre->pbm_A, pbus->self,
+ sabre->pbm_A.prom_node);
else if (pbus->number == sabre->pbm_B.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_B, pbus->self);
+ pdev_cookie_fillin(&sabre->pbm_B, pbus->self,
+ sabre->pbm_B.prom_node);
}
}
@@ -973,7 +998,7 @@ static inline void record_assignments(struct linux_pbm_info *pbm)
{
struct pci_vma *vp;
- if (pbm->parent->pci_bus) {
+ if (apb_present(pbm->parent)) {
/*
* Disallow anything that is not in our IO/MEM map on SIMBA.
*/
@@ -984,12 +1009,8 @@ static inline void record_assignments(struct linux_pbm_info *pbm)
for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
struct pcidev_cookie *pcp = pdev->sysdata;
- if (!pcp) {
- prom_printf("record_assignments: "
- "no pcidev_cookie for pdev %02x\n",
- pdev->devfn);
- prom_halt();
- }
+ if (!pcp)
+ continue;
if (pcp->pbm == pbm)
break;
}
@@ -1448,12 +1469,14 @@ __initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
}
/* Exported for EBUS probing layer. */
-__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino))
+__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ unsigned int ino))
{
- unsigned long imap_off, ign, ino;
+ unsigned long imap_off;
+ int need_dma_sync = 0;
- ign = (full_ino & PSYCHO_IMAP_IGN) >> 6;
- ino = (full_ino & PSYCHO_IMAP_INO);
+ ino &= PSYCHO_IMAP_INO;
/* Compute IMAP register offset, generic IRQ layer figures out
* the ICLR register address as this is simple given the 32-bit
@@ -1529,10 +1552,7 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned in
break;
default:
- /* We don't expect anything else. The other possible
- * values are not found in PCI device nodes, and are
- * so hardware specific that they should use DCOOKIE's
- * anyways.
+ /* We don't expect anything else.
*/
prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
prom_halt();
@@ -1540,7 +1560,11 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned in
}
imap_off -= imap_offset(imap_a_slot0);
- return pci_irq_encode(imap_off, pbm->parent->index, ign, ino);
+ if (apb_present(pbm->parent) && (pdev->bus->number != pbm->pci_first_busno)) {
+ need_dma_sync = 1;
+ }
+
+ return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync);
}
__initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
@@ -1571,6 +1595,9 @@ __initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
if(i == 0 || i == -1)
goto out;
+ /* Use low slot number bits of child as IRQ line. */
+ *interrupt = ((pdev->devfn >> 3) & 3) + 1;
+
preg = &ppreg;
}
@@ -1578,20 +1605,29 @@ __initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
mid = preg->phys_mid & pbm->pbm_intmask.phys_mid;
lo = preg->phys_lo & pbm->pbm_intmask.phys_lo;
irq = *interrupt & pbm->pbm_intmask.interrupt;
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("intmap_match: [%02x.%02x.%x] key: [%08x.%08x.%08x.%08x] ",
+ pdev->bus->number, pdev->devfn >> 3, pdev->devfn & 7,
+ hi, mid, lo, irq);
+#endif
for (i = 0; i < pbm->num_pbm_intmap; i++) {
if ((pbm->pbm_intmap[i].phys_hi == hi) &&
(pbm->pbm_intmap[i].phys_mid == mid) &&
(pbm->pbm_intmap[i].phys_lo == lo) &&
(pbm->pbm_intmap[i].interrupt == irq)) {
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("irq: [%08x]", pbm->pbm_intmap[i].cinterrupt);
+#endif
*interrupt = pbm->pbm_intmap[i].cinterrupt;
- return *interrupt;
+ return 1;
}
}
out:
- prom_printf("pbm_intmap_match: IRQ [%08x.%08x.%08x.%08x] "
- "not found in interrupt-map\n", preg->phys_hi,
- preg->phys_mid, preg->phys_lo, *interrupt);
+ prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ",
+ pdev->bus->number, pdev->devfn);
+ prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+ preg->phys_hi, preg->phys_mid, preg->phys_lo, *interrupt);
prom_halt();
}
@@ -1618,23 +1654,23 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
/* See if we find a matching interrupt-map entry. */
if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
- pdev->irq = psycho_irq_build(pbm,
+ pdev->irq = psycho_irq_build(pbm, pdev,
(pbm->parent->upa_portid << 6)
| prom_irq);
#ifdef FIXUP_IRQ_DEBUG
- dprintf("interrupt-map specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
+ dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
#endif
/* See if fully specified already (ie. for onboard devices like hme) */
} else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
- pdev->irq = psycho_irq_build(pbm, prom_irq);
+ pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
#ifdef FIXUP_IRQ_DEBUG
dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
prom_irq, pdev->irq);
#endif
/* See if onboard device interrupt (i.e. bit 5 set) */
} else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) {
- pdev->irq = psycho_irq_build(pbm,
+ pdev->irq = psycho_irq_build(pbm, pdev,
(pbm->parent->upa_portid << 6)
| prom_irq);
#ifdef FIXUP_IRQ_DEBUG
@@ -1669,7 +1705,7 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
}
slot = (slot << 2);
- pdev->irq = psycho_irq_build(pbm,
+ pdev->irq = psycho_irq_build(pbm, pdev,
(((portid << 6) & PSYCHO_IMAP_IGN)
| (bus | slot | line)));
@@ -1818,7 +1854,7 @@ __initfunc(static void psycho_final_fixup(struct linux_psycho *psycho))
fixup_addr_irq(&psycho->pbm_B);
}
-__initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end))
+__initfunc(void pcibios_fixup(void))
{
struct linux_psycho *psycho;
@@ -1838,32 +1874,32 @@ __initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long
for (psycho = psycho_root; psycho; psycho = psycho->next) {
/* Probe bus on builtin PCI. */
- if (psycho->pci_bus)
- sabre_probe(psycho, &memory_start);
+ if (apb_present(psycho))
+ sabre_probe(psycho);
else {
/* Probe busses under PBM B. */
- pbm_probe(&psycho->pbm_B, &memory_start);
+ pbm_probe(&psycho->pbm_B);
/* Probe busses under PBM A. */
- pbm_probe(&psycho->pbm_A, &memory_start);
+ pbm_probe(&psycho->pbm_A);
}
}
- pci_init_alloc_init(&memory_start);
-
/* Walk all PCI devices found. For each device, and
* PCI bridge which is not one of the PSYCHO PBM's, fill in the
* sysdata with a pointer to the PBM (for pci_bus's) or
* a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
*/
for (psycho = psycho_root; psycho; psycho = psycho->next) {
- if (psycho->pci_bus)
+ if (apb_present(psycho))
sabre_cookie_fillin(psycho);
fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
- &psycho->pbm_A);
+ &psycho->pbm_A,
+ psycho->pbm_A.prom_node);
fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
- &psycho->pbm_B);
+ &psycho->pbm_B,
+ psycho->pbm_B.prom_node);
/* See what OBP has taken care of already. */
record_assignments(&psycho->pbm_A);
@@ -1873,9 +1909,7 @@ __initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long
psycho_final_fixup(psycho);
}
- pci_init_alloc_fini();
-
- return ebus_init(memory_start, memory_end);
+ return ebus_init();
}
/* "PCI: The emerging standard..." 8-( */
@@ -2257,7 +2291,7 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_read_config_byte(pbm, bus, devfn, where, value);
return pbm_read_config_byte(pbm, bus, devfn, where, value);
}
@@ -2267,7 +2301,7 @@ int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_read_config_word(pbm, bus, devfn, where, value);
return pbm_read_config_word(pbm, bus, devfn, where, value);
}
@@ -2277,7 +2311,7 @@ int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_read_config_dword(pbm, bus, devfn, where, value);
return pbm_read_config_dword(pbm, bus, devfn, where, value);
}
@@ -2287,7 +2321,7 @@ int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_write_config_byte(pbm, bus, devfn, where, value);
return pbm_write_config_byte(pbm, bus, devfn, where, value);
}
@@ -2297,7 +2331,7 @@ int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_write_config_word(pbm, bus, devfn, where, value);
return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
}
@@ -2307,7 +2341,7 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
{
struct linux_pbm_info *pbm = bus2pbm[bus];
- if (pbm && pbm->parent && pbm->parent->pci_bus)
+ if (pbm && pbm->parent && apb_present(pbm->parent))
return sabre_write_config_dword(pbm, bus, devfn, where, value);
return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
}
@@ -2397,6 +2431,10 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
return err;
}
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
__initfunc(char *pcibios_setup(char *str))
{
return str;
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 5d3c6f46a..07ee212a3 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -19,10 +19,12 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <asm/asi.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/psrcompat.h>
+#include <asm/visasm.h>
#define MAGIC_CONSTANT 0x80000000
@@ -72,6 +74,41 @@ repeat:
return pgtable;
}
+/* We must bypass the L1-cache to avoid alias issues. -DaveM */
+static __inline__ unsigned long read_user_long(unsigned long kvaddr)
+{
+ unsigned long ret;
+
+ __asm__ __volatile__("ldxa [%1] %2, %0"
+ : "=r" (ret)
+ : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+ return ret;
+}
+
+static __inline__ unsigned int read_user_int(unsigned long kvaddr)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=r" (ret)
+ : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+ return ret;
+}
+
+static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val)
+{
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : /* no outputs */
+ : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+}
+
+static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val)
+{
+ __asm__ __volatile__("stwa %0, [%1] %2"
+ : /* no outputs */
+ : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+}
+
static inline unsigned long get_long(struct task_struct * tsk,
struct vm_area_struct * vma, unsigned long addr)
{
@@ -84,7 +121,7 @@ static inline unsigned long get_long(struct task_struct * tsk,
if (MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
- retval = *(unsigned long *) page;
+ retval = read_user_long(page);
flush_page_to_ram(page);
return retval;
}
@@ -103,14 +140,12 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm
unsigned long pgaddr;
pgaddr = page + (addr & ~PAGE_MASK);
- *(unsigned long *) (pgaddr) = data;
+ write_user_long(pgaddr, data);
__asm__ __volatile__("
membar #StoreStore
flush %0
" : : "r" (pgaddr & ~7) : "memory");
-
- flush_page_to_ram(page);
}
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
@@ -131,7 +166,7 @@ static inline unsigned int get_int(struct task_struct * tsk,
if (MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
- retval = *(unsigned int *) page;
+ retval = read_user_int(page);
flush_page_to_ram(page);
return retval;
}
@@ -150,14 +185,12 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma
unsigned long pgaddr;
pgaddr = page + (addr & ~PAGE_MASK);
- *(unsigned int *) (pgaddr) = data;
+ write_user_int(pgaddr, data);
__asm__ __volatile__("
membar #StoreStore
flush %0
" : : "r" (pgaddr & ~7) : "memory");
-
- flush_page_to_ram(page);
}
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
@@ -323,9 +356,11 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
case 0:
v = t->ksp;
break;
+#if 0
case 4:
v = t->kpc;
break;
+#endif
case 8:
v = t->kpsr;
break;
@@ -800,11 +835,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned int insn;
} fpq[16];
} *fps = (struct fps *) addr;
- unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
if (copy_to_user(&fps->regs[0], fpregs,
(32 * sizeof(unsigned int))) ||
- __put_user(((unsigned int)fpregs[32]), (&fps->fsr)) ||
+ __put_user(child->tss.xfsr[0], (&fps->fsr)) ||
__put_user(0, (&fps->fpqd)) ||
__put_user(0, (&fps->flags)) ||
__put_user(0, (&fps->extra)) ||
@@ -821,11 +856,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned int regs[64];
unsigned long fsr;
} *fps = (struct fps *) addr;
- unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
if (copy_to_user(&fps->regs[0], fpregs,
(64 * sizeof(unsigned int))) ||
- __put_user(fpregs[32], (&fps->fsr))) {
+ __put_user(child->tss.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
goto out;
}
@@ -845,7 +880,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned int insn;
} fpq[16];
} *fps = (struct fps *) addr;
- unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
unsigned fsr;
if (copy_from_user(fpregs, &fps->regs[0],
@@ -854,8 +889,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EFAULT);
goto out;
}
- fpregs[32] &= 0xffffffff00000000UL;
- fpregs[32] |= fsr;
+ child->tss.xfsr[0] &= 0xffffffff00000000UL;
+ child->tss.xfsr[0] |= fsr;
+ if (!(child->tss.fpsaved[0] & FPRS_FEF))
+ child->tss.gsr[0] = 0;
+ child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
pt_succ_return(regs, 0);
goto out;
}
@@ -865,14 +903,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned int regs[64];
unsigned long fsr;
} *fps = (struct fps *) addr;
- unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
if (copy_from_user(fpregs, &fps->regs[0],
(64 * sizeof(unsigned int))) ||
- __get_user(fpregs[32], (&fps->fsr))) {
+ __get_user(child->tss.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
goto out;
}
+ if (!(child->tss.fpsaved[0] & FPRS_FEF))
+ child->tss.gsr[0] = 0;
+ child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
pt_succ_return(regs, 0);
goto out;
}
@@ -890,7 +931,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
vma = find_extend_vma(child, src);
if (!vma) {
pt_error_return(regs, EIO);
- goto out;
+ goto flush_and_out;
}
pgtable = get_page (child, vma, src, 0);
if (src & ~PAGE_MASK) {
@@ -904,13 +945,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) {
flush_page_to_ram(page);
pt_error_return(regs, EFAULT);
- goto out;
+ goto flush_and_out;
}
flush_page_to_ram(page);
} else {
if (clear_user (dest, curlen)) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto flush_and_out;
}
}
src += curlen;
@@ -918,7 +959,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
len -= curlen;
}
pt_succ_return(regs, 0);
- goto out;
+ goto flush_and_out;
}
case PTRACE_WRITETEXT:
@@ -934,7 +975,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
vma = find_extend_vma(child, dest);
if (!vma) {
pt_error_return(regs, EIO);
- goto out;
+ goto flush_and_out;
}
pgtable = get_page (child, vma, dest, 1);
if (dest & ~PAGE_MASK) {
@@ -951,7 +992,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
flush_tlb_page(vma, dest);
pt_error_return(regs, EFAULT);
- goto out;
+ goto flush_and_out;
}
flush_page_to_ram(page);
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -962,7 +1003,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
len -= curlen;
}
pt_succ_return(regs, 0);
- goto out;
+ goto flush_and_out;
}
case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
@@ -1041,6 +1082,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EIO);
goto out;
}
+flush_and_out:
+ {
+ unsigned long va;
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32)
+ spitfire_put_dcache_tag(va, 0x0);
+ }
out:
unlock_kernel();
}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 685182473..85732960f 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,7 +1,7 @@
-/* $Id: rtrap.S,v 1.37 1997/12/11 15:14:54 jj Exp $
+/* $Id: rtrap.S,v 1.39 1998/07/26 03:02:49 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
@@ -10,13 +10,15 @@
#include <asm/ptrace.h>
#include <asm/spitfire.h>
#include <asm/head.h>
+#include <asm/visasm.h>
+
+#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ)
.text
.align 32
.globl rtrap_clr_l6, rtrap
-#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ)
-rtrap_clr_l6: ba,pt %xcc, rtrap
- clr %l6
+rtrap_clr_l6: clr %l6
+ /* Fall through */
rtrap: sethi %hi(bh_active), %l2
sethi %hi(bh_mask), %l1
ldx [%l2 + %lo(bh_active)], %l4
@@ -37,24 +39,37 @@ rtrap: sethi %hi(bh_active), %l2
be,pt %icc, to_user
andn %l7, PSTATE_IE, %l7
- ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5
+ brz,pt %l5, rt_continue
+ srl %l5, 1, %o0
+ add %g6, AOFF_task_tss + AOFF_thread_fpsaved, %l6
+ ldub [%l6 + %o0], %l2
+ sub %l5, 2, %l5
+ add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1
andcc %l2, FPRS_FEF, %g0
- be,pt %icc, rt_continue
+ be,pt %icc, 2f
and %l2, FPRS_DL, %l6
- wr %g0, FPRS_FEF, %fprs
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %g5
+ rd %fprs, %g5
+ wr %g5, FPRS_FEF, %fprs
+ ldub [%o1 + %o0], %g5
+ sll %o0, 3, %o5
+ add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
membar #StoreLoad | #LoadLoad
+ sll %o0, 8, %o2
+ add %g6, AOFF_task_fpregs, %o3
brz,pn %l6, 1f
- wr %g0, ASI_BLK_P, %asi
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
+ add %g6, AOFF_task_fpregs+0x40, %o4
+ ldda [%o3 + %o2] ASI_BLK_P, %f0
+ ldda [%o4 + %o2] ASI_BLK_P, %f16
1: andcc %l2, FPRS_DU, %g0
be,pn %icc, 1f
wr %g5, 0, %gsr
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
+ add %o2, 0x80, %o2
+ ldda [%o3 + %o2] ASI_BLK_P, %f32
+ ldda [%o4 + %o2] ASI_BLK_P, %f48
1: membar #Sync
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
+ ldx [%o1 + %o5], %fsr
+2: stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
@@ -86,11 +101,10 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
wrpr %l1, %g0, %tstate
wrpr %l2, %g0, %tpc
wrpr %o2, %g0, %tnpc
- mov PRIMARY_CONTEXT, %l7
brnz,pn %l3, kern_rtt
- mov SECONDARY_CONTEXT, %o4
+ mov PRIMARY_CONTEXT, %l7
stxa %l0, [%l7] ASI_DMMU
- stxa %l0, [%o4] ASI_DMMU
+ stxa %l0, [%l7 + %l7] ASI_DMMU
flush %o5
rdpr %wstate, %l1
@@ -106,8 +120,7 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
retry
kern_rtt: restore
retry
-to_user: sethi %hi(need_resched), %l0
- ldx [%l0 + %lo(need_resched)], %l0
+to_user: ldx [%g6 + AOFF_task_need_resched], %l0
wrpr %l7, PSTATE_IE, %pstate
orcc %g0, %l0, %g0
be,a,pt %xcc, check_signal
@@ -116,8 +129,7 @@ to_user: sethi %hi(need_resched), %l0
call schedule
nop
lduw [%g6 + AOFF_task_sigpending], %l0
-check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
- brz,a,pt %l0, check_user_wins
+check_signal: brz,a,pt %l0, check_user_wins
lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %o0
mov %l5, %o2
@@ -127,112 +139,20 @@ check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
check_user_wins:brz,pt %o2, 1f
- sethi %hi(TSTATE_PEF), %o3
+ sethi %hi(TSTATE_PEF), %l6
call fault_in_user_windows
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- sethi %hi(TSTATE_PEF), %o3
-1: andcc %l2, FPRS_FEF, %g0
- be,a,pt %icc, rt_continue
- andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2
- wr %g0, FPRS_FEF, %fprs
- wr %o3, 0, %gsr
- andcc %l2, SPARC_FLAG_USEDFPUL, %g0
- bne,pn %icc, 2f
- andcc %l2, SPARC_FLAG_USEDFPUU, %g0
- fzero %f0
- bne,pn %icc, 1f
- fzero %f2
- faddd %f0, %f2, %f4
- fmuld %f0, %f2, %f6
- faddd %f0, %f2, %f8
- fmuld %f0, %f2, %f10
- faddd %f0, %f2, %f12
- fmuld %f0, %f2, %f14
- faddd %f0, %f2, %f16
- fmuld %f0, %f2, %f18
- faddd %f0, %f2, %f20
- fmuld %f0, %f2, %f22
- faddd %f0, %f2, %f24
- fmuld %f0, %f2, %f26
- faddd %f0, %f2, %f28
- fmuld %f0, %f2, %f30
- faddd %f0, %f2, %f32
- fmuld %f0, %f2, %f34
- faddd %f0, %f2, %f36
- fmuld %f0, %f2, %f38
- faddd %f0, %f2, %f40
- fmuld %f0, %f2, %f42
- faddd %f0, %f2, %f44
- fmuld %f0, %f2, %f46
- faddd %f0, %f2, %f48
- fmuld %f0, %f2, %f50
- faddd %f0, %f2, %f52
- fmuld %f0, %f2, %f54
- faddd %f0, %f2, %f56
- fmuld %f0, %f2, %f58
- faddd %f0, %f2, %f60
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
- ba,pt %xcc, rt_continue
- wr %g0, FPRS_FEF, %fprs
-1: wr %g0, ASI_BLK_P, %asi
- membar #StoreLoad | #LoadLoad
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
- faddd %f0, %f2, %f4
- fmuld %f0, %f2, %f6
- faddd %f0, %f2, %f8
- fmuld %f0, %f2, %f10
- faddd %f0, %f2, %f12
- fmuld %f0, %f2, %f14
- faddd %f0, %f2, %f16
- fmuld %f0, %f2, %f18
- faddd %f0, %f2, %f20
- fmuld %f0, %f2, %f22
- faddd %f0, %f2, %f24
- fmuld %f0, %f2, %f26
- faddd %f0, %f2, %f28
- fmuld %f0, %f2, %f30
- membar #Sync
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
- ba,pt %xcc, rt_continue
- wr %g0, FPRS_FEF, %fprs
-2: membar #StoreLoad | #LoadLoad
- andcc %l2, SPARC_FLAG_USEDFPUU, %g0
- bne,pt %icc, 3f
- wr %g0, ASI_BLK_P, %asi
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
- fzero %f32
- fzero %f34
- faddd %f32, %f34, %f36
- fmuld %f32, %f34, %f38
- faddd %f32, %f34, %f40
- fmuld %f32, %f34, %f42
- faddd %f32, %f34, %f44
- fmuld %f32, %f34, %f46
- faddd %f32, %f34, %f48
- fmuld %f32, %f34, %f50
- faddd %f32, %f34, %f52
- fmuld %f32, %f34, %f54
- faddd %f32, %f34, %f56
- fmuld %f32, %f34, %f58
- faddd %f32, %f34, %f60
- fmuld %f32, %f34, %f62
- membar #Sync
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
- ba,pt %xcc, rt_continue
- wr %g0, FPRS_FEF, %fprs
-3: ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32
- ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
- membar #Sync
- ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
- ba,pt %xcc, rt_continue
- wr %g0, FPRS_FEF, %fprs
+1: andcc %l1, %l6, %g0
+ be,pt %xcc, rt_continue
+ stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+
+ rd %fprs, %l5
+ andcc %l5, FPRS_FEF, %g0
+ be,a,pn %icc, rt_continue
+ andn %l1, %l6, %l1
+ ba,pt %xcc, rt_continue+4
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
#undef PTREGS_OFF
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index cdc8f47de..de0124f52 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.20 1998/02/24 17:02:39 jj Exp $
+/* $Id: setup.c,v 1.30 1998/07/24 09:50:08 jj Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
#include <linux/blk.h>
#include <linux/init.h>
#include <linux/inet.h>
+#include <linux/console.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -41,13 +42,15 @@
#include <net/ipconfig.h>
#endif
+#undef PROM_DEBUG_CONSOLE
+
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
- { 0, 0, }, /* unused */
+ 0, /* unused */
0, /* orig-video-page */
0, /* orig-video-mode */
128, /* orig-video-cols */
- 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 0, 0, 0, /* unused, ega_bx, unused */
54, /* orig-video-lines */
0, /* orig-video-isVGA */
16 /* orig-video-points */
@@ -63,7 +66,7 @@ unsigned int phys_bytes_of_ram, end_of_phys_memory;
extern unsigned long sparc64_ttable_tl0;
#if CONFIG_SUN_CONSOLE
-extern void console_restore_palette(void);
+void (*prom_palette)(int);
#endif
asmlinkage void sys_sync(void); /* it's really int */
@@ -77,7 +80,8 @@ void prom_sync_me(long *args)
__asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
#ifdef CONFIG_SUN_CONSOLE
- console_restore_palette ();
+ if (prom_palette)
+ prom_palette (1);
#endif
prom_printf("PROM SYNC COMMAND...\n");
show_free_areas();
@@ -102,8 +106,7 @@ unsigned int boot_flags = 0;
#define BOOTME_KGDB 0x4
#ifdef CONFIG_SUN_CONSOLE
-extern char *console_fb_path;
-static int console_fb = 0;
+static int console_fb __initdata = 0;
#endif
static unsigned long memory_size = 0;
@@ -189,9 +192,17 @@ __initfunc(static void boot_flags_init(char *commands))
} else if (!strncmp (commands, "ttyb", 4)) {
console_fb = 3;
prom_printf ("Using /dev/ttyb as console.\n");
+#if defined(CONFIG_PROM_CONSOLE)
+ } else if (!strncmp (commands, "prom", 4)) {
+ char *p;
+
+ for (p = commands - 8; *p && *p != ' '; p++)
+ *p = ' ';
+ conswitchp = &prom_con;
+ console_fb = 1;
+#endif
} else {
console_fb = 1;
- console_fb_path = commands;
}
} else
#endif
@@ -235,21 +246,31 @@ extern int root_mountflags;
char saved_command_line[256];
char reboot_command[256];
-unsigned long phys_base;
+extern unsigned long phys_base;
static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
-#if 0
-#include <linux/console.h>
+extern struct consw sun_serial_con;
-static void prom_cons_write(struct console *con, const char *str, unsigned count)
+#ifdef PROM_DEBUG_CONSOLE
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
{
- while (count--)
- prom_printf("%c", *str++);
+ prom_printf("%s", s);
}
static struct console prom_console = {
- "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
+ "prom",
+ prom_console_write,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
};
#endif
@@ -260,7 +281,7 @@ __initfunc(void setup_arch(char **cmdline_p,
unsigned long lowest_paddr;
int total, i;
-#if 0
+#ifdef PROM_DEBUG_CONSOLE
register_console(&prom_console);
#endif
@@ -270,6 +291,12 @@ __initfunc(void setup_arch(char **cmdline_p,
printk("ARCH: SUN4U\n");
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#elif defined(CONFIG_PROM_CONSOLE)
+ conswitchp = &prom_con;
+#endif
+
boot_flags_init(*cmdline_p);
idprom_init();
@@ -396,6 +423,8 @@ __initfunc(void setup_arch(char **cmdline_p,
#else
serial_console = 0;
#endif
+ if (serial_console)
+ conswitchp = NULL;
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 94bf90398..004e0e81e 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,11 +1,11 @@
-/* $Id: signal.c,v 1.27 1997/12/15 15:04:44 jj Exp $
+/* $Id: signal.c,v 1.30 1998/07/30 11:29:34 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/config.h>
@@ -17,6 +17,7 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -25,8 +26,8 @@
#include <asm/pgtable.h>
#include <asm/fpumacro.h>
#include <asm/uctx.h>
-#include <asm/smp_lock.h>
#include <asm/siginfo.h>
+#include <asm/visasm.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -104,8 +105,10 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
__get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
if(fenab) {
- unsigned long *fpregs = (unsigned long *)(regs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
+
+ fprs_write(0);
__get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
if (fprs & FPRS_DL)
copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
@@ -113,10 +116,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
if (fprs & FPRS_DU)
copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
(sizeof(unsigned int) * 32));
- __get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
- __get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
- regs->fprs = fprs;
- regs->tstate |= TSTATE_PEF;
+ __get_user(current->tss.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
+ __get_user(current->tss.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
+ regs->tstate &= ~TSTATE_PEF;
}
return;
do_sigsegv:
@@ -131,11 +133,18 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
mc_gregset_t *grp;
mcontext_t *mcp;
unsigned long fp, i7;
- unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU);
+ unsigned char fenab;
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
goto do_sigsegv;
+
+#if 1
+ fenab = 0; /* IMO get_context is like any other system call, thus modifies FPU state -jj */
+#else
+ fenab = (current->tss.fpsaved[0] & FPRS_FEF);
+#endif
+
mcp = &ucp->uc_mcontext;
grp = &mcp->mc_gregs;
@@ -175,25 +184,18 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
__put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
if(fenab) {
- unsigned long *fpregs = (unsigned long *)(regs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
- fprs = (regs->fprs & FPRS_FEF) |
- (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ fprs = current->tss.fpsaved[0];
if (fprs & FPRS_DL)
copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
(sizeof(unsigned int) * 32));
- else
- clear_user(&(mcp->mc_fpregs.mcfpu_fregs),
- (sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
(sizeof(unsigned int) * 32));
- else
- clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16,
- (sizeof(unsigned int) * 32));
- __put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr));
- __put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
+ __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
+ __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
__put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
}
return;
@@ -224,6 +226,7 @@ struct rt_signal_frame {
sigset_t mask;
__siginfo_fpu_t * fpu_save;
unsigned int insns [2];
+ stack_t stack;
__siginfo_fpu_t fpu_state;
};
@@ -331,23 +334,26 @@ asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, struct pt_re
}
}
-static inline void
+static inline int
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
- unsigned long *fpregs = (unsigned long *)(regs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
-
- __get_user(fprs, &fpu->si_fprs);
+ int err;
+
+ err = __get_user(fprs, &fpu->si_fprs);
+ fprs_write(0);
+ regs->tstate &= ~TSTATE_PEF;
if (fprs & FPRS_DL)
- copy_from_user(fpregs, &fpu->si_float_regs[0],
+ err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
(sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
- copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
(sizeof(unsigned int) * 32));
- __get_user(fpregs[32], &fpu->si_fsr);
- __get_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = fprs;
- regs->tstate |= TSTATE_PEF;
+ err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
+ current->tss.fpsaved[0] |= fprs;
+ return err;
}
void do_sigreturn(struct pt_regs *regs)
@@ -356,6 +362,7 @@ void do_sigreturn(struct pt_regs *regs)
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t *fpu_save;
sigset_t set;
+ int err;
synchronize_user_stack ();
sf = (struct new_signal_frame *)
@@ -365,34 +372,33 @@ void do_sigreturn(struct pt_regs *regs)
if (((unsigned long) sf) & 3)
goto segv;
- if (get_user(tpc, &sf->info.si_regs.tpc) ||
- __get_user(tnpc, &sf->info.si_regs.tnpc) ||
- ((tpc | tnpc) & 3))
- goto segv;
-
- regs->tpc = tpc;
- regs->tnpc = tnpc;
+ err = get_user(tpc, &sf->info.si_regs.tpc);
+ err |= __get_user(tnpc, &sf->info.si_regs.tnpc);
+ err |= ((tpc | tnpc) & 3);
/* 2. Restore the state */
- if (__get_user(regs->y, &sf->info.si_regs.y) ||
- __get_user(tstate, &sf->info.si_regs.tstate) ||
- copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)))
- goto segv;
+ err |= __get_user(regs->y, &sf->info.si_regs.y);
+ err |= __get_user(tstate, &sf->info.si_regs.tstate);
+ err |= copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
/* User can only change condition codes in %tstate. */
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= (tstate & TSTATE_ICC);
- if (__get_user(fpu_save, &sf->fpu_save))
- goto segv;
+ err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- restore_fpu_state(regs, &sf->fpu_state);
- if (__get_user(set.sig[0], &sf->info.si_mask) ||
- (_NSIG_WORDS > 1 &&
- __copy_from_user(&set.sig[1], &sf->extramask,
- sizeof(sf->extramask))))
+ err |= restore_fpu_state(regs, &sf->fpu_state);
+
+ err |= __get_user(set.sig[0], &sf->info.si_mask);
+ if (_NSIG_WORDS > 1)
+ err |= __copy_from_user(&set.sig[1], &sf->extramask, sizeof(sf->extramask));
+
+ if (err)
goto segv;
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
current->blocked = set;
@@ -400,8 +406,7 @@ void do_sigreturn(struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
return;
segv:
- lock_kernel();
- do_exit(SIGSEGV);
+ send_sig(SIGSEGV, current, 1);
}
void do_rt_sigreturn(struct pt_regs *regs)
@@ -410,6 +415,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t *fpu_save;
sigset_t set;
+ stack_t st;
+ int err;
synchronize_user_stack ();
sf = (struct rt_signal_frame *)
@@ -419,31 +426,36 @@ void do_rt_sigreturn(struct pt_regs *regs)
if (((unsigned long) sf) & 3)
goto segv;
- if (get_user(tpc, &sf->regs.tpc) ||
- __get_user(tnpc, &sf->regs.tnpc) ||
- ((tpc | tnpc) & 3))
- goto segv;
-
- regs->tpc = tpc;
- regs->tnpc = tnpc;
+ err = get_user(tpc, &sf->regs.tpc);
+ err |= __get_user(tnpc, &sf->regs.tnpc);
+ err |= ((tpc | tnpc) & 3);
/* 2. Restore the state */
- if (__get_user(regs->y, &sf->regs.y) ||
- __get_user(tstate, &sf->regs.tstate) ||
- copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs)))
- goto segv;
+ err |= __get_user(regs->y, &sf->regs.y);
+ err |= __get_user(tstate, &sf->regs.tstate);
+ err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs));
/* User can only change condition codes in %tstate. */
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= (tstate & TSTATE_ICC);
- if (__get_user(fpu_save, &sf->fpu_save))
- goto segv;
+ err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- restore_fpu_state(regs, &sf->fpu_state);
+ err |= restore_fpu_state(regs, &sf->fpu_state);
- if (__copy_from_user(&set, &sf->mask, sizeof(sigset_t)))
+ err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+ err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
+
+ if (err)
goto segv;
+
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, (unsigned long)sf);
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
current->blocked = set;
@@ -451,8 +463,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
return;
segv:
- lock_kernel();
- do_exit(SIGSEGV);
+ send_sig(SIGSEGV, current, 1);
}
/* Checks if the fp is valid */
@@ -469,24 +480,30 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
unsigned long *fpregs = (unsigned long *)(regs+1);
unsigned long fprs;
- fprs = (regs->fprs & FPRS_FEF) |
- (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ fprs = current->tss.fpsaved[0];
if (fprs & FPRS_DL)
copy_to_user(&fpu->si_float_regs[0], fpregs,
(sizeof(unsigned int) * 32));
- else
- clear_user(&fpu->si_float_regs[0],
- (sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
copy_to_user(&fpu->si_float_regs[32], fpregs+16,
(sizeof(unsigned int) * 32));
- else
- clear_user(&fpu->si_float_regs[32],
- (sizeof(unsigned int) * 32));
- __put_user(fpregs[32], &fpu->si_fsr);
- __put_user(fpregs[33], &fpu->si_gsr);
+ __put_user(current->tss.xfsr[0], &fpu->si_fsr);
+ __put_user(current->tss.gsr[0], &fpu->si_gsr);
__put_user(fprs, &fpu->si_fprs);
- regs->tstate &= ~TSTATE_PEF;
+}
+
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
+{
+ unsigned long sp;
+
+ sp = regs->u_regs[UREG_FP] + STACK_BIAS;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+ return (void *)(sp - framesize);
}
static inline void
@@ -498,12 +515,14 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
+ save_and_clear_fpu();
+
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+
+ if (!(current->tss.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
- sf = (struct new_signal_frame *)
- (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size);
+ sf = (struct new_signal_frame *)get_sigframe(ka, regs, sigframe_size);
if (invalid_frame_pointer (sf, sigframe_size))
goto sigill;
@@ -516,8 +535,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 2. Save the current process state */
copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
-
- if (current->tss.flags & SPARC_FLAG_USEDFPU) {
+
+ if (current->tss.fpsaved[0] & FPRS_FEF) {
save_fpu_state(regs, &sf->fpu_state);
__put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
@@ -582,12 +601,13 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
+ save_and_clear_fpu();
+
sigframe_size = RT_ALIGNEDSZ;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+ if (!(current->tss.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
- sf = (struct rt_signal_frame *)
- (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size);
+ sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size);
if (invalid_frame_pointer (sf, sigframe_size))
goto sigill;
@@ -601,12 +621,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 2. Save the current process state */
copy_to_user(&sf->regs, regs, sizeof (*regs));
- if (current->tss.flags & SPARC_FLAG_USEDFPU) {
+ if (current->tss.fpsaved[0] & FPRS_FEF) {
save_fpu_state(regs, &sf->fpu_state);
__put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
__put_user(0, &sf->fpu_save);
}
+
+ /* Setup sigaltstack */
+ __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+ __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+ __put_user(current->sas_ss_size, &sf->stack.ss_size);
copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
@@ -828,28 +853,3 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
}
return 0;
}
-
-asmlinkage int
-sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
-{
- int ret = -EFAULT;
-
- lock_kernel();
- /* First see if old state is wanted. */
- if(ossptr) {
- if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
- __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
- goto out;
- }
-
- /* Now see if we want to update the new state. */
- if(ssptr) {
- if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
- __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
- goto out;
- }
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 269ff413d..b62ab65ff 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,11 +1,11 @@
-/* $Id: signal32.c,v 1.35 1998/04/01 07:00:43 davem Exp $
+/* $Id: signal32.c,v 1.41 1998/07/30 11:29:32 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/sched.h>
@@ -16,6 +16,7 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -24,7 +25,7 @@
#include <asm/pgtable.h>
#include <asm/psrcompat.h>
#include <asm/fpumacro.h>
-#include <asm/smp_lock.h>
+#include <asm/visasm.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -36,6 +37,8 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs,
/* This turned off for production... */
/* #define DEBUG_SIGNALS 1 */
+/* #define DEBUG_SIGNALS_TRACE 1 */
+/* #define DEBUG_SIGNALS_MAPS 1 */
/* Signal frames: the original one (compatible with SunOS):
*
@@ -82,6 +85,7 @@ struct rt_signal_frame32 {
sigset_t32 mask;
/* __siginfo_fpu32_t * */ u32 fpu_save;
unsigned int insns [2];
+ stack_t32 stack;
__siginfo_fpu_t fpu_state;
};
@@ -178,20 +182,23 @@ asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *
}
}
-static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
- unsigned long *fpregs = (unsigned long *)(regs + 1);
+ unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
+ int err;
- __get_user(fprs, &fpu->si_fprs);
+ err = __get_user(fprs, &fpu->si_fprs);
+ fprs_write(0);
+ regs->tstate &= ~TSTATE_PEF;
if (fprs & FPRS_DL)
- copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
+ err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
- copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- __get_user(fpregs[32], &fpu->si_fsr);
- __get_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = fprs;
- regs->tstate |= TSTATE_PEF;
+ err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
+ err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
+ current->tss.fpsaved[0] |= fprs;
+ return err;
}
void do_new_sigreturn32(struct pt_regs *regs)
@@ -201,6 +208,7 @@ void do_new_sigreturn32(struct pt_regs *regs)
unsigned pc, npc, fpu_save;
sigset_t set;
unsigned seta[_NSIG_WORDS32];
+ int err;
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
@@ -220,34 +228,35 @@ void do_new_sigreturn32(struct pt_regs *regs)
regs->tnpc = npc;
/* 2. Restore the state */
- __get_user(regs->y, &sf->info.si_regs.y);
- __get_user(psr, &sf->info.si_regs.psr);
-
- __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
- __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
- __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
- __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
- __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
- __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
- __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
- __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
- __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
- __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
- __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
- __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
- __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
- __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
- __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
+ err = __get_user(regs->y, &sf->info.si_regs.y);
+ err |= __get_user(psr, &sf->info.si_regs.psr);
+
+ err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
+ err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
+ err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
+ err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
+ err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
+ err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
+ err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
+ err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
+ err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
+ err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
+ err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
+ err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
+ err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
+ err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
+ err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
/* User can only change condition codes in %tstate. */
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
- __get_user(fpu_save, &sf->fpu_save);
+ err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- restore_fpu_state32(regs, &sf->fpu_state);
- if (__get_user(seta[0], &sf->info.si_mask) ||
- copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned)))
+ err |= restore_fpu_state32(regs, &sf->fpu_state);
+ err |= __get_user(seta[0], &sf->info.si_mask);
+ err |= copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
+ if (err)
goto segv;
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
@@ -262,8 +271,7 @@ void do_new_sigreturn32(struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
return;
segv:
- lock_kernel();
- do_exit(SIGSEGV);
+ send_sig(SIGSEGV, current, 1);
}
asmlinkage void do_sigreturn32(struct pt_regs *regs)
@@ -272,6 +280,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
unsigned pc, npc, psr;
sigset_t set;
unsigned seta[_NSIG_WORDS32];
+ int err;
synchronize_user_stack();
if (current->tss.new_signal)
@@ -284,15 +293,16 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
(((unsigned long) scptr) & 3))
goto segv;
- __get_user(pc, &scptr->sigc_pc);
- __get_user(npc, &scptr->sigc_npc);
+ err = __get_user(pc, &scptr->sigc_pc);
+ err |= __get_user(npc, &scptr->sigc_npc);
if((pc | npc) & 3)
goto segv; /* Nice try. */
- if (__get_user(seta[0], &scptr->sigc_mask) ||
- /* Note that scptr + 1 points to extramask */
- copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)))
+ err |= __get_user(seta[0], &scptr->sigc_mask);
+ /* Note that scptr + 1 points to extramask */
+ err |= copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
+ if (err)
goto segv;
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
@@ -306,22 +316,21 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
- __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack);
- current->tss.sstk_info.cur_status &= 1;
regs->tpc = pc;
regs->tnpc = npc;
- __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
- __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
- __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
+ err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
+ err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
+ err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
/* User can only change condition codes in %tstate. */
- __get_user(psr, &scptr->sigc_psr);
+ err |= __get_user(psr, &scptr->sigc_psr);
+ if (err)
+ goto segv;
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
return;
segv:
- lock_kernel ();
- do_exit (SIGSEGV);
+ send_sig(SIGSEGV, current, 1);
}
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
@@ -331,6 +340,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
unsigned pc, npc, fpu_save;
sigset_t set;
sigset_t32 seta;
+ stack_t st;
+ int err;
synchronize_user_stack();
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -351,34 +362,43 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
regs->tnpc = npc;
/* 2. Restore the state */
- __get_user(regs->y, &sf->regs.y);
- __get_user(psr, &sf->regs.psr);
-
- __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
- __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
- __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
- __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
- __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
- __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
- __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
- __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
- __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
- __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
- __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
- __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
- __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
- __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
- __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+ err = __get_user(regs->y, &sf->regs.y);
+ err |= __get_user(psr, &sf->regs.psr);
+
+ err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
+ err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
+ err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
+ err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
+ err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
+ err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
+ err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
+ err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
+ err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
+ err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
+ err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
+ err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
+ err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
+ err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
+ err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
/* User can only change condition codes in %tstate. */
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
- __get_user(fpu_save, &sf->fpu_save);
+ err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- restore_fpu_state32(regs, &sf->fpu_state);
- if (copy_from_user(&seta, &sf->mask, sizeof(sigset_t32)))
- goto segv;
+ err |= restore_fpu_state32(regs, &sf->fpu_state);
+ err |= copy_from_user(&seta, &sf->mask, sizeof(sigset_t32));
+ err |= __get_user((long)st.ss_sp, &sf->stack.ss_sp);
+ err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
+ err |= __get_user(st.ss_size, &sf->stack.ss_size);
+ if (err)
+ goto segv;
+
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, (unsigned long)sf);
+
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
@@ -392,8 +412,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
return;
segv:
- lock_kernel();
- do_exit(SIGSEGV);
+ send_sig(SIGSEGV, current, 1);
}
/* Checks if the fp is valid */
@@ -404,6 +423,21 @@ static int invalid_frame_pointer(void *fp, int fplen)
return 0;
}
+static inline void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+{
+ unsigned long sp;
+
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
+ sp = regs->u_regs[UREG_FP];
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (sa->sa_flags & SA_ONSTACK) {
+ if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+ return (void *)(sp - framesize);
+}
+
static void
setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
struct pt_regs *regs, int signr, sigset_t *oldset)
@@ -415,13 +449,12 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
#if 0
int window = 0;
#endif
- int old_status = current->tss.sstk_info.cur_status;
unsigned psr;
synchronize_user_stack();
- regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
- sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
- sframep = (struct signal_sframe32 *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
+ save_and_clear_fpu();
+
+ sframep = (struct signal_sframe32 *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
if (invalid_frame_pointer (sframep, sizeof(*sframep))){
#ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
printk("%s [%d]: User has trashed signal stack\n",
@@ -439,7 +472,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
sc = &sframep->sig_context;
/* We've already made sure frame pointer isn't in kernel space... */
- __put_user(old_status, &sc->sigc_onstack);
+ __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack);
switch (_NSIG_WORDS) {
case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -457,7 +490,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.flags & SPARC_FLAG_USEDFPU)
+ if(current->tss.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
__put_user(psr, &sc->sigc_psr);
__put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
@@ -501,23 +534,17 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
- unsigned long *fpregs = (unsigned long *)(regs+1);
+ unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
- fprs = (regs->fprs & FPRS_FEF) |
- (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ fprs = current->tss.fpsaved[0];
if (fprs & FPRS_DL)
copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32));
- else
- clear_user(&fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32));
- else
- clear_user(&fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- __put_user(fpregs[32], &fpu->si_fsr);
- __put_user(fpregs[33], &fpu->si_gsr);
+ __put_user(current->tss.xfsr[0], &fpu->si_fsr);
+ __put_user(current->tss.gsr[0], &fpu->si_gsr);
__put_user(fprs, &fpu->si_fprs);
- regs->tstate &= ~TSTATE_PEF;
}
static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
@@ -531,12 +558,13 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
/* 1. Make sure everything is clean */
synchronize_user_stack();
+ save_and_clear_fpu();
+
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+ if (!(current->tss.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
- regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
- sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
+ sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer (sf, sigframe_size)) {
#ifdef DEBUG_SIGNALS
@@ -559,7 +587,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
__put_user(regs->tnpc, &sf->info.si_regs.npc);
__put_user(regs->y, &sf->info.si_regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.flags & SPARC_FLAG_USEDFPU)
+ if(current->tss.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
__put_user(psr, &sf->info.si_regs.psr);
for (i = 0; i < 16; i++)
@@ -649,9 +677,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
int i;
synchronize_user_stack();
+ save_and_clear_fpu();
+
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
- sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ;
- sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED);
+ sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, REGWIN_SZ + SVR4_SF_ALIGNED);
if (invalid_frame_pointer (sfp, sizeof (*sfp))){
#ifdef DEBUG_SIGNALS
@@ -688,7 +717,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
__put_user(regs->tpc, &((*gr) [SVR4_PC]));
__put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
psr = tstate_to_psr (regs->tstate);
- if(current->tss.flags & SPARC_FLAG_USEDFPU)
+ if(current->tss.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
__put_user(psr, &((*gr) [SVR4_PSR]));
__put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -699,10 +728,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
for (i = 0; i < 8; i++)
__put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
- /* Setup sigaltstack, FIXME */
- __put_user(0xdeadbeef, &uc->stack.sp);
- __put_user(0, &uc->stack.size);
- __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */
+ /* Setup sigaltstack */
+ __put_user(current->sas_ss_sp, &uc->stack.sp);
+ __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ __put_user(current->sas_ss_size, &uc->stack.size);
/* Save the currently window file: */
@@ -773,6 +802,8 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
int i;
synchronize_user_stack();
+ save_and_clear_fpu();
+
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
lock_kernel();
@@ -797,9 +828,14 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
/* Store registers */
__put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
__put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
- __put_user((tstate_to_psr(regs->tstate) |
- ((current->tss.flags & SPARC_FLAG_USEDFPU) ? PSR_EF : 0)),
- &uc->mcontext.greg [SVR4_PSR]);
+#if 1
+ __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
+#else
+ i = tstate_to_psr(regs->tstate) & ~PSR_EF;
+ if (current->tss.fpsaved[0] & FPRS_FEF)
+ i |= PSR_EF;
+ __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
+#endif
__put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
/* Copy g [1..7] and o [0..7] registers */
@@ -808,10 +844,10 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
for (i = 0; i < 8; i++)
__put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
- /* Setup sigaltstack, FIXME */
- __put_user(0xdeadbeef, &uc->stack.sp);
- __put_user(0, &uc->stack.size);
- __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */
+ /* Setup sigaltstack */
+ __put_user(current->sas_ss_sp, &uc->stack.sp);
+ __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+ __put_user(current->sas_ss_size, &uc->stack.size);
/* The register file is not saved
* we have already stuffed all of it with sync_user_stack
@@ -828,7 +864,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
u32 pc, npc, psr;
sigset_t set;
svr4_sigset_t setv;
- int i;
+ int i, err;
+ stack_t st;
/* Fixme: restore windows, or is this already taken care of in
* svr4_setup_frame when sync_user_windows is done?
@@ -851,20 +888,34 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
/* Check for valid PC and nPC */
gr = &c->mcontext.greg;
- __get_user(pc, &((*gr)[SVR4_PC]));
- __get_user(npc, &((*gr)[SVR4_NPC]));
+ err = __get_user(pc, &((*gr)[SVR4_PC]));
+ err |= __get_user(npc, &((*gr)[SVR4_NPC]));
if((pc | npc) & 3) {
+#ifdef DEBUG_SIGNALS
printk ("setcontext, PC or nPC were bogus\n");
+#endif
goto sigsegv;
}
+
/* Retrieve information from passed ucontext */
- /* note that nPC is ored a 1, this is used to inform entry.S */
- /* that we don't want it to mess with our PC and nPC */
- if (copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t)))
- goto sigsegv;
+ /* note that nPC is ored a 1, this is used to inform entry.S */
+ /* that we don't want it to mess with our PC and nPC */
+
+ err |= copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t));
set.sig[0] = setv.sigbits[0] | (((long)setv.sigbits[1]) << 32);
if (_NSIG_WORDS >= 2)
set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32);
+
+ err |= __get_user((long)st.ss_sp, &c->stack.sp);
+ err |= __get_user(st.ss_flags, &c->stack.flags);
+ err |= __get_user(st.ss_size, &c->stack.size);
+ if (err)
+ goto sigsegv;
+
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, regs->u_regs[UREG_I6]);
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
current->blocked = set;
@@ -904,12 +955,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
/* 1. Make sure everything is clean */
synchronize_user_stack();
+ save_and_clear_fpu();
+
sigframe_size = RT_ALIGNEDSZ;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+ if (!(current->tss.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
- regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
- sf = (struct rt_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
+ sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer (sf, sigframe_size)) {
#ifdef DEBUG_SIGNALS
@@ -932,7 +984,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
__put_user(regs->tnpc, &sf->regs.npc);
__put_user(regs->y, &sf->regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.flags & SPARC_FLAG_USEDFPU)
+ if(current->tss.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
__put_user(psr, &sf->regs.psr);
for (i = 0; i < 16; i++)
@@ -944,6 +996,11 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
} else {
__put_user(0, &sf->fpu_save);
}
+
+ /* Setup sigaltstack */
+ __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+ __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+ __put_user(current->sas_ss_size, &sf->stack.ss_size);
switch (_NSIG_WORDS) {
case 4: seta.sig[7] = (oldset->sig[3] >> 32);
@@ -1048,6 +1105,60 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs
}
}
+#ifdef DEBUG_SIGNALS_MAPS
+
+#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %s %lu "
+
+static inline void read_maps (void)
+{
+ struct vm_area_struct * map, * next;
+ char * buffer;
+ ssize_t i;
+
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return;
+
+ for (map = current->mm->mmap ; map ; map = next ) {
+ /* produce the next line */
+ char *line;
+ char str[5], *cp = str;
+ int flags;
+ kdev_t dev;
+ unsigned long ino;
+
+ /*
+ * Get the next vma now (but it won't be used if we sleep).
+ */
+ next = map->vm_next;
+ flags = map->vm_flags;
+
+ *cp++ = flags & VM_READ ? 'r' : '-';
+ *cp++ = flags & VM_WRITE ? 'w' : '-';
+ *cp++ = flags & VM_EXEC ? 'x' : '-';
+ *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
+ *cp++ = 0;
+
+ dev = 0;
+ ino = 0;
+ if (map->vm_file != NULL) {
+ dev = map->vm_file->f_dentry->d_inode->i_dev;
+ ino = map->vm_file->f_dentry->d_inode->i_ino;
+ line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ }
+ printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset,
+ kdevname(dev), ino);
+ if (map->vm_file != NULL)
+ printk("%s\n", line);
+ else
+ printk("\n");
+ }
+ free_page((unsigned long)buffer);
+ return;
+}
+
+#endif
+
/* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
@@ -1144,8 +1255,25 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
- printk ("Sig ILL going...\n");
+ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
show_regs (regs);
+#ifdef DEBUG_SIGNALS_TRACE
+ {
+ struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
+ unsigned int ins[8];
+
+ while(rw &&
+ !(((unsigned long) rw) & 0x3)) {
+ copy_from_user(ins, &rw->ins[0], sizeof(ins));
+ printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
+ rw = (struct reg_window32 *)(unsigned long)ins[6];
+ }
+ }
+#endif
+#ifdef DEBUG_SIGNALS_MAPS
+ printk("Maps:\n");
+ read_maps();
+#endif
#endif
/* fall through */
default:
@@ -1178,28 +1306,60 @@ struct sigstack32 {
int cur_status;
};
-asmlinkage int sys32_sigstack(u32 u_ssptr, u32 u_ossptr)
+asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
{
struct sigstack32 *ssptr = (struct sigstack32 *)((unsigned long)(u_ssptr));
struct sigstack32 *ossptr = (struct sigstack32 *)((unsigned long)(u_ossptr));
int ret = -EFAULT;
- lock_kernel();
/* First see if old state is wanted. */
- if(ossptr) {
- if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
- __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+ if (ossptr) {
+ if (put_user(current->sas_ss_sp + current->sas_ss_size, &ossptr->the_stack) ||
+ __put_user(on_sig_stack(sp), &ossptr->cur_status))
goto out;
}
-
+
/* Now see if we want to update the new state. */
- if(ssptr) {
- if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
- __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+ if (ssptr) {
+ void *ss_sp;
+
+ if (get_user((long)ss_sp, &ssptr->the_stack))
goto out;
+ /* If the current stack was set with sigaltstack, don't
+ swap stacks while we are on it. */
+ ret = -EPERM;
+ if (current->sas_ss_sp && on_sig_stack(sp))
+ goto out;
+
+ /* Since we don't know the extent of the stack, and we don't
+ track onstack-ness, but rather calculate it, we must
+ presume a size. Ho hum this interface is lossy. */
+ current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
+ current->sas_ss_size = SIGSTKSZ;
}
+
ret = 0;
out:
- unlock_kernel();
+ return ret;
+}
+
+asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
+{
+ stack_t uss, uoss;
+ int ret;
+ mm_segment_t old_fs;
+
+ if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) ||
+ __get_user(uss.ss_flags, &((stack_t32 *)(long)ussa)->ss_flags) ||
+ __get_user(uss.ss_size, &((stack_t32 *)(long)ussa)->ss_size)))
+ return -EFAULT;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp);
+ set_fs(old_fs);
+ if (!ret && uossa && (put_user((long)uoss.ss_sp, &((stack_t32 *)(long)uossa)->ss_sp) ||
+ __put_user(uoss.ss_flags, &((stack_t32 *)(long)uossa)->ss_flags) ||
+ __put_user(uoss.ss_size, &((stack_t32 *)(long)uossa)->ss_size)))
+ return -EFAULT;
return ret;
}
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index ca2aa4360..3ec32e92b 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -3,7 +3,6 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tasks.h>
@@ -48,7 +47,8 @@ static int smp_activated = 0;
volatile int cpu_number_map[NR_CPUS];
volatile int __cpu_logical_map[NR_CPUS];
-struct klock_info klock_info = { KLOCK_CLEAR, 0 };
+/* Kernel spinlock */
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
__initfunc(void smp_setup(char *str, int *ints))
{
@@ -63,8 +63,7 @@ int smp_info(char *buf)
for (i = 0; i < NR_CPUS; i++)
if(cpu_present_map & (1UL << i))
len += sprintf(buf + len,
- "CPU%d:\t\t%s\n",
- i, klock_info.akp == i ? "akp" : "online");
+ "CPU%d:\t\tonline\n", i
return len;
}
@@ -85,10 +84,9 @@ __initfunc(void smp_store_cpu_info(int id))
{
cpu_data[id].udelay_val = loops_per_sec;
cpu_data[id].irq_count = 0;
- cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK;
cpu_data[id].pgcache_size = 0;
+ cpu_data[id].pgdcache_size = 0;
cpu_data[id].pgd_cache = NULL;
- cpu_data[id].pmd_cache = NULL;
cpu_data[id].pte_cache = NULL;
}
@@ -164,8 +162,6 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
-static void smp_tickoffset_init(void);
-
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
extern unsigned long smp_trampoline;
@@ -175,23 +171,8 @@ __initfunc(void smp_boot_cpus(void))
int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
- boot_cpu_id = hard_smp_processor_id();
- smp_tickoffset_init();
__sti();
- cpu_present_map = 0;
- for(i = 0; i < linux_num_cpus; i++)
- cpu_present_map |= (1UL << linux_cpus[i].mid);
- for(i = 0; i < NR_CPUS; i++) {
- cpu_number_map[i] = -1;
- __cpu_logical_map[i] = -1;
- }
- cpu_number_map[boot_cpu_id] = 0;
- prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
- __cpu_logical_map[0] = boot_cpu_id;
- klock_info.akp = boot_cpu_id;
- current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
- smp_setup_percpu_timer();
if(linux_num_cpus == 1)
return;
@@ -368,16 +349,28 @@ void smp_flush_tlb_all(void)
__flush_tlb_all();
}
+/* We know that the window frames of the user have been flushed
+ * to the stack before we get here because all callers of us
+ * are flush_tlb_*() routines, and these run after flush_cache_*()
+ * which performs the flushw.
+ */
static void smp_cross_call_avoidance(struct mm_struct *mm)
{
+ u32 ctx;
+
spin_lock(&scheduler_lock);
- get_new_mmu_context(mm, &tlb_context_cache);
+ get_new_mmu_context(mm);
mm->cpu_vm_mask = (1UL << smp_processor_id());
- if(segment_eq(current->tss.current_ds,USER_DS)) {
- u32 ctx = mm->context & 0x1fff;
-
- current->tss.ctx = ctx;
- spitfire_set_secondary_context(ctx);
+ current->tss.ctx = ctx = mm->context & 0x3ff;
+ spitfire_set_secondary_context(ctx);
+ __asm__ __volatile__("flush %g6");
+ spitfire_flush_dtlb_secondary_context();
+ spitfire_flush_itlb_secondary_context();
+ __asm__ __volatile__("flush %g6");
+ if(!segment_eq(current->tss.current_ds,USER_DS)) {
+ /* Rarely happens. */
+ current->tss.ctx = 0;
+ spitfire_set_secondary_context(0);
__asm__ __volatile__("flush %g6");
}
spin_unlock(&scheduler_lock);
@@ -385,7 +378,7 @@ static void smp_cross_call_avoidance(struct mm_struct *mm)
void smp_flush_tlb_mm(struct mm_struct *mm)
{
- u32 ctx = mm->context & 0x1fff;
+ u32 ctx = mm->context & 0x3ff;
if(mm == current->mm && mm->count == 1) {
if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
@@ -395,13 +388,13 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
local_flush_and_out:
- __flush_tlb_mm(ctx);
+ __flush_tlb_mm(ctx, SECONDARY_CONTEXT);
}
void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- u32 ctx = mm->context & 0x1fff;
+ u32 ctx = mm->context & 0x3ff;
if(mm == current->mm && mm->count == 1) {
if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
@@ -411,12 +404,14 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
local_flush_and_out:
- __flush_tlb_range(ctx, start, end);
+ start &= PAGE_MASK;
+ end &= PAGE_MASK;
+ __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
}
void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- u32 ctx = mm->context & 0x1fff;
+ u32 ctx = mm->context & 0x3ff;
if(mm == current->mm && mm->count == 1) {
if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
@@ -424,7 +419,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
return smp_cross_call_avoidance(mm);
}
#if 0 /* XXX Disabled until further notice... */
- else if(mm != current->mm && mm->count == 1) {
+ else if(mm->count == 1) {
/* Try to handle two special cases to avoid cross calls
* in common scenerios where we are swapping process
* pages out.
@@ -438,7 +433,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
local_flush_and_out:
- __flush_tlb_page(ctx, page);
+ __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT);
}
/* CPU capture. */
@@ -500,8 +495,7 @@ void smp_penguin_jailcell(void)
static inline void sparc64_do_profile(unsigned long pc)
{
-#ifdef CONFIG_PROFILE
- if(prof_buffer && current->pid) {
+ if (prof_buffer && current->pid) {
extern int _stext;
pc -= (unsigned long) &_stext;
@@ -511,7 +505,6 @@ static inline void sparc64_do_profile(unsigned long pc)
pc = prof_len - 1;
atomic_inc((atomic_t *)&prof_buffer[pc]);
}
-#endif
}
static unsigned long current_tick_offset;
@@ -543,8 +536,8 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
do {
if(!user)
sparc64_do_profile(regs->tpc);
- if(!--prof_counter(cpu)) {
-
+ if(!--prof_counter(cpu))
+ {
if (cpu == boot_cpu_id) {
extern void irq_enter(int, int);
extern void irq_exit(int, int);
@@ -563,7 +556,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
update_one_process(current, 1, user, !user, cpu);
if(--current->counter < 0) {
current->counter = 0;
- need_resched = 1;
+ current->need_resched = 1;
}
if(user) {
@@ -581,7 +574,6 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
atomic_inc((atomic_t *)inc);
atomic_inc((atomic_t *)inc2);
}
-
prof_counter(cpu) = prof_multiplier(cpu);
}
@@ -600,49 +592,6 @@ __initfunc(static void smp_setup_percpu_timer(void))
prof_counter(cpu) = prof_multiplier(cpu) = 1;
- if (cpu == boot_cpu_id) {
- extern unsigned long tl0_itick;
- extern unsigned long tl0_smp_itick;
- unsigned long flags;
-
- save_flags(flags); cli();
-
- /*
- * Steal TICK_INT interrupts from timer_interrupt().
- */
- __asm__ __volatile__("
- .globl tl0_smp_itick
- b,pt %%xcc, 1f
- nop
-
- tl0_smp_itick:
- rdpr %%pil, %%g2
- wrpr %%g0, 15, %%pil
- b,pt %%xcc, etrap_irq
- rd %%pc, %%g7
- call smp_percpu_timer_interrupt
- add %%sp, %0, %%o0
- b,pt %%xcc, rtrap
- clr %%l6
-
- 1:"
- : /* no outputs */
- : "i" (STACK_BIAS + REGWIN_SZ));
-
- memcpy(&tl0_itick, &tl0_smp_itick, 8 * 4);
-
- __asm__ __volatile__("
- membar #StoreStore
- flush %0 + 0x00
- flush %0 + 0x08
- flush %0 + 0x10
- flush %0 + 0x18"
- : /* no outputs */
- : "r" (&tl0_itick));
-
- restore_flags(flags);
- }
-
__asm__ __volatile__("rd %%tick, %%g1\n\t"
"add %%g1, %0, %%g1\n\t"
"wr %%g1, 0x0, %%tick_cmpr"
@@ -651,12 +600,27 @@ __initfunc(static void smp_setup_percpu_timer(void))
: "g1");
}
-__initfunc(static void smp_tickoffset_init(void))
+__initfunc(void smp_tick_init(void))
{
+ int i;
+
+ boot_cpu_id = hard_smp_processor_id();
current_tick_offset = timer_tick_offset;
+ cpu_present_map = 0;
+ for(i = 0; i < linux_num_cpus; i++)
+ cpu_present_map |= (1UL << linux_cpus[i].mid);
+ for(i = 0; i < NR_CPUS; i++) {
+ cpu_number_map[i] = -1;
+ __cpu_logical_map[i] = -1;
+ }
+ cpu_number_map[boot_cpu_id] = 0;
+ prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
+ __cpu_logical_map[0] = boot_cpu_id;
+ current->processor = boot_cpu_id;
+ prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
}
-__initfunc(int setup_profiling_timer(unsigned int multiplier))
+int __init setup_profiling_timer(unsigned int multiplier)
{
unsigned long flags;
int i;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 0eb16d7bb..0bdd42775 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.33 1998/04/06 16:09:40 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.39 1998/07/04 12:35:59 ecd Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -113,10 +113,10 @@ EXPORT_SYMBOL_PRIVATE(global_restore_flags);
#else
EXPORT_SYMBOL(local_irq_count);
#endif
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL_PRIVATE(flushw_user);
@@ -139,7 +139,15 @@ EXPORT_SYMBOL(dma_chain);
EXPORT_SYMBOL(ebus_chain);
EXPORT_SYMBOL(pci_dvma_offset);
EXPORT_SYMBOL(pci_dvma_mask);
+EXPORT_SYMBOL(pci_dvma_v2p_hash);
+EXPORT_SYMBOL(pci_dvma_p2v_hash);
EXPORT_SYMBOL(empty_zero_page);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
#endif
/* Solaris/SunOS binary compatibility */
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 44f17ca01..ec23e92a0 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.5 1998/03/24 05:57:56 ecd Exp $
+/* $Id: sys32.S,v 1.6 1998/06/28 08:28:22 ecd Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -84,7 +84,7 @@ sys32_getsockopt:
srl %o3, 0, %o3
mov %o7, %g1
srl %o4, 0, %o4
- call sys_setsockopt
+ call sys_getsockopt
mov %g1, %o7
.globl sys32_bdflush
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index b5198074d..1d9c0457e 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.13 1998/03/29 10:10:52 davem Exp $
+/* $Id: sys_sparc.c,v 1.20 1998/08/03 20:03:26 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -38,17 +38,9 @@ extern asmlinkage unsigned long sys_brk(unsigned long brk);
asmlinkage unsigned long sparc_brk(unsigned long brk)
{
- unsigned long ret;
-
- lock_kernel();
- if(brk >= 0x80000000000UL) { /* VM hole */
- ret = current->mm->brk;
- goto out;
- }
- ret = sys_brk(brk);
-out:
- unlock_kernel();
- return ret;
+ if(brk >= 0x80000000000UL) /* VM hole */
+ return current->mm->brk;
+ return sys_brk(brk);
}
/*
@@ -129,16 +121,6 @@ asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long thir
if (call <= SHMCTL)
switch (call) {
case SHMAT:
- if (first >= 0) {
- extern struct shmid_ds *shm_segs[];
- struct shmid_ds *shp = shm_segs[(unsigned int) first % SHMMNI];
- if (shp == IPC_UNUSED || shp == IPC_NOID) {
- err = -ENOMEM;
- if ((unsigned long)ptr >= 0x80000000000UL - shp->shm_segsz &&
- (unsigned long)ptr < 0xfffff80000000000UL)
- goto out; /* Somebody is trying to fool us */
- }
- }
err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
goto out;
case SHMDT:
@@ -161,8 +143,6 @@ out:
return err;
}
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-
/* Linux version of mmap */
asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long fd,
@@ -245,15 +225,23 @@ extern void check_pending(int signum);
asmlinkage int sys_getdomainname(char *name, int len)
{
- int nlen = strlen(system_utsname.domainname);
+ int nlen;
+ int err = -EFAULT;
+
+ down(&uts_sem);
+
+ nlen = strlen(system_utsname.domainname) + 1;
if (nlen < len)
len = nlen;
if(len > __NEW_UTS_LEN)
- return -EFAULT;
+ goto done;
if(copy_to_user(name, system_utsname.domainname, len))
- return -EFAULT;
- return 0;
+ goto done;
+ err = 0;
+done:
+ up(&uts_sem);
+ return err;
}
/* only AP+ systems have sys_aplib */
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index caad42736..a5043b3ac 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.77 1998/03/29 10:10:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -58,27 +58,10 @@
*/
#define A(x) ((unsigned long)x)
-extern char * getname_quicklist;
-extern int getname_quickcount;
-extern struct semaphore getname_quicklock;
-
-/* Tuning: increase locality by reusing same pages again...
- * if getname_quicklist becomes too long on low memory machines, either a limit
- * should be added or after a number of cycles some pages should
- * be released again ...
- */
static inline char * get_page(void)
{
char * res;
- down(&getname_quicklock);
- res = getname_quicklist;
- if (res) {
- getname_quicklist = *(char**)res;
- getname_quickcount--;
- }
- else
- res = (char*)__get_free_page(GFP_KERNEL);
- up(&getname_quicklock);
+ res = (char *)__get_free_page(GFP_KERNEL);
return res;
}
@@ -845,9 +828,6 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
ret = do_readv_writev32(VERIFY_WRITE, file,
(struct iovec32 *)A(vector), count);
- if (ret > 0)
- current->io_usage += ret;
-
out:
fput(file);
bad_file:
@@ -872,9 +852,6 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
ret = do_readv_writev32(VERIFY_READ, file,
(struct iovec32 *)A(vector), count);
up(&file->f_dentry->d_inode->i_sem);
- if (ret > 0)
- current->io_usage += ret;
-
out:
fput(file);
bad_file:
@@ -1148,6 +1125,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x)
put_user(sec, &tvp->tv_sec);
put_user(usec, &tvp->tv_usec);
}
+ current->timeout = 0;
if (ret < 0)
goto out;
@@ -1247,27 +1225,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
return ret;
}
-extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf);
-
-asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf)
-{
- switch (ver & __XSTAT_VER_MASK) {
- case __XSTAT_VER_1:
- switch (ver & __XSTAT_VER_TYPEMASK) {
- case __XSTAT_VER_XSTAT:
- return sys32_newstat(file, statbuf);
- case __XSTAT_VER_LXSTAT:
- return sys32_newlstat(file, statbuf);
- case __XSTAT_VER_FXSTAT:
- return sys32_newfstat(file, statbuf);
- }
- return -EINVAL;
- case __XSTAT_VER_2:
- return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf));
- }
- return -EINVAL;
-}
-
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
@@ -2662,7 +2619,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
- regs->fprs = 0;
+ current->tss.xfsr[0] = 0;
+ current->tss.fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
@@ -2703,119 +2661,274 @@ struct module_info32 {
s32 usecount;
};
-extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret);
+/* Query various bits about modules. */
+
+extern long get_mod_name(const char *user_name, char **buf);
+extern void put_mod_name(char *buf);
+extern struct module *find_module(const char *name);
+extern struct module kernel_module;
-asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv)
+static int
+qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
{
- char *buff;
- mm_segment_t old_fs = get_fs();
- size_t val;
- int ret, i, j;
- unsigned long *p;
- char *usernam = NULL;
- int bufsiz = bufsize;
- struct module_info mi;
-
- switch (which) {
- case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv));
- case QM_SYMBOLS:
- bufsiz <<= 1;
- case QM_MODULES:
- case QM_REFS:
- case QM_DEPS:
- if (name_user) {
- usernam = getname32 (name_user);
- ret = PTR_ERR(usernam);
- if (IS_ERR(usernam))
- return ret;
- }
- buff = kmalloc (bufsiz, GFP_KERNEL);
- if (!buff) {
- if (name_user) putname32 (usernam);
- return -ENOMEM;
+ struct module *mod;
+ size_t nmod, space, len;
+
+ nmod = space = 0;
+
+ for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+ len = strlen(mod->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, mod->name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nmod, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((mod = mod->next) != &kernel_module)
+ space += strlen(mod->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = 0;
+ for (i = 0; i < mod->ndeps; ++i) {
+ const char *dep_name = mod->deps[i].dep->name;
+
+ len = strlen(dep_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, dep_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(i, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while (++i < mod->ndeps)
+ space += strlen(mod->deps[i].dep->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t nrefs, space, len;
+ struct module_ref *ref;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = 0;
+ for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+ const char *ref_name = ref->ref->name;
+
+ len = strlen(ref_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, ref_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nrefs, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((ref = ref->next_ref) != NULL)
+ space += strlen(ref->ref->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+ struct module_symbol *s;
+ char *strings;
+ unsigned *vals;
+
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = mod->nsyms * 2*sizeof(u32);
+
+ i = len = 0;
+ s = mod->syms;
+
+ if (space > bufsize)
+ goto calc_space_needed;
+
+ if (!access_ok(VERIFY_WRITE, buf, space))
+ return -EFAULT;
+
+ bufsize -= space;
+ vals = (unsigned *)buf;
+ strings = buf+space;
+
+ for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+ len = strlen(s->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+
+ if (copy_to_user(strings, s->name, len)
+ || __put_user(s->value, vals+0)
+ || __put_user(space, vals+1))
+ return -EFAULT;
+
+ strings += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(i, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ for (; i < mod->nsyms; ++i, ++s)
+ space += strlen(s->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ int error = 0;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+
+ if (sizeof(struct module_info32) <= bufsize) {
+ struct module_info32 info;
+ info.addr = (unsigned long)mod;
+ info.size = mod->size;
+ info.flags = mod->flags;
+ info.usecount = (mod_member_present(mod, can_unload)
+ && mod->can_unload ? -1 : mod->usecount);
+
+ if (copy_to_user(buf, &info, sizeof(struct module_info32)))
+ return -EFAULT;
+ } else
+ error = -ENOSPC;
+
+ if (put_user(sizeof(struct module_info32), ret))
+ return -EFAULT;
+
+ return error;
+}
+
+asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret)
+{
+ struct module *mod;
+ int err;
+
+ lock_kernel();
+ if (name_user == 0)
+ mod = &kernel_module;
+ else {
+ long namelen;
+ char *name;
+
+ if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) {
+ err = namelen;
+ goto out;
}
-qmsym_toshort:
- set_fs (KERNEL_DS);
- ret = sys_query_module (usernam, which, buff, bufsiz, &val);
- set_fs (old_fs);
- if (which != QM_SYMBOLS) {
- if (ret == -ENOSPC || !ret) {
- if (put_user (val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- if (!ret) {
- if (copy_to_user ((char *)A(buf), buff, bufsize))
- ret = -EFAULT;
- }
- } else {
- if (ret == -ENOSPC) {
- if (put_user (2 * val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- p = (unsigned long *)buff;
- if (!ret) {
- if (put_user (val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- if (!ret) {
- j = val * 8;
- for (i = 0; i < val; i++, p += 2) {
- if (bufsize < (2 * sizeof (u32))) {
- bufsiz = 0;
- goto qmsym_toshort;
- }
- if (put_user (p[0], (u32 *)A(buf)) ||
- __put_user (p[1] - j, (((u32 *)A(buf))+1))) {
- ret = -EFAULT;
- break;
- }
- bufsize -= (2 * sizeof (u32));
- buf += (2 * sizeof (u32));
- }
- }
- if (!ret && val) {
- char *strings = buff + ((unsigned long *)buff)[1];
- j = *(p - 1) - ((unsigned long *)buff)[1];
- j = j + strlen (strings + j) + 1;
- if (bufsize < j) {
- bufsiz = 0;
- goto qmsym_toshort;
- }
- if (copy_to_user ((char *)A(buf), strings, j))
- ret = -EFAULT;
- }
+ err = -ENOENT;
+ if (namelen == 0)
+ mod = &kernel_module;
+ else if ((mod = find_module(name)) == NULL) {
+ put_mod_name(name);
+ goto out;
}
- kfree (buff);
- if (name_user) putname32 (usernam);
- return ret;
+ put_mod_name(name);
+ }
+
+ switch (which)
+ {
+ case 0:
+ err = 0;
+ break;
+ case QM_MODULES:
+ err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_DEPS:
+ err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_REFS:
+ err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_SYMBOLS:
+ err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
case QM_INFO:
- if (name_user) {
- usernam = getname32 (name_user);
- ret = PTR_ERR(usernam);
- if (IS_ERR(usernam))
- return ret;
- }
- set_fs (KERNEL_DS);
- ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
- set_fs (old_fs);
- if (!ret) {
- if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- else if (bufsize < sizeof (struct module_info32))
- ret = -ENOSPC;
- }
- if (!ret) {
- if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) ||
- __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) ||
- __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) ||
- __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount)))
- ret = -EFAULT;
- }
- if (name_user) putname32 (usernam);
- return ret;
+ err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ break;
}
+out:
+ unlock_kernel();
+ return err;
}
struct kernel_sym32 {
@@ -3356,3 +3469,24 @@ asmlinkage int sys32_personality(unsigned long personality)
ret = PER_LINUX;
return ret;
}
+
+extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ off_t of;
+
+ if (offset && get_user(of, (__kernel_off_t32 *)A(offset)))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+ set_fs(old_fs);
+
+ if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset)))
+ return -EFAULT;
+
+ return ret;
+}
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index ad7bac534..ec965972f 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.11 1998/03/29 10:10:55 davem Exp $
+/* $Id: sys_sunos32.c,v 1.16 1998/06/16 04:37:06 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -56,8 +56,6 @@
#define SUNOS_NR_OPEN 256
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-
asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
{
struct file *file = NULL;
@@ -259,12 +257,12 @@ asmlinkage void sunos_madvise(u32 address, u32 len, u32 strategy)
* *or* the passed base address is not aligned on a page boundary you
* get an error.
*/
-asmlinkage int sunos_mincore(u32 addr, u32 len, u32 u_array)
+asmlinkage int sunos_mincore(u32 __addr, u32 len, u32 u_array)
{
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
- unsigned long limit;
+ unsigned long limit, addr = (unsigned long)__addr;
int num_pages, pnum, retval = -EINVAL;
char *array = (char *)A(u_array);
@@ -523,26 +521,6 @@ out:
return error;
}
-asmlinkage int sunos_getdomainname(u32 u_name, int len)
-{
- int nlen = strlen(system_utsname.domainname);
- int ret = -EFAULT;
- char *name = (char *)A(u_name);
-
- lock_kernel();
- if (nlen < len)
- len = nlen;
-
- if(len > __NEW_UTS_LEN)
- goto out;
- if(copy_to_user(name, system_utsname.domainname, len))
- goto out;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
struct sunos_utsname {
char sname[9];
char nname[9];
@@ -557,7 +535,7 @@ asmlinkage int sunos_uname(u32 u_name)
struct sunos_utsname *name = (struct sunos_utsname *)A(u_name);
int ret = -EFAULT;
- lock_kernel();
+ down(&uts_sem);
if(!name)
goto out;
if(copy_to_user(&name->sname[0],
@@ -573,7 +551,7 @@ asmlinkage int sunos_uname(u32 u_name)
copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
ret = 0;
out:
- unlock_kernel();
+ up(&uts_sem);
return ret;
}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 6389681dd..beed61bd7 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.41 1998/03/24 05:57:57 ecd Exp $
+/* $Id: systbls.S,v 1.47 1998/07/28 13:07:55 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -17,14 +17,14 @@
.globl sys_call_table32
sys_call_table32:
-/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_xstat, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_xmknod, sys32_lseek
-/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
- .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+ .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile
/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
.word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
@@ -40,11 +40,11 @@ sys_call_table32:
/*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
.word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall
/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
@@ -65,8 +65,8 @@ sys_call_table32:
.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+ .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
.word sys_aplib
@@ -76,14 +76,14 @@ sys_call_table32:
.globl sys_call_table64, sys_call_table
sys_call_table64:
sys_call_table:
-/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_xstat, sys_mknod
-/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_xmknod, sys_lseek
-/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
- .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+ .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
.word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
@@ -99,11 +99,11 @@ sys_call_table:
/*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
.word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
- .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+ .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
- .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+ .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
.word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
@@ -124,8 +124,8 @@ sys_call_table:
.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
/*230*/ .word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+ .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
.word sys_aplib
@@ -134,7 +134,7 @@ sys_call_table:
.align 1024
.globl sunos_sys_table
sunos_sys_table:
-/*0*/ .word sunos_indir, sys_exit, sys_fork
+/*0*/ .word sunos_indir, sparc_exit, sys_fork
.word sunos_read, sunos_write, sunos_open
.word sys_close, sunos_wait4, sys_creat
.word sys_link, sys_unlink, sunos_execv
@@ -189,7 +189,7 @@ sunos_sys_table:
.word sys_poll, sunos_nosys, sunos_nosys
.word sunos_getdirentries, sys32_statfs, sys32_fstatfs
.word sys_umount, sunos_nosys, sunos_nosys
- .word sunos_getdomainname, sys_setdomainname
+ .word sys_getdomainname, sys_setdomainname
.word sunos_nosys, sys32_quotactl, sunos_nosys
.word sunos_mount, sys_ustat, sunos_semsys
.word sunos_nosys, sunos_shmsys, sunos_audit
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index debb08888..364f2b4a1 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.13 1998/03/15 17:23:47 ecd Exp $
+/* $Id: time.c,v 1.15 1998/05/12 22:38:29 ecd Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -227,13 +227,17 @@ __initfunc(void clock_probe(void))
struct linux_prom_registers clk_reg[2];
char model[128];
int node, busnd = -1, err;
+#ifdef CONFIG_PCI
+ struct linux_ebus *ebus = 0;
+#endif
if(central_bus != NULL) {
busnd = central_bus->child->prom_node;
}
#ifdef CONFIG_PCI
else if (ebus_chain != NULL) {
- busnd = ebus_chain->prom_node;
+ ebus = ebus_chain;
+ busnd = ebus->prom_node;
}
#endif
else {
@@ -253,6 +257,15 @@ __initfunc(void clock_probe(void))
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59")) {
node = prom_getsibling(node);
+#ifdef CONFIG_PCI
+ if ((node == 0) && ebus) {
+ ebus = ebus->next;
+ if (ebus) {
+ busnd = ebus->prom_node;
+ node = prom_getchild(busnd);
+ }
+ }
+#endif
if(node == 0) {
prom_printf("clock_probe: Cannot find timer chip\n");
prom_halt();
@@ -275,7 +288,7 @@ __initfunc(void clock_probe(void))
else if (ebus_chain) {
struct linux_ebus_device *edev;
- for_each_ebusdev(edev, ebus_chain)
+ for_each_ebusdev(edev, ebus)
if (edev->prom_node == node)
break;
if (!edev) {
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 8604b3301..797d4047e 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.3 1998/02/22 21:06:11 jj Exp $
+/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -172,13 +172,29 @@ bounce:
mov %o2, %g6
wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
-#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
- sethi %uhi(KERN_HIGHBITS), %g2
- sllx %g2, 32, %g2
-#undef KERN_HIGHBITS
- ldx [%o2 + AOFF_task_mm], %g6
- ldx [%g6 + AOFF_mm_pgd], %g6
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+#ifdef THIS_IS_CHEETAH
+#error Dave, make sure you took care of other issues in rest of sparc64 code...
+#define VPTE_BASE 0xffe0000000000000
+#else /* Spitfire/Blackbird */
+#define VPTE_BASE 0xfffffffe00000000
+#endif
+ mov TSB_REG, %g1
+ stxa %g0, [%g1] ASI_DMMU
+ membar #Sync
+ mov TLB_SFSR, %g1
+ sethi %uhi(KERN_HIGHBITS), %g2
+ or %g2, %ulo(KERN_HIGHBITS), %g2
+ sllx %g2, 32, %g2
+ or %g2, KERN_LOWBITS, %g2
+ sethi %uhi(VPTE_BASE), %g3
+ or %g3, %ulo(VPTE_BASE), %g3
+ sllx %g3, 32, %g3
clr %g7
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
+#undef VPTE_BASE
wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
sethi %hi(ivector_to_mask), %g5
@@ -186,14 +202,6 @@ bounce:
mov 0x40, %g2
wrpr %g0, 0, %wstate
- wrpr %o1, PSTATE_IE, %pstate
-
- mov TSB_REG, %o4
- mov 1, %o5
- stxa %o5, [%o4] ASI_DMMU
- stxa %o5, [%o4] ASI_IMMU
- membar #Sync
-
or %o1, PSTATE_IE, %o1
wrpr %o1, 0, %pstate
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 069e908d0..e1d652841 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.49 1998/04/06 16:09:38 jj Exp $
+/* $Id: traps.c,v 1.51 1998/06/12 14:54:20 jj Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -316,10 +316,10 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs)
{
-#ifdef DEBUG_FPU
- struct fpustate *f = FPUSTATE;
-
- printk("fpieee %016lx\n", f->fsr);
+#ifdef DEBUG_FPU
+ save_and_clear_fpu();
+
+ printk("fpieee %016lx\n", current->tss.xfsr[0]);
#endif
do_fpe_common(regs);
}
@@ -331,7 +331,8 @@ void do_fpother(struct pt_regs *regs)
struct fpustate *f = FPUSTATE;
int ret = 0;
- switch ((f->fsr & 0x1c000)) {
+ save_and_clear_fpu();
+ switch ((current->tss.xfsr[0] & 0x1c000)) {
case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */
ret = do_mathemu(regs, f);
@@ -339,7 +340,7 @@ void do_fpother(struct pt_regs *regs)
}
if (ret) return;
#ifdef DEBUG_FPU
- printk("fpother %016lx\n", f->fsr);
+ printk("fpother %016lx\n", current->tss.xfsr[0]);
#endif
do_fpe_common(regs);
}
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 3d17fb3cb..87f282fa1 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.23 1998/03/15 17:23:48 ecd Exp $
+/* $Id: ttable.S,v 1.25 1998/05/23 18:24:53 jj Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -6,7 +6,7 @@
#include <linux/config.h>
- .globl sparc64_ttable_tl0, tl0_itick, sparc64_ttable_tl1,
+ .globl sparc64_ttable_tl0, sparc64_ttable_tl1,
sparc64_ttable_tl0:
tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
@@ -45,7 +45,11 @@ tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
tl0_irq13: TRAP_IRQ(handler_irq, 13)
-tl0_itick: TRAP_IRQ(handler_irq, 14)
+#ifndef __SMP__
+tl0_irq14: TRAP_IRQ(handler_irq, 14)
+#else
+tl0_irq14: TICK_SMP_IRQ
+#endif
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
@@ -55,9 +59,9 @@ tl0_paw: TRAP(do_paw)
tl0_vaw: TRAP(do_vaw)
tl0_cee: TRAP(do_cee)
tl0_iamiss:
-#include "itlb_miss.S"
+#include "itlb_base.S"
tl0_damiss:
-#include "dtlb_miss.S"
+#include "dtlb_base.S"
tl0_daprot:
#include "dtlb_prot.S"
tl0_resv070: BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
@@ -199,10 +203,9 @@ tl1_ivec: TRAP_IVEC
tl1_paw: TRAPTL1(do_paw_tl1)
tl1_vaw: TRAPTL1(do_vaw_tl1)
tl1_cee: TRAPTL1(do_cee_tl1)
-tl1_iamiss:
-#include "itlb_miss.S"
+tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
tl1_damiss:
-#include "dtlb_miss.S"
+#include "dtlb_backend.S"
tl1_daprot:
#include "dtlb_prot.S"
tl1_resv070: BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 1c433d793..50de6cfd5 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.8 1997/10/14 16:21:24 jj Exp $
+/* $Id: unaligned.c,v 1.10 1998/06/19 13:00:32 jj Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -453,7 +453,7 @@ int handle_popc(u32 insn, struct pt_regs *regs)
} else {
struct reg_window *win;
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
- get_user(ret, &win->locals[rd - 16]);
+ put_user(ret, &win->locals[rd - 16]);
}
}
advance(regs);
@@ -470,11 +470,12 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
struct fpustate *f = FPUSTATE;
int asi = decode_asi(insn, regs);
- int flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
+ int flag = (freg < 32) ? FPRS_DL : FPRS_DU;
- f->fsr &= ~0x1c000;
+ save_and_clear_fpu();
+ current->tss.xfsr[0] &= ~0x1c000;
if (freg & 3) {
- f->fsr |= (6 << 14) /* invalid_fp_register */;
+ current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
do_fpother(regs);
return 0;
}
@@ -482,7 +483,7 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
/* STQ */
u64 first = 0, second = 0;
- if (current->tss.flags & flag) {
+ if (current->tss.fpsaved[0] & flag) {
first = *(u64 *)&f->regs[freg];
second = *(u64 *)&f->regs[freg+2];
}
@@ -545,13 +546,11 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
second = le32_to_cpup(&third);
third = tmp;
}
- regs->fprs |= FPRS_FEF;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) {
- current->tss.flags |= SPARC_FLAG_USEDFPU;
- f->fsr = 0;
- f->gsr = 0;
+ if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
+ current->tss.fpsaved[0] = FPRS_FEF;
+ current->tss.gsr[0] = 0;
}
- if (!(current->tss.flags & flag)) {
+ if (!(current->tss.fpsaved[0] & flag)) {
if (freg < 32)
memset(f->regs, 0, 32*sizeof(u32));
else
@@ -561,7 +560,7 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
f->regs[freg+1] = second;
f->regs[freg+2] = third;
f->regs[freg+3] = fourth;
- current->tss.flags |= flag;
+ current->tss.fpsaved[0] |= flag;
}
advance(regs);
return 1;
@@ -593,25 +592,24 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
} else
goto daex;
}
+ save_and_clear_fpu();
freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
value = (((u64)first) << 32) | second;
if (asi & 0x8) /* Little */
value = __swab64p(&value);
- flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
- regs->fprs |= FPRS_FEF;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) {
- current->tss.flags |= SPARC_FLAG_USEDFPU;
- f->fsr = 0;
- f->gsr = 0;
+ flag = (freg < 32) ? FPRS_DL : FPRS_DU;
+ if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
+ current->tss.fpsaved[0] = FPRS_FEF;
+ current->tss.gsr[0] = 0;
}
- if (!(current->tss.flags & flag)) {
+ if (!(current->tss.fpsaved[0] & flag)) {
if (freg < 32)
memset(f->regs, 0, 32*sizeof(u32));
else
memset(f->regs+32, 0, 32*sizeof(u32));
}
*(u64 *)(f->regs + freg) = value;
- current->tss.flags |= flag;
+ current->tss.fpsaved[0] |= flag;
} else {
daex: data_access_exception(regs);
return;
@@ -638,10 +636,11 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
asi = sfsr >> 16;
value = 0;
- flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
+ flag = (freg < 32) ? FPRS_DL : FPRS_DU;
if (asi > ASI_SNFL)
goto daex;
- if (current->tss.flags & flag)
+ save_and_clear_fpu();
+ if (current->tss.fpsaved[0] & flag)
value = *(u64 *)&f->regs[freg];
switch (asi) {
case ASI_P:
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index 6e3f6193a..fd75011fd 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.22 1997/10/24 11:57:48 jj Exp $
+/* $Id: winfixup.S,v 1.24 1998/06/12 14:54:19 jj Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -60,15 +60,14 @@ fill_fixup:
sll %g2, 3, %g2 ! NORMAL-->OTHER
wrpr %g0, 0x0, %canrestore ! Standard etrap stuff.
- wr %g0, 0x0, %fprs ! zap FPU just in case...
wrpr %g2, 0x0, %wstate ! This must be consistant.
wrpr %g0, 0x0, %otherwin ! We know this.
mov PRIMARY_CONTEXT, %g1 ! Change contexts...
stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus.
flush %g6 ! Flush instruction buffers
rdpr %pstate, %l1 ! Prepare to change globals.
-
mov %g6, %o7 ! Get current.
+
andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
srlx %g5, PAGE_SHIFT, %o1 ! Fault address
wrpr %g0, 0x0, %tl ! Out of trap levels.
@@ -166,12 +165,6 @@ window_scheisse_from_user_common:
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
-winfix_trampoline:
- andn %g3, 0x7f, %g3
- add %g3, 0x7c, %g3
-
- wrpr %g3, %tnpc
- done
.globl winfix_mna, fill_fixup_mna, spill_fixup_mna
winfix_mna:
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 9f8729ee5..a580f7ae4 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 1997/08/19 03:11:50 davem Exp $
+# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $
# Makefile for Sparc library files..
#
@@ -6,7 +6,7 @@ CFLAGS := $(CFLAGS)
OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
- VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
+ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S
index ede87843b..3992da997 100644
--- a/arch/sparc64/lib/VISbzero.S
+++ b/arch/sparc64/lib/VISbzero.S
@@ -1,4 +1,4 @@
-/* $Id: VISbzero.S,v 1.8 1997/08/22 15:54:50 jj Exp $
+/* $Id: VISbzero.S,v 1.9 1998/06/12 14:53:50 jj Exp $
* VISbzero.S: High speed clear operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -9,6 +9,8 @@
#include "VIS.h"
#ifdef __KERNEL__
+#include <asm/visasm.h>
+
#define EXN(x,y,a,b,z) \
98: x,y; \
.section .fixup; \
@@ -141,9 +143,9 @@ bzero:
6: andncc %o1, 0x3f, %o3
7: be,pn %xcc, 9f
#ifdef __KERNEL__
- rd %asi, %g7
- wr %g0, FPRS_FEF, %fprs
- wr %g7, ASI_BLK_XOR, %asi
+ rd %asi, %o4
+ wr %o4, ASI_BLK_XOR, %asi
+ VISEntryHalf
#else
wr %g0, ASI_BLK_P, %asi
#endif
@@ -178,8 +180,8 @@ bzero:
add %o0, 256, %o0
12:
#ifdef __KERNEL__
- wr %g0, 0, %fprs
- wr %g7, 0x0, %asi
+ VISExitHalf
+ wr %o4, 0x0, %asi
#else
#ifndef REGS_64BIT
wr %g0, FPRS_FEF, %fprs
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index 40b781e73..7f2f497cd 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,9 +1,9 @@
-/* $Id: VIScopy.S,v 1.14 1997/08/22 15:54:53 jj Exp $
+/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include "VIS.h"
@@ -24,12 +24,15 @@
*/
#ifdef __KERNEL__
+
+#include <asm/visasm.h>
+
#define FPU_CLEAN_RETL \
- wr %g0, 0, %fprs; \
+ VISExit \
retl; \
clr %o0;
#define FPU_RETL \
- wr %g0, 0, %fprs; \
+ VISExit \
retl; \
clr %o0;
#define NORMAL_RETL \
@@ -40,7 +43,7 @@
.section .fixup; \
.align 4; \
99: ba VIScopyfixup_ret; \
- a, b, %o0; \
+ a, b, %o1; \
.section __ex_table; \
.align 4; \
.word 98b, 99b; \
@@ -52,7 +55,7 @@
.align 4; \
99: c, d, e; \
ba VIScopyfixup_ret; \
- a, b, %o0; \
+ a, b, %o1; \
.section __ex_table; \
.align 4; \
.word 98b, 99b; \
@@ -298,10 +301,6 @@
.globl __memcpy_entry
.type __memcpy_entry,@function
-
- .globl copy_page
- .type copy_page,@function
-
memcpy_private:
__memcpy:
memcpy: mov ASI_BLK_P, asi_src ! IEU0 Group
@@ -310,12 +309,6 @@ memcpy: mov ASI_BLK_P, asi_src ! IEU0 Group
retl
clr %o0
-copy_page: wr %g0, FPRS_FEF, %fprs ! FPU Group
- sethi %hi(8192), %o2 ! IEU0 Group
- mov ASI_BLK_P, asi_src ! IEU1
- b,pt %xcc, dest_is_64byte_aligned ! CTI
- mov ASI_BLK_P, asi_dest ! IEU0 Group
-
.align 32
.globl __copy_from_user
.type __copy_from_user,@function
@@ -355,7 +348,11 @@ __memcpy_384plus:
#endif
VIS_enter:
be,pt %xcc, dest_is_8byte_aligned ! CTI
+#ifdef __KERNEL__
+ nop ! IEU0 Group
+#else
andcc %o0, 0x38, %g5 ! IEU1 Group
+#endif
do_dest_8byte_align:
mov 8, %g1 ! IEU0
sub %g1, %g2, %g2 ! IEU0 Group
@@ -377,7 +374,8 @@ do_dest_8byte_align:
EX(LDUB [%o1] ASINORMAL, %o5,
add %o2, %g2) ! Load Group
add %o0, 2, %o0 ! IEU0
- EX(LDUB [%o1 + 1] ASINORMAL, %g3,
+ EX2(LDUB [%o1 + 1] ASINORMAL, %g3,
+ sub %o0, 2, %o0,
add %o2, %g2) ! Load Group
ASI_SETDST_NOBLK ! LSU Group
subcc %g2, 2, %g2 ! IEU1 Group
@@ -389,17 +387,17 @@ do_dest_8byte_align:
EX2(STB %g3, [%o0 - 1] ASINORMAL,
add %g2, 1, %g2,
add %o2, %g2) ! Store
-3: andcc %o0, 0x38, %g5 ! IEU1 Group
-dest_is_8byte_aligned:
- be,pt %icc, dest_is_64byte_aligned ! CTI
#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs ! FPU Group
-do_dest_64byte_align:
- mov 64, %g1 ! IEU0 Group
+3:
+dest_is_8byte_aligned:
+ VISEntry
+ andcc %o0, 0x38, %g5 ! IEU1 Group
#else
- mov 64, %g1 ! IEU0 Group
-do_dest_64byte_align:
+3: andcc %o0, 0x38, %g5 ! IEU1 Group
+dest_is_8byte_aligned:
#endif
+ be,pt %icc, dest_is_64byte_aligned ! CTI
+ mov 64, %g1 ! IEU0
fmovd %f0, %f2 ! FPU
sub %g1, %g5, %g5 ! IEU0 Group
ASI_SETSRC_NOBLK ! LSU Group
@@ -646,7 +644,9 @@ __memcpy_short:
2: ASI_SETSRC_NOBLK ! LSU Group
EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group
add %o0, 2, %o0 ! IEU0
- EXO2(LDUB [%o1 + 1] ASINORMAL, %o5) ! LOAD Group
+ EX2(LDUB [%o1 + 1] ASINORMAL, %o5,
+ sub %o0, 2, %o0,
+ add %o2, %g0) ! LOAD Group
add %o1, 2, %o1 ! IEU0
ASI_SETDST_NOBLK ! LSU Group
subcc %o2, 2, %o2 ! IEU1 Group
@@ -866,9 +866,9 @@ normal_retl:
ASI_SETSRC_NOBLK ! LSU Group
EX(LDX [%o1] ASINORMAL, %g2,
and %o2, 0xf) ! Load Group
- add %o1, 8, %o1 ! IEU0
+ add %o0, 8, %o0 ! IEU0
ASI_SETDST_NOBLK ! LSU Group
- add %o0, 8, %o0 ! IEU0 Group
+ add %o1, 8, %o1 ! IEU0 Group
EX(STX %g2, [%o0 - 0x8] ASINORMAL,
and %o2, 0xf) ! Store
85: be,pt %xcc, 1f ! CTI
@@ -876,9 +876,9 @@ normal_retl:
ASI_SETSRC_NOBLK ! LSU Group
EX(LDUW [%o1] ASINORMAL, %g2,
and %o2, 0x7) ! Load Group
- add %o1, 4, %o1 ! IEU0
+ add %o0, 4, %o0 ! IEU0
ASI_SETDST_NOBLK ! LSU Group
- add %o0, 4, %o0 ! IEU0 Group
+ add %o1, 4, %o1 ! IEU0 Group
EX(STW %g2, [%o0 - 0x4] ASINORMAL,
and %o2, 0x7) ! Store
1: be,pt %xcc, 1f ! CTI
@@ -886,9 +886,9 @@ normal_retl:
ASI_SETSRC_NOBLK ! LSU Group
EX(LDUH [%o1] ASINORMAL, %g2,
and %o2, 0x3) ! Load Group
- add %o1, 2, %o1 ! IEU0
+ add %o0, 2, %o0 ! IEU0
ASI_SETDST_NOBLK ! LSU Group
- add %o0, 2, %o0 ! IEU0 Group
+ add %o1, 2, %o1 ! IEU0 Group
EX(STH %g2, [%o0 - 0x2] ASINORMAL,
and %o2, 0x3) ! Store
1: be,pt %xcc, 1f ! CTI
@@ -920,7 +920,7 @@ memcpy_noVIS_misaligned:
add %o2, 1) ! Store
2:
#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs ! FPU Group
+ VISEntry
#endif
andn %o2, 7, %g5 ! IEU0 Group
and %o2, 7, %o2 ! IEU1
@@ -976,16 +976,31 @@ fpu_retl:
.section .fixup
.align 4
VIScopyfixup_reto2:
- mov %o2, %o0
+ mov %o2, %o1
VIScopyfixup_ret:
+ /* If this is copy_from_user(), zero out the rest of the
+ * kernel buffer.
+ */
+ andcc asi_src, 0x1, %g0
+ be,pt %icc, 1f
+ andcc asi_dest, 0x1, %g0
+ bne,pn %icc, 1f
+ VISExit
+ save %sp, -160, %sp
+ mov %i0, %o0
+ call __bzero
+ mov %i1, %o1
+ restore
+1: mov %o1, %o0
retl
- wr %g0, 0, %fprs
+ nop
VIScopyfixup1: subcc %g2, 18, %g2
+ add %o0, 32, %o0
bgeu,a,pt %icc, VIScopyfixup1
sub %g7, 32, %g7
+ sub %o0, 32, %o0
rd %pc, %g5
- add %g2, 18, %g2
- add %g2, 20, %g2
+ add %g2, (18 + 16), %g2
ldub [%g5 + %g2], %g2
ba,a,pt %xcc, 2f
.byte 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 12, 12, 16, 20, 20, 24, 28, 28
@@ -994,41 +1009,43 @@ VIScopyfixup2: mov (7 * 16), %g7
1: subcc %g2, 10, %g2
bgeu,a,pt %icc, 1b
sub %g7, 16, %g7
+ sub %o0, %g7, %o0
rd %pc, %g5
- add %g2, 10, %g2
- add %g2, 20, %g2
+ add %g2, (10 + 16), %g2
ldub [%g5 + %g2], %g2
ba,a,pt %xcc, 4f
.byte 0, 0, 0, 0, 0, 4, 4, 8, 12, 12
.align 4
VIScopyfixup3: subcc %g2, 10, %g2
+ add %o0, 32, %o0
bgeu,a,pt %icc, VIScopyfixup3
sub %g7, 32, %g7
+ sub %o0, 32, %o0
rd %pc, %g5
- add %g2, 10, %g2
- add %g2, 20, %g2
+ add %g2, (10 + 16), %g2
ldub [%g5 + %g2], %g2
ba,a,pt %xcc, 2f
.byte 0, 0, 0, 0, 0, 0, 0, 8, 16, 24
.align 4
-2: and %g1, 0x7f, %g1
+2: and %o2, 0x7f, %o2
sub %g7, %g2, %g7
ba,pt %xcc, VIScopyfixup_ret
- add %g7, %g1, %o0
+ add %g7, %o2, %o1
VIScopyfixup4: mov (7 * 16), %g7
3: subcc %g2, 6, %g2
bgeu,a,pt %icc, 3b
sub %g7, 16, %g7
+ sub %o0, %g7, %o0
rd %pc, %g5
- add %g2, 6, %g2
- add %g2, 20, %g2
+ add %g2, (6 + 16), %g2
ldub [%g5 + %g2], %g2
ba,a,pt %xcc, 4f
.byte 0, 0, 0, 0, 0, 8
.align 4
-4: and %g1, 7, %g1
+4: and %o2, 0xf, %o2
+ sub %g7, %g2, %g7
ba,pt %xcc, VIScopyfixup_ret
- add %g7, %g1, %o0
+ add %g7, %o2, %o1
VIScopyfixup_vis3:
sub %o2, 0x80, %o2
VIScopyfixup_vis2:
@@ -1038,13 +1055,13 @@ VIScopyfixup_vis0:
VIScopyfixup_vis1:
add %g7, %g3, %g7
ba,pt %xcc, VIScopyfixup_ret
- add %o2, %g7, %o0
+ add %o2, %g7, %o1
VIScopyfixup_vis5:
add %g3, 8, %g3
VIScopyfixup_vis4:
add %g3, 8, %g3
ba,pt %xcc, VIScopyfixup_ret
- add %o2, %g3, %o0
+ add %o2, %g3, %o1
#endif
#ifdef __KERNEL__
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
index 81b020c49..a370bdff3 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ b/arch/sparc64/lib/VIScsum.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
+/* $Id: VIScsum.S,v 1.3 1998/06/12 14:53:57 jj Exp $
* VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -26,6 +26,7 @@
#ifdef __KERNEL__
#include <asm/head.h>
#include <asm/asi.h>
+#include <asm/visasm.h>
#else
#define ASI_BLK_P 0xf0
#define FRPS_FEF 0x04
@@ -278,13 +279,13 @@ csum_partial:
add %o2, 1, %o2 /* IEU0 */
3: cmp %o1, 0xc0 /* IEU1 Group */
blu,pn %icc, 20f /* CTI */
- sllx %o2, 32, %g1 /* IEU0 */
- addcc %o2, %g1, %o2 /* IEU1 Group */
- sub %o1, 0xc0, %o1 /* IEU0 */
- wr %g0, ASI_BLK_P, %asi /* LSU Group */
+ sllx %o2, 32, %g5 /* IEU0 */
#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs /* LSU Group */
+ VISEntry
#endif
+ addcc %o2, %g5, %o2 /* IEU1 Group */
+ sub %o1, 0xc0, %o1 /* IEU0 */
+ wr %g0, ASI_BLK_P, %asi /* LSU Group */
membar #StoreLoad /* LSU Group */
srlx %o2, 32, %o2 /* IEU0 Group */
bcs,a,pn %xcc, 1f /* CTI */
@@ -340,7 +341,7 @@ csum_partial:
END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
and %o1, 0x3f, %o1 /* IEU0 Group */
#ifdef __KERNEL__
- wr %g0, 0, %fprs /* LSU Group */
+ VISExit
#endif
20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
be,pn %icc, 23f /* CTI */
diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
index fff41bab2..469b007fc 100644
--- a/arch/sparc64/lib/VIScsumcopy.S
+++ b/arch/sparc64/lib/VIScsumcopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsumcopy.S,v 1.4 1998/04/01 08:29:52 davem Exp $
+/* $Id: VIScsumcopy.S,v 1.5 1998/06/12 14:53:48 jj Exp $
* VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
* copying utilizing the UltraSparc Visual Instruction Set.
*
@@ -27,6 +27,7 @@
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/page.h>
+#include <asm/visasm.h>
#else
#define ASI_P 0x80
#define ASI_BLK_P 0xf0
@@ -42,11 +43,11 @@
#define sum o3
#define x1 g1
#define x2 g2
-#define x3 g3
+#define x3 o4
#define x4 g4
#define x5 g5
#define x6 g7
-#define x7 o4
+#define x7 g3
#define x8 o5
/* Dobrou noc, SunSoft engineers. Spete sladce.
@@ -248,7 +249,7 @@
csum_partial_copy_vis:
andcc %dst, 7, %g0 /* IEU1 Group */
be,pt %icc, 4f /* CTI */
- and %dst, 0x38, %g3 /* IEU0 */
+ and %dst, 0x38, %o4 /* IEU0 */
mov 1, %g5 /* IEU0 Group */
andcc %dst, 2, %g0 /* IEU1 */
be,pt %icc, 1f /* CTI */
@@ -266,18 +267,18 @@ csum_partial_copy_vis:
add %sum, %g5, %sum /* IEU0 */
1: lduwa [%src] %asi, %g2 /* Load */
brz,a,pn %g7, 4f /* CTI+IEU1 Group */
- and %dst, 0x38, %g3 /* IEU0 */
+ and %dst, 0x38, %o4 /* IEU0 */
add %dst, 4, %dst /* IEU0 Group */
sub %len, 4, %len /* IEU1 */
addcc %g2, %sum, %sum /* IEU1 Group */
bcs,a,pn %icc, 1f /* CTI */
add %sum, 1, %sum /* IEU0 */
-1: and %dst, 0x38, %g3 /* IEU0 Group */
+1: and %dst, 0x38, %o4 /* IEU0 Group */
stw %g2, [%dst - 4] /* Store */
add %src, 4, %src /* IEU1 */
4:
#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs /* LSU Group */
+ VISEntry
#endif
mov %src, %g7 /* IEU1 Group */
fzero %f48 /* FPA */
@@ -291,10 +292,10 @@ csum_partial_copy_vis:
sub %sum, 1, %sum /* IEU0 */
1: srl %sum, 0, %sum /* IEU0 Group */
clr %g5 /* IEU1 */
- brz,pn %g3, 3f /* CTI+IEU1 Group */
- sub %g1, %g3, %g1 /* IEU0 */
+ brz,pn %o4, 3f /* CTI+IEU1 Group */
+ sub %g1, %o4, %g1 /* IEU0 */
ldda [%src] %asi, %f0 /* Load */
- clr %g3 /* IEU0 Group */
+ clr %o4 /* IEU0 Group */
andcc %dst, 8, %g0 /* IEU1 */
be,pn %icc, 1f /* CTI */
ldda [%src + 8] %asi, %f2 /* Load Group */
@@ -303,7 +304,7 @@ csum_partial_copy_vis:
fpadd32 %f0, %f48, %f50 /* FPA */
addcc %dst, 8, %dst /* IEU1 Group */
faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %g3 /* FPM Group */
+ fcmpgt32 %f48, %f50, %o4 /* FPM Group */
fmovd %f2, %f0 /* FPA Group */
ldda [%src + 8] %asi, %f2 /* Load */
std %f16, [%dst - 8] /* Store */
@@ -318,13 +319,13 @@ csum_partial_copy_vis:
faligndata %f0, %f2, %f16 /* FPA */
fcmpgt32 %f48, %f50, %g5 /* FPM Group */
sub %len, 16, %len /* IEU0 */
- inc %g3 /* IEU1 */
+ inc %o4 /* IEU1 */
std %f16, [%dst - 16] /* Store Group */
fpadd32 %f2, %f50, %f48 /* FPA */
- srl %g3, 1, %o5 /* IEU0 */
+ srl %o4, 1, %o5 /* IEU0 */
faligndata %f2, %f4, %f18 /* FPA Group */
std %f18, [%dst - 8] /* Store */
- fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
add %o5, %sum, %sum /* IEU0 */
ldda [%src + 8] %asi, %f2 /* Load */
fmovd %f4, %f0 /* FPA */
@@ -337,18 +338,18 @@ csum_partial_copy_vis:
add %dst, 32, %dst /* IEU1 */
faligndata %f0, %f2, %f16 /* FPA */
fcmpgt32 %f48, %f50, %o5 /* FPM Group */
- inc %g3 /* IEU0 */
+ inc %o4 /* IEU0 */
ldda [%src + 24] %asi, %f6 /* Load */
- srl %g3, 1, %g3 /* IEU0 Group */
+ srl %o4, 1, %o4 /* IEU0 Group */
add %g5, %sum, %sum /* IEU1 */
ldda [%src + 32] %asi, %f8 /* Load */
fpadd32 %f2, %f50, %f48 /* FPA */
faligndata %f2, %f4, %f18 /* FPA Group */
sub %len, 32, %len /* IEU0 */
std %f16, [%dst - 32] /* Store */
- fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
inc %o5 /* IEU0 */
- add %g3, %sum, %sum /* IEU1 */
+ add %o4, %sum, %sum /* IEU1 */
fpadd32 %f4, %f48, %f50 /* FPA */
faligndata %f4, %f6, %f20 /* FPA Group */
srl %o5, 1, %o5 /* IEU0 */
@@ -356,14 +357,14 @@ csum_partial_copy_vis:
add %o5, %sum, %sum /* IEU0 */
std %f18, [%dst - 24] /* Store */
fpadd32 %f6, %f50, %f48 /* FPA */
- inc %o4 /* IEU0 Group */
+ inc %g3 /* IEU0 Group */
std %f20, [%dst - 16] /* Store */
add %src, 32, %src /* IEU1 */
faligndata %f6, %f8, %f22 /* FPA */
- fcmpgt32 %f50, %f48, %g3 /* FPM Group */
- srl %o4, 1, %o4 /* IEU0 */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ srl %g3, 1, %g3 /* IEU0 */
std %f22, [%dst - 8] /* Store */
- add %o4, %sum, %sum /* IEU0 Group */
+ add %g3, %sum, %sum /* IEU0 Group */
3: rd %asi, %g2 /* LSU Group + 4 bubbles */
#ifdef __KERNEL__
4: sethi %hi(vis0s), %g7 /* IEU0 Group */
@@ -371,16 +372,16 @@ csum_partial_copy_vis:
4: rd %pc, %g7 /* LSU Group + 4 bubbles */
#endif
inc %g5 /* IEU0 Group */
- and %src, 0x38, %o4 /* IEU1 */
+ and %src, 0x38, %g3 /* IEU1 */
membar #StoreLoad /* LSU Group */
srl %g5, 1, %g5 /* IEU0 */
- inc %g3 /* IEU1 */
- sll %o4, 8, %o4 /* IEU0 Group */
+ inc %o4 /* IEU1 */
+ sll %g3, 8, %g3 /* IEU0 Group */
sub %len, 0xc0, %len /* IEU1 */
addcc %g5, %sum, %sum /* IEU1 Group */
- srl %g3, 1, %g3 /* IEU0 */
- add %g7, %o4, %g7 /* IEU0 Group */
- add %g3, %sum, %sum /* IEU1 */
+ srl %o4, 1, %o4 /* IEU0 */
+ add %g7, %g3, %g7 /* IEU0 Group */
+ add %o4, %sum, %sum /* IEU1 */
#ifdef __KERNEL__
jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
#else
@@ -815,7 +816,7 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */
END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
membar #Sync /* LSU Group */
#ifdef __KERNEL__
- wr %g0, 0, %fprs /* LSU Group */
+ VISExit
add %sp, 8, %sp /* IEU0 Group */
#endif
23: brnz,pn %len, 26f /* CTI+IEU1 Group */
@@ -834,12 +835,12 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */
#endif
26: andcc %len, 8, %g0 /* IEU1 Group */
be,pn %icc, 1f /* CTI */
- lduwa [%src] %asi, %g3 /* Load */
+ lduwa [%src] %asi, %o4 /* Load */
lduwa [%src+4] %asi, %g2 /* Load Group */
add %src, 8, %src /* IEU0 */
add %dst, 8, %dst /* IEU1 */
- sllx %g3, 32, %g5 /* IEU0 Group */
- stw %g3, [%dst - 8] /* Store */
+ sllx %o4, 32, %g5 /* IEU0 Group */
+ stw %o4, [%dst - 8] /* Store */
or %g5, %g2, %g5 /* IEU0 Group */
stw %g2, [%dst - 4] /* Store */
addcc %g5, %sum, %sum /* IEU1 Group */
@@ -855,11 +856,11 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */
stw %g7, [%dst - 4] /* Store */
1: andcc %len, 2, %g0 /* IEU1 */
be,a,pn %icc, 1f /* CTI */
- clr %o4 /* IEU0 Group */
+ clr %g3 /* IEU0 Group */
lduha [%src] %asi, %g7 /* Load */
add %src, 2, %src /* IEU1 */
add %dst, 2, %dst /* IEU0 Group */
- sll %g7, 16, %o4 /* IEU0 Group */
+ sll %g7, 16, %g3 /* IEU0 Group */
sth %g7, [%dst - 2] /* Store */
1: andcc %len, 1, %g0 /* IEU1 */
be,a,pn %icc, 1f /* CTI */
@@ -867,9 +868,9 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */
lduba [%src] %asi, %g7 /* Load */
sll %g7, 8, %o5 /* IEU0 Group */
stb %g7, [%dst] /* Store */
-1: or %g2, %o4, %o4 /* IEU1 */
- or %o5, %o4, %o4 /* IEU0 Group (regdep) */
- addcc %o4, %sum, %sum /* IEU1 Group (regdep) */
+1: or %g2, %g3, %g3 /* IEU1 */
+ or %o5, %g3, %g3 /* IEU0 Group (regdep) */
+ addcc %g3, %sum, %sum /* IEU1 Group (regdep) */
bcs,a,pn %xcc, 1f /* CTI */
add %sum, 1, %sum /* IEU0 */
1: ba,pt %xcc, 25b /* CTI Group */
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
index 4c24931ba..9be111134 100644
--- a/arch/sparc64/lib/VISmemset.S
+++ b/arch/sparc64/lib/VISmemset.S
@@ -1,4 +1,4 @@
-/* $Id: VISmemset.S,v 1.7 1997/08/22 15:54:56 jj Exp $
+/* $Id: VISmemset.S,v 1.8 1998/06/12 14:53:59 jj Exp $
* VISmemset.S: High speed memset operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -32,6 +32,9 @@
#endif
#ifdef __KERNEL__
+
+#include <asm/visasm.h>
+
#define RETL clr %o0
#else
#define RETL mov %g3, %o0
@@ -135,8 +138,9 @@ memset:
#endif
add %o0, 32, %o0
7: be,pn %xcc, 9f
+ nop
#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs
+ VISEntryHalf
#endif
ldd [%o0 - 8], %f0
18: wr %g0, ASI_BLK_P, %asi
@@ -170,7 +174,7 @@ memset:
add %o0, 256, %o0
12:
#ifdef __KERNEL__
- wr %g0, 0, %fprs
+ VISExitHalf
#else
#ifndef REGS_64BIT
wr %g0, FPRS_FEF, %fprs
@@ -231,10 +235,9 @@ memset:
#endif
andncc %o2, 0x3f, %o3
be,pn %xcc, 9b
-#ifdef __KERNEL__
- wr %g0, FPRS_FEF, %fprs
-#else
nop
+#ifdef __KERNEL__
+ VISEntryHalf
#endif
ba,pt %xcc, 18b
ldd [%o0], %f0
diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S
new file mode 100644
index 000000000..10d127bb5
--- /dev/null
+++ b/arch/sparc64/lib/VISsave.S
@@ -0,0 +1,122 @@
+/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $
+ * VISsave.S: Code for saving FPU register state for
+ * VIS routines. One should not call this directly,
+ * but use macros provided in <asm/visasm.h>.
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/visasm.h>
+
+ .text
+ .globl VISenter, VISenterhalf
+
+ /* On entry: %o5=current FPRS value, %g7 is callers address */
+ /* May clobber %o5, %g1, %g2, %g3, %g7, %icc, %xcc */
+
+ .align 32
+VISenter:
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1
+ brnz,a,pn %g1, 1f
+ cmp %g1, 1
+ stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+ stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+9: jmpl %g7 + %g0, %g0
+ nop
+1: bne,pn %icc, 2f
+
+ srl %g1, 1, %g1
+vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
+ stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+ or %g3, %o5, %g3
+ stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+ rd %gsr, %g3
+ clr %g1
+ ba,pt %xcc, 3f
+
+ stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr]
+2: add %g6, %g1, %g3
+ cmp %o5, FPRS_DU
+ be,pn %icc, 6f
+ sll %g1, 3, %g1
+ stb %o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+ rd %gsr, %g2
+ stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr]
+
+ add %g6, %g1, %g2
+ stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr]
+ sll %g1, 5, %g1
+3: andcc %o5, FPRS_DL|FPRS_DU, %g0
+ be,pn %icc, 9b
+ add %g6, AOFF_task_fpregs, %g2
+ andcc %o5, FPRS_DL, %g0
+ membar #StoreStore | #LoadStore
+
+ be,pn %icc, 4f
+ add %g6, AOFF_task_fpregs+0x40, %g3
+ stda %f0, [%g2 + %g1] ASI_BLK_P
+ stda %f16, [%g3 + %g1] ASI_BLK_P
+ andcc %o5, FPRS_DU, %g0
+ be,pn %icc, 5f
+4: add %g1, 128, %g1
+ stda %f32, [%g2 + %g1] ASI_BLK_P
+
+ stda %f48, [%g3 + %g1] ASI_BLK_P
+5: membar #Sync
+ jmpl %g7 + %g0, %g0
+ nop
+
+6: ldub [%g3 + AOFF_task_tss + AOFF_thread_fpsaved], %o5
+ or %o5, FPRS_DU, %o5
+ add %g6, AOFF_task_fpregs+0x80, %g2
+ stb %o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+
+ sll %g1, 5, %g1
+ add %g6, AOFF_task_fpregs+0xc0, %g3
+ membar #StoreStore | #LoadStore
+ stda %f32, [%g2 + %g1] ASI_BLK_P
+ stda %f48, [%g3 + %g1] ASI_BLK_P
+ membar #Sync
+ jmpl %g7 + %g0, %g0
+ nop
+
+ .align 32
+VISenterhalf:
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1
+ brnz,a,pn %g1, 1f
+ cmp %g1, 1
+ stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+ stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+ clr %o5
+ jmpl %g7 + %g0, %g0
+ wr %g0, FPRS_FEF, %fprs
+
+1: bne,pn %icc, 2f
+ srl %g1, 1, %g1
+ ba,pt %xcc, vis1
+ sub %g7, 8, %g7
+2: addcc %g6, %g1, %g3
+ sll %g1, 3, %g1
+ andn %o5, FPRS_DU, %g2
+ stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved]
+
+ rd %gsr, %g2
+ stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr]
+ add %g6, %g1, %g2
+ stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr]
+ sll %g1, 5, %g1
+3: andcc %o5, FPRS_DL, %g0
+ be,pn %icc, 4f
+ add %g6, AOFF_task_fpregs, %g2
+
+ membar #StoreStore | #LoadStore
+ add %g6, AOFF_task_fpregs+0x40, %g3
+ stda %f0, [%g2 + %g1] ASI_BLK_P
+ stda %f16, [%g3 + %g1] ASI_BLK_P
+ membar #Sync
+4: and %o5, FPRS_DU, %o5
+ jmpl %g7 + %g0, %g0
+ wr %o5, FPRS_FEF, %fprs
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index 7d5b240ad..c57f0aefc 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,52 +1,66 @@
-/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
- * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
+/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $
+ * blockops.S: UltraSparc block zero optimized routines.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include "VIS.h"
+#include <asm/visasm.h>
+
+#define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \
+ fmovd %reg0, %f48; fmovd %reg1, %f50; \
+ fmovd %reg2, %f52; fmovd %reg3, %f54; \
+ fmovd %reg4, %f56; fmovd %reg5, %f58; \
+ fmovd %reg6, %f60; fmovd %reg7, %f62;
.text
.align 32
-
- .globl __bfill64
-__bfill64: /* %o0 = buf, %o1= ptr to pattern */
- wr %g0, FPRS_FEF, %fprs ! FPU Group
- ldd [%o1], %f48 ! Load Group
- wr %g0, ASI_BLK_P, %asi ! LSU Group
- membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
- mov 32, %g2 ! IEU0 Group
-
- /* Cannot perform real arithmatic on the pattern, that can
- * lead to fp_exception_other ;-)
- */
- fmovd %f48, %f50 ! FPA Group
- fmovd %f48, %f52 ! FPA Group
- fmovd %f48, %f54 ! FPA Group
- fmovd %f48, %f56 ! FPA Group
- fmovd %f48, %f58 ! FPA Group
- fmovd %f48, %f60 ! FPA Group
- fmovd %f48, %f62 ! FPA Group
-
-1: stda %f48, [%o0 + 0x00] %asi ! Store Group
- stda %f48, [%o0 + 0x40] %asi ! Store Group
- stda %f48, [%o0 + 0x80] %asi ! Store Group
- stda %f48, [%o0 + 0xc0] %asi ! Store Group
- subcc %g2, 1, %g2 ! IEU1 Group
- bne,pt %icc, 1b ! CTI
- add %o0, 0x100, %o0 ! IEU0
- membar #StoreLoad | #StoreStore ! LSU Group
-
- jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
- wr %g0, 0, %fprs ! FPU Group
+ .globl copy_page
+ .type copy_page,@function
+copy_page: /* %o0=dest, %o1=src */
+ VISEntry
+ membar #LoadStore | #StoreStore | #StoreLoad
+ ldda [%o1] ASI_BLK_P, %f0
+ add %o1, 0x40, %o1
+ ldda [%o1] ASI_BLK_P, %f16
+ add %o1, 0x40, %o1
+ sethi %hi(8192), %o2
+1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
+ ldda [%o1] ASI_BLK_P, %f32
+ add %o1, 0x40, %o1
+ sub %o2, 0x40, %o2
+ stda %f48, [%o0] ASI_BLK_P
+ add %o0, 0x40, %o0
+ TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
+ ldda [%o1] ASI_BLK_P, %f0
+ add %o1, 0x40, %o1
+ sub %o2, 0x40, %o2
+ stda %f48, [%o0] ASI_BLK_P
+ add %o0, 0x40, %o0
+ TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
+ ldda [%o1] ASI_BLK_P, %f16
+ add %o1, 0x40, %o1
+ sub %o2, 0x40, %o2
+ stda %f48, [%o0] ASI_BLK_P
+ cmp %o2, 0x80
+ bne,pt %xcc, 1b
+ add %o0, 0x40, %o0
+ membar #Sync
+ stda %f0, [%o0] ASI_BLK_P
+ add %o0, 0x40, %o0
+ stda %f16, [%o0] ASI_BLK_P
+ membar #StoreStore | #StoreLoad
+ jmpl %o7 + 0x8, %g0
+ VISExit
.align 32
.globl __bzero_1page
-__bzero_1page:
- wr %g0, FPRS_FEF, %fprs ! FPU Group
+ .type __bzero_1page,@function
+__bzero_1page: /* %o0=dest */
+ VISEntryHalf
fzero %f0 ! FPA Group
- mov 32, %g1 ! IEU0
+ mov 32, %o1 ! IEU0
fzero %f2 ! FPA Group
faddd %f0, %f2, %f4 ! FPA Group
fmuld %f0, %f2, %f6 ! FPM
@@ -62,9 +76,9 @@ __bzero_1page:
stda %f0, [%o0 + 0x80] %asi ! Store Group
stda %f0, [%o0 + 0xc0] %asi ! Store Group
- subcc %g1, 1, %g1 ! IEU1
+ subcc %o1, 1, %o1 ! IEU1
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0 Group
- membar #StoreLoad | #StoreStore ! LSU Group
+ membar #StoreStore | #StoreLoad ! LSU Group
jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
- wr %g0, 0, %fprs ! FPU Group
+ VISExitHalf
diff --git a/arch/sparc64/lib/memscan.S b/arch/sparc64/lib/memscan.S
index 83abe4040..423bc1409 100644
--- a/arch/sparc64/lib/memscan.S
+++ b/arch/sparc64/lib/memscan.S
@@ -1,116 +1,129 @@
-/* $Id: memscan.S,v 1.1 1997/03/14 21:04:24 jj Exp $
- * memscan.S: Optimized memscan for the Sparc64.
+/* $Id: memscan.S,v 1.2 1998/05/21 14:42:22 jj Exp $
+ * memscan.S: Optimized memscan for Sparc64.
*
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
*/
-/* In essence, this is just a fancy strlen. */
-
-#define LO_MAGIC 0x01010101
-#define HI_MAGIC 0x80808080
+#define HI_MAGIC 0x8080808080808080
+#define LO_MAGIC 0x0101010101010101
+#define ASI_PL 0x88
.text
- .align 4
- .globl __memscan_zero, __memscan_generic
- .globl memscan
+ .align 32
+ .globl __memscan_zero, __memscan_generic
+ .globl memscan
+
__memscan_zero:
- /* %o0 = addr, %o1 = size */
- brlez,pn %o1, 0f
- andcc %o0, 3, %g0
- be,pt %icc, 9f
- sethi %hi(HI_MAGIC), %o4
- ldub [%o0], %o5
- subcc %o1, 1, %o1
- brz,pn %o5, 10f
- add %o0, 1, %o0
- be,pn %xcc, 0f
- andcc %o0, 3, %g0
- be,pn %icc, 4f
- or %o4, %lo(HI_MAGIC), %o3
- ldub [%o0], %o5
- subcc %o1, 1, %o1
- brz,pn %o5, 10f
- add %o0, 1, %o0
- be,pn %xcc, 0f
- andcc %o0, 3, %g0
- be,pt %icc, 5f
- sethi %hi(LO_MAGIC), %o4
- ldub [%o0], %o5
- subcc %o1, 1, %o1
- brz,pn %o5, 10f
- add %o0, 1, %o0
- be,pn %xcc, 0f
- or %o4, %lo(LO_MAGIC), %o2
- ba,pt %xcc, 2f
- ld [%o0], %o5
-9:
- or %o4, %lo(HI_MAGIC), %o3
-4:
- sethi %hi(LO_MAGIC), %o4
-5:
- or %o4, %lo(LO_MAGIC), %o2
- ld [%o0], %o5
-2:
- sub %o5, %o2, %o4
- sub %o1, 4, %o1
- andcc %o4, %o3, %g0
- be,pn %icc, 1f
- add %o0, 4, %o0
- brgz,pt %o1, 2b
- ld [%o0], %o5
+ /* %o0 = bufp, %o1 = size */
+ brlez,pn %o1, szzero
+ andcc %o0, 7, %g0
+ be,pt %icc, we_are_aligned
+ sethi %hi(HI_MAGIC), %o4
+ ldub [%o0], %o5
+1: subcc %o1, 1, %o1
+ brz,pn %o5, 10f
+ add %o0, 1, %o0
+ be,pn %xcc, szzero
+ andcc %o0, 7, %g0
+ bne,a,pn %icc, 1b
+ ldub [%o0], %o5
+we_are_aligned:
+ ldxa [%o0] ASI_PL, %o5
+ or %o4, %lo(HI_MAGIC), %o3
+ sllx %o3, 32, %o4
+ or %o4, %o3, %o3
+
+ srlx %o3, 7, %o2
+msloop:
+ sub %o1, 8, %o1
+ add %o0, 8, %o0
+ sub %o5, %o2, %o4
+ xor %o4, %o5, %o4
+ andcc %o4, %o3, %g3
+ bne,pn %xcc, check_bytes
+ srlx %o4, 32, %g3
+
+ brgz,a,pt %o1, msloop
+ ldxa [%o0] ASI_PL, %o5
+check_bytes:
+ bne,a,pn %icc, 2f
+ andcc %o5, 0xff, %g0
+ add %o0, -5, %g2
+ ba,pt %xcc, 3f
+ srlx %o5, 32, %g5
+
+2: srlx %o5, 8, %g5
+ be,pn %icc, 1f
+ add %o0, -8, %g2
+ andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g5, 0xff, %g0
+
+ srlx %g5, 8, %g5
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g3, %o3, %g0
+
+ be,a,pn %icc, 2f
+ mov %o0, %g2
+3: andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+ be,pn %icc, 1f
+ inc %g2
+ andcc %g5, 0xff, %g0
+ srlx %g5, 8, %g5
+
+ be,pn %icc, 1f
+ inc %g2
+2: brgz,a,pt %o1, msloop
+ ldxa [%o0] ASI_PL, %o5
+ inc %g2
+1: add %o0, %o1, %o0
+ cmp %g2, %o0
retl
- add %o0, %o1, %o0
-1:
- /* Check every byte. */
- srl %o5, 24, %g5
- andcc %g5, 0xff, %g0
- be,pn %icc, 1f
- add %o0, -4, %o4
- srl %o5, 16, %g5
- andcc %g5, 0xff, %g0
- be,pn %icc, 1f
- add %o4, 1, %o4
- srl %o5, 8, %g5
- andcc %g5, 0xff, %g0
- be,pn %icc, 1f
- add %o4, 1, %o4
- andcc %o5, 0xff, %g0
- be,pn %icc, 1f
- add %o4, 1, %o4
- brgz,pt %o1, 2b
- ld [%o0], %o5
-1:
- add %o0, %o1, %o0
- cmp %o4, %o0
- retl
- movle %xcc, %o4, %o0
-0:
- retl
+
+ movle %xcc, %g2, %o0
+10: retl
+ sub %o0, 1, %o0
+szzero: retl
nop
-10:
- retl
- sub %o0, 1, %o0
memscan:
__memscan_generic:
/* %o0 = addr, %o1 = c, %o2 = size */
- brz,pn %o2, 3f
- add %o0, %o2, %o3
- ldub [%o0], %o5
- sub %g0, %o2, %o4
+ brz,pn %o2, 3f
+ add %o0, %o2, %o3
+ ldub [%o0], %o5
+ sub %g0, %o2, %o4
1:
- cmp %o5, %o1
- be,pn %icc, 2f
- addcc %o4, 1, %o4
- bne,a,pt %xcc, 1b
- ldub [%o3 + %o4], %o5
+ cmp %o5, %o1
+ be,pn %icc, 2f
+ addcc %o4, 1, %o4
+ bne,a,pt %xcc, 1b
+ ldub [%o3 + %o4], %o5
retl
/* The delay slot is the same as the next insn, this is just to make it look more awful */
2:
- add %o3, %o4, %o0
+ add %o3, %o4, %o0
retl
- sub %o0, 1, %o0
+ sub %o0, 1, %o0
3:
retl
nop
diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c
index e0380720f..5a71804b9 100644
--- a/arch/sparc64/math-emu/math.c
+++ b/arch/sparc64/math-emu/math.c
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.4 1998/04/06 16:09:57 jj Exp $
+/* $Id: math.c,v 1.5 1998/06/12 14:54:27 jj Exp $
* arch/sparc64/math-emu/math.c
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -122,59 +122,57 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
if (type) {
void *rs1 = NULL, *rs2 = NULL, *rd = NULL;
- freg = (f->fsr >> 14) & 0xf;
+ freg = (current->tss.xfsr[0] >> 14) & 0xf;
if (freg != (type >> 8))
goto err;
- f->fsr &= ~0x1c000;
+ current->tss.xfsr[0] &= ~0x1c000;
freg = ((insn >> 14) & 0x1f);
switch (type & 0x3) {
case 3: if (freg & 2) {
- f->fsr |= (6 << 14) /* invalid_fp_register */;
+ current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
goto err;
}
case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
case 1: rs1 = (void *)&f->regs[freg];
- flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
- if (!(current->tss.flags & flags))
- rs1 = (void *)&zero;
+ flags = (freg < 32) ? FPRS_DL : FPRS_DU;
+ if (!(current->tss.fpsaved[0] & flags))
+ rs1 = (void *)&zero;
break;
}
freg = (insn & 0x1f);
switch ((type >> 2) & 0x3) {
case 3: if (freg & 2) {
- f->fsr |= (6 << 14) /* invalid_fp_register */;
+ current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
goto err;
}
case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
case 1: rs2 = (void *)&f->regs[freg];
- flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
- if (!(current->tss.flags & flags))
+ flags = (freg < 32) ? FPRS_DL : FPRS_DU;
+ if (!(current->tss.fpsaved[0] & flags))
rs2 = (void *)&zero;
break;
}
freg = ((insn >> 25) & 0x1f);
switch ((type >> 4) & 0x3) {
- case 0: rd = (void *)(((long)&f->fsr) | (freg & 3)); break;
+ case 0: rd = (void *)(((long)&current->tss.xfsr[0]) | (freg & 3)); break;
case 3: if (freg & 2) {
- f->fsr |= (6 << 14) /* invalid_fp_register */;
+ current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
goto err;
}
case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
case 1: rd = (void *)&f->regs[freg];
- flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
- regs->fprs |= FPRS_FEF;
- if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) {
- current->tss.flags |= SPARC_FLAG_USEDFPU;
- f->fsr = 0;
- f->gsr = 0;
+ flags = (freg < 32) ? FPRS_DL : FPRS_DU;
+ if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
+ current->tss.fpsaved[0] = FPRS_FEF;
+ current->tss.gsr[0] = 0;
}
- if (!(current->tss.flags & flags)) {
+ if (!(current->tss.fpsaved[0] & flags)) {
if (freg < 32)
memset(f->regs, 0, 32*sizeof(u32));
else
memset(f->regs+32, 0, 32*sizeof(u32));
}
- current->tss.flags |= flags;
+ current->tss.fpsaved[0] |= flags;
break;
}
func(rd, rs2, rs1);
diff --git a/arch/sparc64/math-emu/op-common.h b/arch/sparc64/math-emu/op-common.h
index d4ce104f6..ac49cd6c2 100644
--- a/arch/sparc64/math-emu/op-common.h
+++ b/arch/sparc64/math-emu/op-common.h
@@ -83,8 +83,17 @@ do { \
{ \
_FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
_FP_ROUND(wc, X); \
- X##_e = _FP_FRAC_OVERP_##wc(fs, X); \
- _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
+ _FP_FRAC_SLL_##wc(X, 1); \
+ if (_FP_FRAC_OVERP_##wc(fs, X)) \
+ { \
+ X##_e = 1; \
+ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
+ } \
+ else \
+ { \
+ X##_e = 0; \
+ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \
+ } \
} \
else \
{ \
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
index 72f4fa079..a7448f1db 100644
--- a/arch/sparc64/mm/Makefile
+++ b/arch/sparc64/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $
+# $Id: Makefile,v 1.5 1998/07/26 03:02:54 davem Exp $
# Makefile for the linux Sparc64-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -7,24 +7,12 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-ifdef SMP
-
.S.s:
$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
-else
-
-.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-
-.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
-endif
-
O_TARGET := mm.o
O_OBJS := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c
index ae7e3233c..9308e41fc 100644
--- a/arch/sparc64/mm/asyncd.c
+++ b/arch/sparc64/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.3 1997/12/11 15:15:58 jj Exp $
+/* $Id: asyncd.c,v 1.4 1998/05/24 02:53:58 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -108,7 +108,7 @@ void async_fault(unsigned long address, int write, int taskid,
static int fault_in_page(int taskid,
struct vm_area_struct *vma,
- unsigned address,int write)
+ unsigned long address, int write)
{
static unsigned last_address;
static int last_task, loop_counter;
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index e7d863997..035b023fc 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.71 1998/03/27 07:00:08 davem Exp $
+/* $Id: init.c,v 1.93 1998/08/04 20:49:25 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,8 @@
#include <linux/config.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
#include <linux/blk.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
@@ -34,27 +36,54 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
/* Ugly, but necessary... -DaveM */
unsigned long phys_base;
-unsigned int null_pte_table;
-unsigned long two_null_pmd_table, two_null_pte_table;
-
-extern unsigned long empty_null_pmd_table;
-extern unsigned long empty_null_pte_table;
unsigned long tlb_context_cache = CTX_FIRST_VERSION;
/* References to section boundaries */
extern char __init_begin, __init_end, etext, __bss_start;
-extern void __bfill64(void *, unsigned long *);
-
-static __inline__ void __init_pmd(pmd_t *pmdp)
-{
- __bfill64((void *)pmdp, &two_null_pte_table);
-}
-
-static __inline__ void __init_pgd(pgd_t *pgdp)
+int do_check_pgt_cache(int low, int high)
{
- __bfill64((void *)pgdp, &two_null_pmd_table);
+ struct page *page, *page2;
+ int freed = 0;
+
+ if(pgtable_cache_size > high) {
+ do {
+#ifdef __SMP__
+ if(pgd_quicklist)
+ free_pgd_slow(get_pgd_fast()), freed++;
+#endif
+ if(pte_quicklist)
+ free_pte_slow(get_pte_fast()), freed++;
+ } while(pgtable_cache_size > low);
+ }
+#ifndef __SMP__
+ if (pgd_cache_size > high / 4) {
+ for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
+ if ((unsigned long)page->pprev_hash == 3) {
+ if (page2)
+ page2->next_hash = page->next_hash;
+ else
+ (struct page *)pgd_quicklist = page->next_hash;
+ page->next_hash = NULL;
+ page->pprev_hash = NULL;
+ pgd_cache_size -= 2;
+ free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ freed++;
+ if (page2)
+ page = page2->next_hash;
+ else
+ page = (struct page *)pgd_quicklist;
+ if (pgd_cache_size <= low / 4)
+ break;
+ continue;
+ }
+ page2 = page;
+ page = page->next_hash;
+ }
+ }
+#endif
+ return freed;
}
/*
@@ -70,21 +99,6 @@ static __inline__ void __init_pgd(pgd_t *pgdp)
* ZERO_PAGE is a special page that is used for zero-initialized
* data and COW.
*/
-pmd_t *__bad_pmd(void)
-{
- pmd_t *pmdp = (pmd_t *) &empty_bad_pmd_table;
-
- __init_pmd(pmdp);
- return pmdp;
-}
-
-pte_t *__bad_pte(void)
-{
- memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE);
- return (pte_t *) (((unsigned long)&empty_bad_pte_table)
- - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET);
-}
-
pte_t __bad_page(void)
{
memset((void *) &empty_bad_page, 0, PAGE_SIZE);
@@ -125,6 +139,9 @@ void show_mem(void)
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
printk("%ld pages in page table cache\n",pgtable_cache_size);
+#ifndef __SMP__
+ printk("%ld entries in page dir cache\n",pgd_cache_size);
+#endif
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
@@ -135,27 +152,47 @@ void show_mem(void)
/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
/* NOTE: All of these are inited to 0 in bss, don't need to make data segment bigger */
-static unsigned long dvma_map_pages[0x10000000 >> 16];
+#define DVMAIO_SIZE 0x2000000
+static unsigned long dvma_map_pages[DVMAIO_SIZE >> 16];
static unsigned long dvma_pages_current_offset;
static int dvma_pages_current_index;
+static unsigned long dvmaiobase = 0;
+static unsigned long dvmaiosz __initdata = 0;
/* #define E3000_DEBUG */
-__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
- unsigned long memory_end, struct linux_sbus *sbus))
+__initfunc(void dvmaio_init(void))
+{
+ int i;
+
+ if (!dvmaiobase) {
+ for (i = 0; sp_banks[i].num_bytes != 0; i++)
+ if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase)
+ dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+ dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1);
+ for (i = 0; i < 6; i++)
+ if (dvmaiobase <= ((1024 * 64 * 1024) << i))
+ break;
+ dvmaiobase = ((1024 * 64 * 1024) << i) - DVMAIO_SIZE;
+ dvmaiosz = i;
+ }
+}
+
+__initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
{
struct iommu_struct *iommu;
struct sysio_regs *sregs;
struct linux_prom64_registers rprop;
unsigned long impl, vers;
unsigned long control, tsbbase;
+ unsigned long tsbbases[32];
unsigned long *iopte;
- u32 rlow, rhigh;
- int err, i;
-
+ int err, i, j;
+
+ dvmaio_init();
#ifdef E3000_DEBUG
- prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
- iommu_node, memory_start, memory_end, sbus);
+ prom_printf("\niommu_init: [%x:%p] ",
+ iommu_node, sbus);
#endif
err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
sizeof(rprop));
@@ -163,14 +200,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
- rlow = (rprop.phys_addr & 0xffffffff);
- rhigh = (rprop.phys_addr >> 32);
-#ifdef E3000_DEBUG
- prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
-#endif
- sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
- sizeof(struct sysio_regs),
- "SYSIO Regs", rhigh, 0x0);
+ sregs = (struct sysio_regs *) __va(rprop.phys_addr);
+
#ifdef E3000_DEBUG
prom_printf("sregs[%p]\n");
#endif
@@ -179,9 +210,7 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
prom_halt();
}
- memory_start = (memory_start + 7) & ~7;
- iommu = (struct iommu_struct *) memory_start;
- memory_start += sizeof(struct iommu_struct);
+ iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
#ifdef E3000_DEBUG
prom_printf("iommu_init: iommu[%p] ", iommu);
@@ -203,26 +232,54 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
(unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
control &= ~(IOMMU_CTRL_TSBSZ);
- control |= (IOMMU_TSBSZ_64K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
/* Use only 64k pages, things are layed out in the 32-bit SBUS
* address space like this:
*
- * 0x00000000 ----------------------------------------
- * | Direct physical mappings for most |
- * | DVMA to paddr's within this range |
- * 0xf0000000 ----------------------------------------
- * | For mappings requested via |
- * | sparc_alloc_dvma() |
- * 0xffffffff ----------------------------------------
- */
- tsbbase = PAGE_ALIGN(memory_start);
- memory_start = (tsbbase + ((64 * 1024) * 8));
+ * 0x00000000 ----------------------------------------
+ * | Direct physical mappings for most |
+ * | DVMA to paddr's within this range |
+ * dvmaiobase ----------------------------------------
+ * | For mappings requested via |
+ * | sparc_alloc_dvma() |
+ * dvmaiobase+32M ----------------------------------------
+ *
+ * NOTE: we need to order 2 contiguous order 5, that's the largest
+ * chunk page_alloc will give us. -JJ */
+ tsbbase = 0;
+ if (dvmaiosz == 6) {
+ memset (tsbbases, 0, sizeof(tsbbases));
+ for (i = 0; i < 32; i++) {
+ tsbbases[i] = __get_free_pages(GFP_DMA, 5);
+ for (j = 0; j < i; j++)
+ if (tsbbases[j] == tsbbases[i] + 32768*sizeof(iopte_t)) {
+ tsbbase = tsbbases[i];
+ break;
+ } else if (tsbbases[i] == tsbbases[j] + 32768*sizeof(iopte_t)) {
+ tsbbase = tsbbases[j];
+ break;
+ }
+ if (tsbbase) {
+ tsbbases[i] = 0;
+ tsbbases[j] = 0;
+ break;
+ }
+ }
+ for (i = 0; i < 32; i++)
+ if (tsbbases[i])
+ free_pages(tsbbases[i], 5);
+ } else
+ tsbbase = __get_free_pages(GFP_DMA, dvmaiosz);
+ if (!tsbbase) {
+ prom_printf("Strange. Could not allocate 512K of contiguous RAM.\n");
+ prom_halt();
+ }
iommu->page_table = (iopte_t *) tsbbase;
iopte = (unsigned long *) tsbbase;
/* Setup aliased mappings... */
- for(i = 0; i < (65536 - 4096); i++) {
+ for(i = 0; i < (dvmaiobase >> 16); i++) {
*iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
@@ -230,7 +287,7 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
}
/* Clear all sparc_alloc_dvma() maps. */
- for( ; i < 65536; i++)
+ for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++)
*iopte++ = 0;
#ifdef E3000_DEBUG
@@ -252,23 +309,19 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
#endif
printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
(unsigned int)impl, (unsigned int)vers);
- printk("FlushFLAG[%p,%016lx] ... ",
- (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
- (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+ iommu->sbuf_flushflag_va = kmalloc(sizeof(unsigned long), GFP_DMA);
+ printk("FlushFLAG[%016lx] ... ", (iommu->sbuf_flushflag_pa = __pa(iommu->sbuf_flushflag_va)));
*(iommu->sbuf_flushflag_va) = 0;
- memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
#ifdef E3000_DEBUG
- prom_printf("done, returning %016lx\n", memory_start);
+ prom_printf("done, returning\n");
#endif
printk("ENABLED\n");
/* Finally enable DVMA arbitration for all devices, just in case. */
sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
-
- return memory_start;
}
void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
@@ -300,7 +353,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
}
/* Stick it in the IOMMU. */
- i = (65536 - 4096) + i;
+ i = (dvmaiobase >> 16) + i;
for_each_sbus(sbus) {
struct iommu_struct *iommu = sbus->iommu;
unsigned long flags;
@@ -314,7 +367,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
}
/* Get this out of the way. */
- *dvma_addr = (__u32) ((0xf0000000) +
+ *dvma_addr = (__u32) ((dvmaiobase) +
(dvma_pages_current_index << 16) +
(dvma_pages_current_offset));
@@ -345,13 +398,17 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
{
__u32 sbus_addr = (__u32) __pa(vaddr);
- if((sbus_addr < 0xf0000000) &&
- ((sbus_addr + len) < 0xf0000000))
+#ifndef DEBUG_IOMMU
+ return sbus_addr;
+#else
+ if((sbus_addr < dvmaiobase) &&
+ ((sbus_addr + len) < dvmaiobase))
return sbus_addr;
/* "can't happen"... GFP_DMA assures this. */
panic("Very high scsi_one mappings should never happen.");
return (__u32)0;
+#endif
}
void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
@@ -385,13 +442,17 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
{
while(sz >= 0) {
__u32 page = (__u32) __pa(((unsigned long) sg[sz].addr));
- if((page < 0xf0000000) &&
- (page + sg[sz].len) < 0xf0000000) {
+#ifndef DEBUG_IOMMU
+ sg[sz].dvma_addr = page;
+#else
+ if((page < dvmaiobase) &&
+ (page + sg[sz].len) < dvmaiobase) {
sg[sz].dvma_addr = page;
} else {
/* "can't happen"... GFP_DMA assures this. */
panic("scsi_sgl high mappings should never happen.");
}
+#endif
sz--;
}
}
@@ -440,35 +501,42 @@ struct linux_prom_translation {
unsigned long data;
};
-#define MAX_TRANSLATIONS 64
static inline void inherit_prom_mappings(void)
{
- struct linux_prom_translation transl[MAX_TRANSLATIONS];
+ struct linux_prom_translation *trans;
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
int node, n, i;
node = prom_finddevice("/virtual-memory");
- if ((n = prom_getproperty(node, "translations", (char *) transl,
- sizeof(transl))) == -1) {
+ n = prom_getproplen(node, "translations");
+ if (n == 0 || n == -1) {
+ prom_printf("Couldn't get translation property\n");
+ prom_halt();
+ }
+
+ for (i = 1; i < n; i <<= 1) /* empty */;
+ trans = sparc_init_alloc(&mempool, i);
+
+ if (prom_getproperty(node, "translations", (char *)trans, i) == -1) {
prom_printf("Couldn't get translation property\n");
prom_halt();
}
- n = n / sizeof(transl[0]);
+ n = n / sizeof(*trans);
for (i = 0; i < n; i++) {
unsigned long vaddr;
- if (transl[i].virt >= 0xf0000000 && transl[i].virt < 0x100000000) {
- for (vaddr = transl[i].virt;
- vaddr < transl[i].virt + transl[i].size;
+ if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) {
+ for (vaddr = trans[i].virt;
+ vaddr < trans[i].virt + trans[i].size;
vaddr += PAGE_SIZE) {
pgdp = pgd_offset(init_task.mm, vaddr);
if (pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool,
PMD_TABLE_SIZE);
- __init_pmd(pmdp);
+ clear_page(pmdp);
pgd_set(pgdp, pmdp);
}
pmdp = pmd_offset(pgdp, vaddr);
@@ -478,17 +546,89 @@ static inline void inherit_prom_mappings(void)
pmd_set(pmdp, ptep);
}
ptep = pte_offset(pmdp, vaddr);
- set_pte (ptep, __pte(transl[i].data | _PAGE_MODIFIED));
- transl[i].data += PAGE_SIZE;
+ set_pte (ptep, __pte(trans[i].data | _PAGE_MODIFIED));
+ trans[i].data += PAGE_SIZE;
}
}
}
}
+/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
+ * upwards as reserved for use by the firmware (I wonder if this
+ * will be the same on Cheetah...). We use this virtual address
+ * range for the VPTE table mappings of the nucleus so we need
+ * to zap them when we enter the PROM. -DaveM
+ */
+static void __flush_nucleus_vptes(void)
+{
+ unsigned long pstate;
+ unsigned long prom_reserved_base = 0xfffffffc00000000UL;
+ int i;
+
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate\n\t"
+ "flushw"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
+
+ /* Only DTLB must be checked for VPTE entries. */
+ for(i = 0; i < 63; i++) {
+ unsigned long tag = spitfire_get_dtlb_tag(i);
+
+ if(((tag & ~(PAGE_MASK)) == 0) &&
+ ((tag & (PAGE_MASK)) >= prom_reserved_base)) {
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
+ : /* no outputs */
+ : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+ membar("#Sync");
+ spitfire_put_dtlb_data(i, 0x0UL);
+ membar("#Sync");
+ }
+ }
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (pstate));
+}
+
+static int prom_ditlb_set = 0;
int prom_itlb_ent, prom_dtlb_ent;
unsigned long prom_itlb_tag, prom_itlb_data;
unsigned long prom_dtlb_tag, prom_dtlb_data;
+void prom_world(int enter)
+{
+ if (!prom_ditlb_set)
+ return;
+ if (enter) {
+ /* Kick out nucleus VPTEs. */
+ __flush_nucleus_vptes();
+
+ /* Install PROM world. */
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
+ "i" (ASI_DMMU));
+ membar("#Sync");
+ spitfire_put_dtlb_data(62, prom_dtlb_data);
+ membar("#Sync");
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
+ "i" (ASI_IMMU));
+ membar("#Sync");
+ spitfire_put_itlb_data(62, prom_itlb_data);
+ membar("#Sync");
+ } else {
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
+ : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+ membar("#Sync");
+ spitfire_put_dtlb_data(62, 0x0UL);
+ membar("#Sync");
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
+ : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+ membar("#Sync");
+ spitfire_put_itlb_data(62, 0x0UL);
+ membar("#Sync");
+ }
+}
+
void inherit_locked_prom_mappings(int save_p)
{
int i;
@@ -500,8 +640,7 @@ void inherit_locked_prom_mappings(int save_p)
* translations property. The only ones that matter are
* the locked PROM tlb entries, so we impose the following
* irrecovable rule on the PROM, it is allowed 1 locked
- * entry in the ITLB and 1 in the DTLB. We move those
- * (if necessary) up into tlb entry 62.
+ * entry in the ITLB and 1 in the DTLB.
*
* Supposedly the upper 16GB of the address space is
* reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
@@ -510,7 +649,7 @@ void inherit_locked_prom_mappings(int save_p)
* systems to coordinate mmu mappings is also COMPLETELY
* UNDOCUMENTED!!!!!! Thanks S(t)un!
*/
- for(i = 0; i < 62; i++) {
+ for(i = 0; i < 63; i++) {
unsigned long data;
data = spitfire_get_dtlb_data(i);
@@ -528,13 +667,6 @@ void inherit_locked_prom_mappings(int save_p)
spitfire_put_dtlb_data(i, 0x0UL);
membar("#Sync");
- /* Re-install it. */
- __asm__ __volatile__("stxa %0, [%1] %2"
- : : "r" (tag), "r" (TLB_TAG_ACCESS),
- "i" (ASI_DMMU));
- membar("#Sync");
- spitfire_put_dtlb_data(62, data);
- membar("#Sync");
dtlb_seen = 1;
if(itlb_seen)
break;
@@ -566,6 +698,8 @@ void inherit_locked_prom_mappings(int save_p)
break;
}
}
+ if (save_p)
+ prom_ditlb_set = 1;
}
/* Give PROM back his world, done during reboots... */
@@ -628,44 +762,76 @@ void __flush_tlb_all(void)
: : "r" (pstate));
}
-/* We are always protected by scheduler_lock under SMP. */
-void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
+#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
+unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
+
+/* We are always protected by scheduler_lock under SMP.
+ * Caller does TLB context flushing on local CPU if necessary.
+ *
+ * We must be careful about boundary cases so that we never
+ * let the user have CTX 0 (nucleus) or we ever use a CTX
+ * version of zero (and thus NO_CONTEXT would not be caught
+ * by version mis-match tests in mmu_context.h).
+ */
+void get_new_mmu_context(struct mm_struct *mm)
{
- unsigned int new_ctx = *ctx;
-
- if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
- new_ctx += CTX_FIRST_VERSION;
- if(new_ctx == 1)
- new_ctx = CTX_FIRST_VERSION;
- *ctx = new_ctx;
- DO_LOCAL_FLUSH(smp_processor_id());
+ unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
+ unsigned long new_ctx;
+
+ if (ctx == 0)
+ ctx = 1;
+ if ((mm->context != NO_CONTEXT) &&
+ !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK))
+ clear_bit(mm->context & ~(CTX_VERSION_MASK), mmu_context_bmap);
+ new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx);
+ if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) {
+ new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
+ if (new_ctx >= ctx) {
+ int i;
+ new_ctx = (tlb_context_cache & CTX_VERSION_MASK) +
+ CTX_FIRST_VERSION;
+ if (new_ctx == 1)
+ new_ctx = CTX_FIRST_VERSION;
+
+ /* Don't call memset, for 16 entries that's just
+ * plain silly...
+ */
+ mmu_context_bmap[0] = 3;
+ mmu_context_bmap[1] = 0;
+ mmu_context_bmap[2] = 0;
+ mmu_context_bmap[3] = 0;
+ for(i = 4; i < CTX_BMAP_SLOTS; i += 4) {
+ mmu_context_bmap[i + 0] = 0;
+ mmu_context_bmap[i + 1] = 0;
+ mmu_context_bmap[i + 2] = 0;
+ mmu_context_bmap[i + 3] = 0;
+ }
+ goto out;
+ }
}
+ set_bit(new_ctx, mmu_context_bmap);
+ new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
+out:
+ tlb_context_cache = new_ctx;
mm->context = new_ctx;
- mm->cpu_vm_mask = 0; /* Callers sets it properly. */
- (*ctx)++;
+ mm->cpu_vm_mask = 0;
}
#ifndef __SMP__
struct pgtable_cache_struct pgt_quicklists;
#endif
-pgd_t *get_pgd_slow(void)
-{
- pgd_t *pgd;
-
- pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
- if(pgd)
- __init_pgd(pgd);
- return pgd;
-}
-
+/* XXX Add __GFP_HIGH to these calls to "fool" page allocator
+ * XXX so we don't go to swap so quickly... then do the same
+ * XXX for get_user_page as well -DaveM
+ */
pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
{
pmd_t *pmd;
pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
if(pmd) {
- __init_pmd(pmd);
+ clear_page(pmd);
pgd_set(pgd, pmd);
return pmd + offset;
}
@@ -678,7 +844,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
if(pte) {
- memset((void *)pte, 0, PTE_TABLE_SIZE);
+ clear_page(pte);
pmd_set(pmd, pte);
return pte + offset;
}
@@ -695,15 +861,14 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end))
while (start < end) {
pgdp = pgd_offset(init_task.mm, start);
if (pgd_none(*pgdp)) {
- pmdp = sparc_init_alloc(&mempool,
- PMD_TABLE_SIZE);
- __init_pmd(pmdp);
+ pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
+ clear_page(pmdp);
pgd_set(pgdp, pmdp);
}
pmdp = pmd_offset(pgdp, start);
if (pmd_none(*pmdp)) {
- ptep = sparc_init_alloc(&mempool,
- PTE_TABLE_SIZE);
+ ptep = sparc_init_alloc(&mempool, PAGE_SIZE);
+ clear_page(ptep);
pmd_set(pmdp, ptep);
}
start = (start + PMD_SIZE) & PMD_MASK;
@@ -733,6 +898,7 @@ void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
set_pte(ptep, pte);
}
+/* XXX no longer used, remove me... -DaveM */
void sparc_ultra_unmapioaddr(unsigned long virt_addr)
{
pgd_t *pgdp;
@@ -747,7 +913,7 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
pte_clear(ptep);
}
-#if NOTUSED
+#ifdef NOTUSED
void sparc_ultra_dump_itlb(void)
{
int slot;
@@ -767,11 +933,11 @@ void sparc_ultra_dump_dtlb(void)
{
int slot;
- printk ("Contents of dtlb: ");
+ prom_printf ("Contents of dtlb: ");
for (slot = 0; slot < 14; slot++) printk (" ");
- printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+ prom_printf ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
for (slot = 1; slot < 64; slot+=3) {
- printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+ prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
@@ -786,16 +952,16 @@ extern unsigned long free_area_init(unsigned long, unsigned long);
__initfunc(unsigned long
paging_init(unsigned long start_mem, unsigned long end_mem))
{
- extern unsigned long phys_base;
- extern void setup_tba(unsigned long kpgdir);
- extern void __bfill64(void *, unsigned long *);
- pmd_t *pmdp;
- int i;
+ extern void setup_tba(void);
+ extern pmd_t swapper_pmd_dir[1024];
+ extern unsigned long irq_init(unsigned long start_mem, unsigned long end_mem);
+ extern unsigned int sparc64_vpte_patchme[1];
unsigned long alias_base = phys_base + PAGE_OFFSET;
unsigned long pt;
unsigned long flags;
unsigned long shift = alias_base - ((unsigned long)&empty_zero_page);
-
+
+ set_bit(0, mmu_context_bmap);
/* We assume physical memory starts at some 4mb multiple,
* if this were not true we wouldn't boot up to this point
* anyways.
@@ -821,44 +987,28 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
* work.
*/
init_mm.pgd += ((shift) / (sizeof(pgd_t)));
-
- /* The funny offsets are to make page table operations much quicker and
- * requite less state, see pgtable.h for gory details.
- * pgtable.h assumes null_pmd_table is null_pte_table - PAGE_SIZE, lets
- * check it now.
- */
- null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
- if (null_pmd_table != __pa(((unsigned long)&empty_null_pmd_table)+shift)) {
- prom_printf("null_p{md|te}_table broken.\n");
- prom_halt();
- }
- two_null_pmd_table = (((unsigned long)null_pmd_table) << 32) | null_pmd_table;
- two_null_pte_table = (((unsigned long)null_pte_table) << 32) | null_pte_table;
-
- pmdp = (pmd_t *) &empty_null_pmd_table;
- for(i = 0; i < PTRS_PER_PMD; i++)
- pmd_val(pmdp[i]) = null_pte_table;
-
- memset((void *) &empty_null_pte_table, 0, PTE_TABLE_SIZE);
+
+ memset(swapper_pmd_dir, 0, sizeof(swapper_pmd_dir));
/* Now can init the kernel/bad page tables. */
- __bfill64((void *)swapper_pg_dir, &two_null_pmd_table);
- __bfill64((void *)&empty_bad_pmd_table, &two_null_pte_table);
+ pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t)));
+
+ sparc64_vpte_patchme[0] |= (init_mm.pgd[0] >> 10);
+
+ start_mem = irq_init(start_mem, end_mem);
/* We use mempool to create page tables, therefore adjust it up
* such that __pa() macros etc. work.
*/
mempool = PAGE_ALIGN(start_mem) + shift;
- /* FIXME: This should be done much nicer.
- * Just now we allocate 64M for each.
- */
- allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000);
+ /* Allocate 64M for dynamic DVMA mapping area. */
allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
inherit_prom_mappings();
+
/* Ok, we can use our TLB miss and window trap handlers safely. */
- setup_tba((unsigned long)init_mm.pgd);
+ setup_tba();
/* Really paranoid. */
flushi((long)&empty_zero_page);
@@ -884,11 +1034,16 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
return device_scan (PAGE_ALIGN (start_mem));
}
+/* XXX Add also PG_Hole flag, set it in the page structs here,
+ * XXX remove FREE_UNUSED_MEM_MAP code, and the nfsd file handle
+ * problems will all be gone. -DaveM
+ */
__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
{
unsigned long tmp = 0, paddr, endaddr;
unsigned long end = __pa(end_mem);
+ dvmaio_init();
for (paddr = __pa(start_mem); paddr < end; ) {
for (; sp_banks[tmp].num_bytes != 0; tmp++)
if (sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes > paddr)
@@ -911,7 +1066,7 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e
endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes;
while (paddr < endaddr) {
mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_reserved);
- if (paddr >= 0xf0000000)
+ if (paddr >= dvmaiobase)
mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_DMA);
paddr += PAGE_SIZE;
}
@@ -926,6 +1081,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
unsigned long addr;
unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page);
struct page *page, *end;
+ int i;
end_mem &= PAGE_MASK;
max_mapnr = MAP_NR(end_mem);
@@ -998,6 +1154,19 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
free_page(addr);
}
+
+#ifndef __SMP__
+ {
+ /* Put empty_pg_dir on pgd_quicklist */
+ extern pgd_t empty_pg_dir[1024];
+ unsigned long addr = (unsigned long)empty_pg_dir;
+
+ memset(empty_pg_dir, 0, sizeof(empty_pg_dir));
+ addr += alias_base;
+ mem_map[MAP_NR(addr)].pprev_hash = 0;
+ free_pgd_fast((pgd_t *)addr);
+ }
+#endif
printk("Memory: %uk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n",
nr_free_pages << (PAGE_SHIFT-10),
@@ -1006,11 +1175,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
initpages << (PAGE_SHIFT-10),
PAGE_OFFSET, end_mem);
- freepages.low = nr_free_pages >> 7;
- if(freepages.low < 48)
- freepages.low = 48;
- freepages.low = freepages.low + (freepages.low >> 1);
- freepages.high = freepages.low + freepages.low;
+ /* NOTE NOTE NOTE NOTE
+ * Please keep track of things and make sure this
+ * always matches the code in mm/page_alloc.c -DaveM
+ */
+ i = nr_free_pages >> 7;
+ if (i < 48)
+ i = 48;
+ if (i > 256)
+ i = 256;
+ freepages.min = i;
+ freepages.low = i << 1;
+ freepages.high = freepages.low + i;
}
void free_initmem (void)
diff --git a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c
index 303b98996..6d68d7468 100644
--- a/arch/sparc64/mm/modutil.c
+++ b/arch/sparc64/mm/modutil.c
@@ -1,4 +1,4 @@
-/* $Id: modutil.c,v 1.3 1998/01/16 16:35:02 jj Exp $
+/* $Id: modutil.c,v 1.4 1998/07/26 06:29:08 davem Exp $
* arch/sparc64/mm/modutil.c
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -35,32 +35,6 @@ void module_unmap (void * addr)
printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
}
-void module_shrink(void * addr, unsigned long size)
-{
- struct vm_struct *tmp;
-
- if (!addr)
- return;
- if ((PAGE_SIZE-1) & (unsigned long) addr) {
- printk("Trying to shrink module with bad address (%p)\n", addr);
- return;
- }
- size = PAGE_ALIGN(size);
- if (!size)
- module_unmap(addr);
- for (tmp = modvmlist; tmp; tmp = tmp->next) {
- if (tmp->addr == addr) {
- if (size > tmp->size - PAGE_SIZE) {
- printk("Trying to expand module with module_shrink()\n");
- return;
- }
- vmfree_area_pages(VMALLOC_VMADDR(tmp->addr)+size, tmp->size-size);
- return;
- }
- }
- printk("Trying to shrink nonexistent module vm area (%p)\n", addr);
-}
-
void * module_map (unsigned long size)
{
void * addr;
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index ea0faa16b..683f4bcb1 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.20 1997/10/03 20:42:46 davem Exp $
+/* $Id: ultra.S,v 1.24 1998/05/22 11:02:56 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,90 +8,119 @@
#include <asm/pgtable.h>
#include <asm/spitfire.h>
- /* All callers check mm->context != NO_CONTEXT for us. */
+ /* This file is meant to be read efficiently by the CPU, not humans.
+ * Staraj sie tego nikomu nie pierdolnac...
+ */
.text
.align 32
- .globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
-__flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */
- mov SECONDARY_CONTEXT, %g7
-9: ldxa [%g7] ASI_DMMU, %g2
+ .globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
+__flush_tlb_page: /* %o0=(ctx & 0x3ff), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
+/*IC1*/ ldxa [%o2] ASI_DMMU, %g2
+ cmp %g2, %o0
+ bne,pn %icc, __flush_tlb_page_slow
+ or %o1, 0x10, %g3
+ stxa %g0, [%g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g3] ASI_IMMU_DEMAP
+ retl
+ flush %g6
+__flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */
+/*IC2*/ ldxa [%o1] ASI_DMMU, %g2
cmp %g2, %o0
- bne,pn %icc, 1f
+ bne,pn %icc, __flush_tlb_mm_slow
mov 0x50, %g3
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
retl
flush %g6
-1: rdpr %pstate, %g1
+__flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
+ * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
+ */
+#define TLB_MAGIC 206 /* Students, do you know how I calculated this? -DaveM */
+/*IC3*/ cmp %o5, %o4
+ be,pt %xcc, __flush_tlb_page
+ srlx %o5, 13, %g5
+ cmp %g5, TLB_MAGIC
+ bgeu,pn %icc, __flush_tlb_range_constant_time
+ or %o1, 0x10, %g5
+ ldxa [%o2] ASI_DMMU, %g2
+ cmp %g2, %o0
+__flush_tlb_range_page_by_page:
+/*IC4*/ bne,pn %icc, __flush_tlb_range_pbp_slow
+ sub %o5, %o4, %o5
+1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
+ stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
+ brnz,pt %o5, 1b
+ sub %o5, %o4, %o5
+ retl
+ flush %g6
+__flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
+/*IC5*/ rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
- stxa %o0, [%g7] ASI_DMMU
+ mov (62 << 3), %g2
+1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4
+ and %o4, 0x3ff, %o5
+ cmp %o5, %o0
+ bne,pt %icc, 2f
+ andn %o4, 0x3ff, %o4
+/*IC6*/ cmp %o4, %o1
+ blu,pt %xcc, 2f
+ cmp %o4, %o3
+ blu,pn %xcc, 4f
+2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4
+ and %o4, 0x3ff, %o5
+ cmp %o5, %o0
+ andn %o4, 0x3ff, %o4
+/*IC7*/ bne,pt %icc, 3f
+ cmp %o4, %o1
+ blu,pt %xcc, 3f
+ cmp %o4, %o3
+ blu,pn %xcc, 5f
+ nop
+3: brnz,pt %g2, 1b
+ sub %g2, (1 << 3), %g2
+/*IC8*/ retl
+ wrpr %g1, 0x0, %pstate
+4: stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS
+ ba,pt %xcc, 2b
+ flush %g6
+5: stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS
+ ba,pt %xcc, 3b
+ flush %g6
+__flush_tlb_mm_slow:
+/*IC9*/ rdpr %pstate, %g1
+ wrpr %g1, PSTATE_IE, %pstate
+ stxa %o0, [%o1] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
flush %g6
- stxa %g2, [%g7] ASI_DMMU
+ stxa %g2, [%o1] ASI_DMMU
flush %g6
- retl
+/*IC10*/retl
wrpr %g1, 0, %pstate
- nop
-__flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
- sethi %hi(8192 - 1), %g5
- or %g5, %lo(8192 - 1), %g5
- andn %o1, %g5, %o1
- andn %o2, %g5, %o2
-
- sub %o2, %o1, %o3
- add %g5, 1, %g5
- orcc %o1, 0x10, %o1
- srlx %o3, 13, %o4
- cmp %o4, 96
- bgu,pn %icc, 9b
- mov SECONDARY_CONTEXT, %g7
- ldxa [%g7] ASI_DMMU, %g2
-
- nop
- nop
- cmp %g2, %o0
- be,pt %icc, 1f
- sub %o3, %g5, %o3
+__flush_tlb_page_slow:
rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
- stxa %o0, [%g7] ASI_DMMU
-
-1: stxa %g0, [%o1 + %o3] ASI_DMMU_DEMAP
- stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP
- brnz,pt %o3, 1b
- sub %o3, %g5, %o3
- flush %g6
- be,pt %icc, 1f
- nop
- stxa %g2, [%g7] ASI_DMMU
-
- flush %g6
- wrpr %g1, 0, %pstate
-1: retl
- nop
-
- .align 32
-__flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
- mov SECONDARY_CONTEXT, %g7
- ldxa [%g7] ASI_DMMU, %g2
- cmp %g2, %o0
- bne,pt %icc, 1f
- or %o1, 0x10, %g3
+ stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
+ flush %g6
+/*IC11*/stxa %g2, [%o2] ASI_DMMU
+ flush %g6
retl
- flush %g6
-1: rdpr %pstate, %g1
+ wrpr %g1, 0, %pstate
+__flush_tlb_range_pbp_slow:
+ rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate
- stxa %o0, [%g7] ASI_DMMU
- stxa %g0, [%g3] ASI_DMMU_DEMAP
- stxa %g0, [%g3] ASI_IMMU_DEMAP
+ stxa %o0, [%o2] ASI_DMMU
+2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
+ stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
+ brnz,pt %o5, 2b
+ sub %o5, %o4, %o5
flush %g6
- stxa %g2, [%g7] ASI_DMMU
+/*IC13*/stxa %g2, [%o2] ASI_DMMU
flush %g6
retl
- wrpr %g1, 0, %pstate
+ wrpr %g1, 0x0, %pstate
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
@@ -106,6 +135,8 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
* %g2 scratch 1
* %g3 scratch 2
* %g4 scratch 3
+ *
+ * TODO: Make xcall TLB range flushes use the tricks above... -DaveM
*/
.align 32
.globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 9720f1a70..8e7ff7700 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $
+/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -33,8 +33,7 @@ prom_feval(char *fstring)
/* We want to do this more nicely some day. */
#ifdef CONFIG_SUN_CONSOLE
-extern void console_restore_palette(void);
-extern void set_palette(void);
+extern void (*prom_palette)(int);
extern int serial_console;
#endif
@@ -52,10 +51,8 @@ prom_cmdline(void)
/* kernel_enter_debugger(); */
#ifdef CONFIG_SUN_CONSOLE
-#if 0
- if(!serial_console)
- console_restore_palette ();
-#endif
+ if(!serial_console && prom_palette)
+ prom_palette (1);
#endif
/* install_obp_ticker(); */
save_flags(flags); cli();
@@ -63,10 +60,8 @@ prom_cmdline(void)
restore_flags(flags);
/* install_linux_ticker(); */
#ifdef CONFIG_SUN_CONSOLE
-#if 0
- if(!serial_console)
- set_palette ();
-#endif
+ if(!serial_console && prom_palette)
+ prom_palette (0);
#endif
}
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index 9c5bce294..722243e99 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
+/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -24,6 +24,8 @@ struct {
char prom_buffer [3000];
} p1275buf;
+extern void prom_world(int);
+
void prom_cif_interface (void)
{
__asm__ __volatile__ ("
@@ -115,7 +117,11 @@ long p1275_cmd (char *service, long fmt, ...)
}
va_end(list);
+ prom_world(1);
+
prom_cif_interface();
+
+ prom_world(0);
attrs = fmt >> 8;
va_start(list, fmt);
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 6df97c7c4..3980f1d67 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.8 1998/03/29 10:11:02 davem Exp $
+/* $Id: fs.c,v 1.10 1998/05/09 06:15:45 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -523,7 +523,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
}
- DQUOT_TRANSFER(dentry, newattrs);
+ error = DQUOT_TRANSFER(dentry, &newattrs);
out:
return error;
}
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
index 4788e9944..9c95a9234 100644
--- a/arch/sparc64/solaris/ipc.c
+++ b/arch/sparc64/solaris/ipc.c
@@ -1,9 +1,10 @@
-/* $Id: ipc.c,v 1.2 1997/09/18 10:38:27 rth Exp $
+/* $Id: ipc.c,v 1.3 1998/07/30 11:29:47 davem Exp $
* ipc.c: Solaris IPC emulation
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/smp_lock.h>
#include <linux/shm.h>
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 4179f54b3..8e0ce81da 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.10 1998/04/01 05:16:06 davem Exp $
+/* $Id: misc.c,v 1.12 1998/06/16 04:37:08 davem Exp $
* misc.c: Miscelaneous syscall emulation for Solaris
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -164,7 +164,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
{
switch (which) {
case 0: /* old uname */
- /* Lets cheat */
+ /* Let's cheat */
set_utsfield(((struct sol_uname *)A(buf))->sysname,
"SunOS", 1, 0);
set_utsfield(((struct sol_uname *)A(buf))->nodename,
@@ -188,6 +188,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
asmlinkage int solaris_utsname(u32 buf)
{
/* Why should we not lie a bit? */
+ down(&uts_sem);
set_utsfield(((struct sol_utsname *)A(buf))->sysname,
"SunOS", 0, 0);
set_utsfield(((struct sol_utsname *)A(buf))->nodename,
@@ -198,6 +199,7 @@ asmlinkage int solaris_utsname(u32 buf)
"Generic", 0, 0);
set_utsfield(((struct sol_utsname *)A(buf))->machine,
machine(), 0, 0);
+ up(&uts_sem);
return 0;
}
diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h
index 2e948c788..e91570803 100644
--- a/arch/sparc64/solaris/signal.h
+++ b/arch/sparc64/solaris/signal.h
@@ -1,4 +1,4 @@
-/* $Id: signal.h,v 1.2 1997/09/03 12:29:21 jj Exp $
+/* $Id: signal.h,v 1.3 1998/04/12 06:20:33 davem Exp $
* signal.h: Signal emulation for Solaris
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -106,4 +106,3 @@ struct sol_siginfo {
#define SOLARIS_POLL_ERR 4
#define SOLARIS_POLL_PRI 5
#define SOLARIS_POLL_HUP 6
-
diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds
index d2c08f0fe..ec1ca0461 100644
--- a/arch/sparc64/vmlinux.lds
+++ b/arch/sparc64/vmlinux.lds
@@ -6,7 +6,8 @@ ENTRY(_start)
SECTIONS
{
empty_zero_page = 0x0000000000400000;
- swapper_pg_dir = 0x0000000000402000;
+ swapper_pmd_dir = 0x0000000000402000;
+ empty_pg_dir = 0x0000000000403000;
. = 0x4000;
.text 0x0000000000404000 :
{
@@ -47,16 +48,6 @@ SECTIONS
*(.dynbss)
*(.bss)
*(COMMON)
- . = ALIGN(8192);
- empty_bad_pmd_table = .;
- . += 8192;
- empty_bad_pte_table = .;
- . += 8192;
- . += 0x40;
- empty_null_pmd_table = .;
- . += 8192;
- empty_null_pte_table = .;
- . += 8192;
}
_end = . ;
PROVIDE (end = .);