summaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/ap1000/aplib.c2
-rw-r--r--arch/sparc/ap1000/apmmu.c3
-rw-r--r--arch/sparc/ap1000/bnet.c7
-rw-r--r--arch/sparc/ap1000/mpp.c2
-rw-r--r--arch/sparc/ap1000/msc.c9
-rw-r--r--arch/sparc/ap1000/timer.c8
-rw-r--r--arch/sparc/ap1000/tnet.c9
-rw-r--r--arch/sparc/config.in24
-rw-r--r--arch/sparc/defconfig77
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/entry.S60
-rw-r--r--arch/sparc/kernel/head.S15
-rw-r--r--arch/sparc/kernel/irq.c153
-rw-r--r--arch/sparc/kernel/muldiv.c43
-rw-r--r--arch/sparc/kernel/process.c6
-rw-r--r--arch/sparc/kernel/ptrace.c10
-rw-r--r--arch/sparc/kernel/rtrap.S28
-rw-r--r--arch/sparc/kernel/setup.c118
-rw-r--r--arch/sparc/kernel/signal.c329
-rw-r--r--arch/sparc/kernel/smp.c24
-rw-r--r--arch/sparc/kernel/sparc-stub.c41
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c4
-rw-r--r--arch/sparc/kernel/sun4d_irq.c483
-rw-r--r--arch/sparc/kernel/sun4m_irq.c8
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c6
-rw-r--r--arch/sparc/kernel/sys_sparc.c103
-rw-r--r--arch/sparc/kernel/sys_sunos.c110
-rw-r--r--arch/sparc/kernel/systbls.S36
-rw-r--r--arch/sparc/lib/memcpy.S9
-rw-r--r--arch/sparc/mm/Makefile4
-rw-r--r--arch/sparc/mm/asyncd.c9
-rw-r--r--arch/sparc/mm/hypersparc.S14
-rw-r--r--arch/sparc/mm/init.c7
-rw-r--r--arch/sparc/mm/io-unit.c158
-rw-r--r--arch/sparc/mm/iommu.c284
-rw-r--r--arch/sparc/mm/srmmu.c506
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc/mm/turbosparc.S4
-rw-r--r--arch/sparc/mm/viking.S81
-rw-r--r--arch/sparc/prom/ranges.c16
-rw-r--r--arch/sparc/prom/tree.c40
41 files changed, 1955 insertions, 901 deletions
diff --git a/arch/sparc/ap1000/aplib.c b/arch/sparc/ap1000/aplib.c
index 453427162..173191492 100644
--- a/arch/sparc/ap1000/aplib.c
+++ b/arch/sparc/ap1000/aplib.c
@@ -455,7 +455,7 @@ static inline int aplib_poll(unsigned counter)
while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
tnet_check_completion();
- if (resched_needed())
+ if (need_resched)
break;
if (signal_pending(current)) break;
}
diff --git a/arch/sparc/ap1000/apmmu.c b/arch/sparc/ap1000/apmmu.c
index b0251d908..0bafe3fc9 100644
--- a/arch/sparc/ap1000/apmmu.c
+++ b/arch/sparc/ap1000/apmmu.c
@@ -11,7 +11,6 @@
* based on srmmu.c
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/malloc.h>
@@ -593,7 +592,7 @@ struct task_struct *apmmu_alloc_task_struct(void)
static unsigned long apmmu_alloc_kernel_stack(struct task_struct *tsk)
{
- unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
+ unsigned long kstk = __get_free_pages(GFP_KERNEL, 1);
if(!kstk)
kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
diff --git a/arch/sparc/ap1000/bnet.c b/arch/sparc/ap1000/bnet.c
index 974501d79..e87d01181 100644
--- a/arch/sparc/ap1000/bnet.c
+++ b/arch/sparc/ap1000/bnet.c
@@ -8,7 +8,6 @@
/* routines to control the AP1000 bif interface. This is the interface
used to talk to the front end processor */
-#include <linux/config.h>
#include <linux/sched.h>
#include <asm/ap1000/apservice.h>
#include <asm/ap1000/apreg.h>
@@ -584,7 +583,7 @@ static void bif_intr_runqueue(void)
if (q->req.type == REQ_IP) {
struct sk_buff *skb = (struct sk_buff *)q->data;
write_bif(skb->data,q->data_size,1,1);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
} else {
write_bif(q->data,q->data_size,1,1);
if (!(q->flags & BIF_NOCOPY))
@@ -718,7 +717,7 @@ int bif_send_ip(int cid, struct sk_buff *skb)
q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
if (!q) {
/* yikes! */
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return(-ENOMEM);
}
@@ -1021,7 +1020,7 @@ static void bif_dma_complete(void)
}
if (skb_out) {
- dev_kfree_skb(skb_out, FREE_WRITE);
+ dev_kfree_skb(skb_out);
skb_out = NULL;
}
diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c
index 3465e311b..84ef7f28e 100644
--- a/arch/sparc/ap1000/mpp.c
+++ b/arch/sparc/ap1000/mpp.c
@@ -28,7 +28,7 @@ static int last_task = 0;
void mpp_schedule(struct cap_request *req)
{
mpp_current_task = req->data[0];
- resched_force();
+ need_resched = 1;
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/ap1000/msc.c b/arch/sparc/ap1000/msc.c
index fc8aaf6e5..92c1f2eeb 100644
--- a/arch/sparc/ap1000/msc.c
+++ b/arch/sparc/ap1000/msc.c
@@ -10,7 +10,6 @@
* and Memory Controller (MC+).
*
*/
-#include <linux/config.h>
#define _APLIB_
#include <asm/ap1000/apreg.h>
#include <linux/mm.h>
@@ -237,7 +236,7 @@ void ap_msc_init(void)
MSC_OUT(MSC_SQRAM + i * 8, -1);
if (!qof_base) {
- qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER, 0);
+ qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER);
for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i)
set_bit(PG_reserved, &mem_map[i].flags);
}
@@ -285,7 +284,7 @@ void ap_msc_init(void)
if (!system_ringbuf.ringbuf) {
system_ringbuf.ringbuf =
- (void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER,0);
+ (void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER);
for (i=MAP_NR(system_ringbuf.ringbuf);
i<=MAP_NR(system_ringbuf.ringbuf+SYSTEM_RINGBUF_SIZE-1);i++)
set_bit(PG_reserved, &mem_map[i].flags);
@@ -294,7 +293,7 @@ void ap_msc_init(void)
if (!dummy_ringbuf.ringbuf) {
dummy_ringbuf.ringbuf =
- (void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER,0);
+ (void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER);
for (i=MAP_NR(dummy_ringbuf.ringbuf);
i<=MAP_NR(dummy_ringbuf.ringbuf+DUMMY_RINGBUF_SIZE-1);i++)
set_bit(PG_reserved, &mem_map[i].flags);
@@ -338,7 +337,7 @@ static inline void qbmful_interrupt(void)
#endif
MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
- resched_force();
+ need_resched = 1;
block_parallel_tasks = 1;
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/ap1000/timer.c b/arch/sparc/ap1000/timer.c
index 40f74a92b..129b4e6d5 100644
--- a/arch/sparc/ap1000/timer.c
+++ b/arch/sparc/ap1000/timer.c
@@ -7,6 +7,7 @@
*/
/* routines to control the AP1000 timer chip */
+#include <linux/config.h> /* for CONFIG_PROFILE */
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -73,6 +74,7 @@ void ap_gettimeofday(struct timeval *xt)
last_freerun = new_freerun;
}
+#ifdef CONFIG_PROFILE
static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
@@ -96,6 +98,8 @@ void ap_profile_init(void)
}
}
+#endif
+
void ap_init_timers(void)
{
extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs);
@@ -109,11 +113,13 @@ void ap_init_timers(void)
timer_interrupt,
(SA_INTERRUPT | SA_STATIC_ALLOC),
"timer", NULL);
-
+
+#ifdef CONFIG_PROFILE
request_irq(APTIM0_IRQ,
profile_interrupt,
(SA_INTERRUPT | SA_STATIC_ALLOC),
"profile", NULL);
+#endif
ap_clear_clock_irq();
diff --git a/arch/sparc/ap1000/tnet.c b/arch/sparc/ap1000/tnet.c
index 293be0d5b..3d30a56a9 100644
--- a/arch/sparc/ap1000/tnet.c
+++ b/arch/sparc/ap1000/tnet.c
@@ -578,7 +578,7 @@ static void tnet_send(long cid,long type,char *src_addr,long byteSize,
static void free_skb(struct sk_buff *skb, int op)
{
- dev_kfree_skb(skb,op);
+ dev_kfree_skb(skb);
}
void tnet_send_ip(int cid,struct sk_buff *skb)
@@ -596,11 +596,10 @@ void tnet_send_ip(int cid,struct sk_buff *skb)
int *info = (int *)skb->data; /* re-use the header */
info[0] = (int)data;
info[1] = size;
- info[2] = tnet_add_completion(free_skb,(int)skb,(int)FREE_WRITE);
+ info[2] = tnet_add_completion(free_skb, (int)skb, 0);
tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0);
} else {
- flag = tnet_add_completion(free_skb,
- (int)skb,(int)FREE_WRITE);
+ flag = tnet_add_completion(free_skb, (int)skb, 0);
tnet_send(cid,TNET_IP_SMALL,data,size,0,flag);
tnet_stats.small_packets_sent++;
}
@@ -613,7 +612,7 @@ void tnet_send_ip(int cid,struct sk_buff *skb)
static void reschedule(void)
{
- resched_force();
+ need_resched = 1;
mark_bh(TQUEUE_BH);
}
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index ef4bb3777..d7902e886 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.38 1997/09/04 01:54:33 davem Exp $
+# $Id: config.in,v 1.51 1998/01/08 04:16:54 baccala Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -28,6 +28,7 @@ bool 'Support for AP1000 multicomputer' CONFIG_AP1000
if [ "$CONFIG_AP1000" = "y" ]; then
define_bool CONFIG_NO_KEYBOARD y
+ define_bool CONFIG_FDDI y
define_bool CONFIG_APFDDI y
define_bool CONFIG_APBLOCK y
define_bool CONFIG_APBIF y
@@ -39,6 +40,7 @@ else
define_bool CONFIG_SUN_MOUSE y
define_bool CONFIG_SERIAL y
define_bool CONFIG_SUN_SERIAL y
+ define_bool CONFIG_SERIAL_CONSOLE y
define_bool CONFIG_SUN_KEYBOARD y
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
@@ -50,6 +52,7 @@ fi
tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
@@ -78,6 +81,7 @@ if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
fi
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+tristate 'Network block device support' CONFIG_BLK_DEV_NBD
endmenu
@@ -86,6 +90,15 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
mainmenu_option next_comment
+comment 'ISDN subsystem'
+
+tristate 'ISDN support' CONFIG_ISDN
+if [ "$CONFIG_ISDN" != "n" ]; then
+ source drivers/isdn/Config.in
+fi
+endmenu
+
+mainmenu_option next_comment
comment 'SCSI support'
tristate 'SCSI support' CONFIG_SCSI
@@ -97,7 +110,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then
dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
- bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+ bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
fi
dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
@@ -116,6 +129,8 @@ if [ "$CONFIG_SCSI" != "n" ]; then
fi
endmenu
+source drivers/fc4/Config.in
+
if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
comment 'Network device support'
@@ -162,7 +177,9 @@ source fs/nls/Config.in
mainmenu_option next_comment
comment 'Watchdog'
-bool 'Software watchdog' CONFIG_SOFT_WATCHDOG
+tristate 'Software watchdog' CONFIG_SOFT_WATCHDOG
+endmenu
+
mainmenu_option next_comment
comment 'Kernel hacking'
@@ -170,4 +187,5 @@ 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
endmenu
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 434d95d2b..5641663e5 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -49,7 +49,6 @@ SUN_FB_CREATOR=y
#
CONFIG_SUN_OPENPROMIO=m
CONFIG_SUN_MOSTEK_RTC=y
-# CONFIG_SAB82532 is not set
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
@@ -62,6 +61,7 @@ CONFIG_SUN_MOSTEK_RTC=y
CONFIG_SUN_OPENPROMFS=m
CONFIG_NET=y
CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
@@ -75,6 +75,8 @@ CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_LINEAR=y
CONFIG_MD_STRIPED=y
+CONFIG_MD_MIRRORING=m
+CONFIG_MD_RAID5=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=m
@@ -82,41 +84,46 @@ CONFIG_BLK_DEV_LOOP=m
#
# Networking options
#
+CONFIG_PACKET=y
CONFIG_NETLINK=y
CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
CONFIG_FIREWALL=y
# CONFIG_NET_SECURITY is not set
CONFIG_NET_ALIAS=y
+CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
CONFIG_IP_FIREWALL=y
# CONFIG_IP_FIREWALL_NETLINK is not set
# CONFIG_IP_FIREWALL_VERBOSE is not set
+# CONFIG_IP_TRANSPARENT_PROXY is not set
+# CONFIG_IP_ALWAYS_DEFRAG is not set
+# CONFIG_IP_ACCT is not set
CONFIG_IP_MASQUERADE=y
#
# Protocol-specific masquerading support will be built as modules.
#
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG 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_MROUTE is not set
CONFIG_IP_ALIAS=m
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
-# CONFIG_XTP is not set
#
# (it is safe to leave these untouched)
#
-# CONFIG_INET_PCTCP is not set
CONFIG_INET_RARP=m
-# CONFIG_PATH_MTU_DISCOVERY is not set
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
+# CONFIG_IPV6_EUI64 is not set
+# CONFIG_IPV6_NO_PB is not set
#
#
@@ -125,13 +132,22 @@ CONFIG_IPX=m
# CONFIG_IPX_INTERN is not set
# CONFIG_IPX_PPROP_ROUTING is not set
CONFIG_ATALK=m
-# CONFIG_IPDDP is not set
# CONFIG_AX25 is not set
CONFIG_X25=m
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_CPU_IS_SLOW is not set
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_HFQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_PFIFO=y
+CONFIG_NET_SCH_PRIO=y
#
# SCSI support
@@ -184,22 +200,20 @@ CONFIG_MYRI_SBUS=m
CONFIG_QUOTA=y
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
-# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_RNFS_BOOTP=y
-CONFIG_RNFS_RARP=y
CONFIG_NFSD=m
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
-CONFIG_ISO9660_FS=y
CONFIG_HPFS_FS=m
CONFIG_SYSV_FS=m
CONFIG_AFFS_FS=m
@@ -212,6 +226,43 @@ CONFIG_SMD_DISKLABEL=y
# CONFIG_MAC_PARTITION is not set
#
+# Native Language Support
+#
+CONFIG_NLS=y
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Watchdog
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
# Kernel hacking
#
# CONFIG_PROFILE is not set
+# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index d3307e463..7be8ddd3a 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $
+# $Id: Makefile,v 1.41 1997/11/19 15:11:59 jj Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -31,7 +31,7 @@ endif
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
+IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
process.o signal.o ioport.o setup.o idprom.o \
sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 59dd627b2..d82c098d5 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.138 1997/04/15 09:00:50 davem Exp $
+/* $Id: entry.S,v 1.142 1998/01/07 06:33:47 baccala Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -92,8 +92,8 @@ C_LABEL(trap_low):
/* Load new kgdb register set. */
LOAD_KGDB_GLOBALS(sp)
LOAD_KGDB_INS(sp)
- LOAD_KGDB_SREGS(sp, l0, l2)
- wr %l0, 0x0, %y
+ LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
+ wr %l4, 0x0, %y
sethi %hi(in_trap_handler), %l4
ld [%lo(in_trap_handler) + %l4], %l5
@@ -108,7 +108,7 @@ C_LABEL(trap_low):
STORE_PT_INS(sp)
STORE_PT_GLOBALS(sp)
STORE_PT_YREG(sp, g2)
- STORE_PT_PRIV(sp, l1, l2, l3)
+ STORE_PT_PRIV(sp, l0, l1, l2)
RESTORE_ALL
@@ -283,7 +283,7 @@ bad_trap_handler:
*/
.align 4
- .globl real_irq_entry
+ .globl real_irq_entry, patch_handler_irq
real_irq_entry:
SAVE_ALL
@@ -299,6 +299,7 @@ real_irq_continue:
wr %g2, PSR_ET, %psr
WRITE_PAUSE
mov %l7, %o0 ! irq level
+patch_handler_irq:
call C_LABEL(handler_irq)
add %sp, REGWIN_SZ, %o1 ! pt_regs ptr
wr %l0, PSR_ET, %psr
@@ -1109,7 +1110,7 @@ C_LABEL(sys_ptrace):
call C_LABEL(do_ptrace)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1143,7 +1144,7 @@ C_LABEL(sys_sigpause):
call C_LABEL(do_sigpause)
add %sp, REGWIN_SZ, %o1
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1161,7 +1162,26 @@ C_LABEL(sys_sigsuspend):
call C_LABEL(do_sigsuspend)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be 1f
+ nop
+
+ call C_LABEL(syscall_trace)
+ nop
+
+1:
+ /* We are returning to a signal handler. */
+ RESTORE_ALL
+
+ .align 4
+ .globl C_LABEL(sys_rt_sigsuspend)
+C_LABEL(sys_rt_sigsuspend):
+ /* Note: %o0, %o1 already have correct value... */
+ call C_LABEL(do_rt_sigsuspend)
+ add %sp, REGWIN_SZ, %o2
+
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1179,7 +1199,7 @@ C_LABEL(sys_sigreturn):
call C_LABEL(do_sigreturn)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1193,6 +1213,24 @@ C_LABEL(sys_sigreturn):
*/
RESTORE_ALL
+ .align 4
+ .globl C_LABEL(sys_rt_sigreturn)
+C_LABEL(sys_rt_sigreturn):
+ call C_LABEL(do_rt_sigreturn)
+ add %sp, REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be 1f
+ nop
+
+ call C_LABEL(syscall_trace)
+ nop
+
+1:
+ /* We are returning to a signal handler. */
+ RESTORE_ALL
+
/* Now that we have a real sys_clone, sys_fork() is
* implemented in terms of it. Our _real_ implementation
* of SunOS vfork() will use sys_clone() instead.
@@ -1301,7 +1339,7 @@ syscall_is_too_hard:
mov %i1, %o1
mov %i2, %o2
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
mov %i3, %o3
andcc %l5, 0x20, %g0
mov %i4, %o4
@@ -1315,7 +1353,7 @@ syscall_is_too_hard:
.globl C_LABEL(ret_sys_call)
C_LABEL(ret_sys_call):
- ld [%curptr + 0x14], %l6
+ ld [%curptr + AOFF_task_flags], %l6
cmp %o0, -ENOIOCTLCMD
ld [%sp + REGWIN_SZ + PT_PSR], %g3
set PSR_C, %g2
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 5742453ff..2de97e92b 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.83 1997/08/28 11:10:39 jj Exp $
+/* $Id: head.S,v 1.84 1997/11/19 15:12:01 jj Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -843,7 +843,7 @@ got_prop:
cmp %l1, 'm' ! Test for sun4d, sun4e ?
be sun4m_init
cmp %l1, 'd' ! Let us see how the beast will die
- be sun4m_init
+ be sun4d_init
nop
/* Jump into mmu context zero. */
@@ -853,6 +853,17 @@ got_prop:
b sun4c_continue_boot
nop
+sun4d_init:
+ /* Need to patch call to handler_irq */
+ set C_LABEL(patch_handler_irq), %g4
+ set C_LABEL(sun4d_handler_irq), %g5
+ sethi %hi(0x40000000), %g3 ! call
+ sub %g5, %g4, %g5
+ srl %g5, 2, %g5
+ or %g5, %g3, %g5
+ st %g5, [%g4]
+ /* Fall through to sun4m_init */
+
sun4m_init:
/* XXX Fucking Cypress... */
lda [%g0] ASI_M_MMUREGS, %g5
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index b22f008a1..08c0be5c6 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 davem Exp $
+/* $Id: irq.c,v 1.77 1997/11/19 15:33:05 jj Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -41,10 +41,6 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
-#ifdef __SMP_PROF__
-extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
-#endif
-
/*
* Dave Redman (djhr@tadpole.co.uk)
*
@@ -101,10 +97,10 @@ void (*set_irq_udt)(int);
*
*/
#define MAX_STATIC_ALLOC 4
-static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count = 0;
+struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+int static_irq_count = 0;
-static struct irqaction *irq_action[NR_IRQS+1] = {
+struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
@@ -114,6 +110,11 @@ int get_irq_list(char *buf)
int i, len = 0;
struct irqaction * action;
+ if (sparc_cpu_model == sun4d) {
+ extern int sun4d_get_irq_list(char *);
+
+ return sun4d_get_irq_list(buf);
+ }
for (i = 0 ; i < (NR_IRQS+1) ; i++) {
action = *(i + irq_action);
if (!action)
@@ -132,109 +133,6 @@ int get_irq_list(char *buf)
return len;
}
-#ifdef __SMP_PROF__
-
-static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
-
-extern unsigned int prof_multiplier[NR_CPUS];
-extern unsigned int prof_counter[NR_CPUS];
-
-int get_smp_prof_list(char *buf) {
- int i,j, len = 0;
- struct irqaction * action;
- unsigned long sum_spins = 0;
- unsigned long sum_spins_syscall = 0;
- unsigned long sum_spins_sys_idle = 0;
- unsigned long sum_smp_idle_count = 0;
- unsigned long sum_local_timer_ticks = 0;
-
- for (i=0;i<smp_num_cpus;i++) {
- int cpunum = cpu_logical_map[i];
- sum_spins+=smp_spins[cpunum];
- sum_spins_syscall+=smp_spins_syscall[cpunum];
- sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
- sum_smp_idle_count+=smp_idle_count[cpunum];
- sum_local_timer_ticks+=smp_local_timer_ticks[cpunum];
- }
-
- len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
- len += sprintf(buf+len," SUM ");
- for (i=0;i<smp_num_cpus;i++)
- len += sprintf(buf+len," P%1d ",cpu_logical_map[i]);
- len += sprintf(buf+len,"\n");
- for (i = 0 ; i < NR_IRQS ; i++) {
- action = *(i + irq_action);
- if (!action || !action->handler)
- continue;
- len += sprintf(buf+len, "%3d: %10d ",
- i, kstat.interrupts[i]);
- for (j=0;j<smp_num_cpus;j++)
- len+=sprintf(buf+len, "%10d ",
- int_count[cpu_logical_map[j]][i]);
- len += sprintf(buf+len, "%c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
- }
- len += sprintf(buf+len, "\n");
- }
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from int\n");
-
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins_syscall);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from syscall\n");
-
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins_sys_idle);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from sysidle\n");
- len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," idle ticks\n");
-
- len+=sprintf(buf+len,"TICK %10lu",sum_local_timer_ticks);
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_local_timer_ticks[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," local APIC timer ticks\n");
-
- len+=sprintf(buf+len,"MULT: ");
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10u",prof_multiplier[cpu_logical_map[i]]);
- len +=sprintf(buf+len," profiling multiplier\n");
-
- len+=sprintf(buf+len,"COUNT: ");
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10u",prof_counter[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," profiling counter\n");
-
- len+=sprintf(buf+len, "IPI: %10lu received\n",
- ipi_count);
-
- return len;
-}
-#endif
-
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action;
@@ -242,6 +140,11 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long flags;
unsigned int cpu_irq;
+ if (sparc_cpu_model == sun4d) {
+ extern void sun4d_free_irq(unsigned int, void *);
+
+ return sun4d_free_irq(irq, dev_id);
+ }
cpu_irq = irq & NR_IRQS;
action = *(cpu_irq + irq_action);
if (cpu_irq > 14) { /* 14 irq levels on the sparc */
@@ -531,29 +434,28 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
void handler_irq(int irq, struct pt_regs * regs)
{
struct irqaction * action;
- unsigned int cpu_irq = irq & NR_IRQS;
int cpu = smp_processor_id();
#ifdef __SMP__
extern void smp_irq_rotate(int cpu);
#endif
- disable_pil_irq(cpu_irq);
+ disable_pil_irq(irq);
#ifdef __SMP__
/* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
if(irq < 10)
smp_irq_rotate(cpu);
#endif
- irq_enter(cpu, cpu_irq, regs);
- action = *(cpu_irq + irq_action);
- kstat.interrupts[cpu_irq]++;
+ irq_enter(cpu, irq, regs);
+ action = *(irq + irq_action);
+ kstat.interrupts[irq]++;
do {
if (!action || !action->handler)
unexpected_irq(irq, 0, regs);
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
- irq_exit(cpu, cpu_irq);
- enable_pil_irq(cpu_irq);
+ irq_exit(cpu, irq);
+ enable_pil_irq(irq);
}
#ifdef CONFIG_BLK_DEV_FD
@@ -669,12 +571,22 @@ int request_irq(unsigned int irq,
unsigned long flags;
unsigned int cpu_irq;
+ if (sparc_cpu_model == sun4d) {
+ extern int sun4d_request_irq(unsigned int,
+ void (*)(int, void *, struct pt_regs *),
+ unsigned long, const char *, void *);
+ return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
+ }
cpu_irq = irq & NR_IRQS;
if(cpu_irq > 14)
return -EINVAL;
if (!handler)
return -EINVAL;
+
+ if (irqflags & SA_DCOOKIE)
+ dev_id = ((struct devid_cookie *)dev_id)->real_dev_id;
+
action = *(cpu_irq + irq_action);
if (action) {
if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
@@ -751,6 +663,7 @@ __initfunc(void init_IRQ(void))
{
extern void sun4c_init_IRQ( void );
extern void sun4m_init_IRQ( void );
+ extern void sun4d_init_IRQ( void );
switch(sparc_cpu_model) {
case sun4c:
@@ -760,6 +673,10 @@ __initfunc(void init_IRQ(void))
case sun4m:
sun4m_init_IRQ();
break;
+
+ case sun4d:
+ sun4d_init_IRQ();
+ break;
case ap1000:
#if CONFIG_AP1000
diff --git a/arch/sparc/kernel/muldiv.c b/arch/sparc/kernel/muldiv.c
index 6a193200b..b2cc64bb0 100644
--- a/arch/sparc/kernel/muldiv.c
+++ b/arch/sparc/kernel/muldiv.c
@@ -1,4 +1,4 @@
-/* $Id: muldiv.c,v 1.4 1997/04/11 00:42:08 davem Exp $
+/* $Id: muldiv.c,v 1.5 1997/12/15 20:07:20 ecd Exp $
* muldiv.c: Hardware multiply/division illegal instruction trap
* for sun4c/sun4 (which do not have those instructions)
*
@@ -69,18 +69,23 @@ static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
ret; \
})
-static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
+static inline int
+store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs)
{
struct reg_window *win;
- if(!reg)
- return NULL;
- else if(reg < 16)
- return &regs->u_regs[reg];
- win = (struct reg_window *) regs->u_regs[UREG_FP];
- return &win->locals[reg - 16];
+ if (!reg)
+ return 0;
+ if (reg < 16) {
+ regs->u_regs[reg] = result;
+ return 0;
+ } else {
+ /* need to use put_user() in this case: */
+ win = (struct reg_window *)regs->u_regs[UREG_FP];
+ return (put_user(result, &win->locals[reg - 16]));
+ }
}
-
+
extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc,
unsigned long npc, unsigned long psr);
@@ -90,7 +95,6 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
unsigned int insn;
int inst;
unsigned int rs1, rs2, rdv;
- unsigned long *rd;
if (!pc) return -1; /* This happens to often, I think */
if (get_user (insn, (unsigned int *)pc)) return -1;
@@ -109,7 +113,6 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
rs2 = fetch_reg(rs2, regs);
}
rs1 = fetch_reg(rs1, regs);
- rd = fetch_reg_addr(rdv, regs);
switch (inst) {
case 10: /* umul */
#ifdef DEBUG_MULDIV
@@ -127,9 +130,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x%08x\n", rs2, rs1);
#endif
- if (rd) {
- if (put_user (rs1, rd)) return -1;
- }
+ if (store_reg(rs1, rdv, regs))
+ return -1;
regs->y = rs2;
break;
case 11: /* smul */
@@ -148,9 +150,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x%08x\n", rs2, rs1);
#endif
- if (rd) {
- if (put_user (rs1, rd)) return -1;
- }
+ if (store_reg(rs1, rdv, regs))
+ return -1;
regs->y = rs2;
break;
case 14: /* udiv */
@@ -179,8 +180,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x\n", rs1);
#endif
- if (rd)
- if (put_user (rs1, rd)) return -1;
+ if (store_reg(rs1, rdv, regs))
+ return -1;
break;
case 15: /* sdiv */
#ifdef DEBUG_MULDIV
@@ -208,8 +209,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x\n", rs1);
#endif
- if (rd)
- if (put_user (rs1, rd)) return -1;
+ if (store_reg(rs1, rdv, regs))
+ return -1;
break;
}
if (is_foocc (insn)) {
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index ff4a3f192..32feff3de 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.100 1997/08/10 04:49:23 davem Exp $
+/* $Id: process.c,v 1.102 1997/12/01 03:36:31 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -120,7 +120,7 @@ int cpu_idle(void *unused)
}
/* endless idle loop with no priority at all */
current->counter = -100;
- if(!smp_commenced || resched_needed())
+ if(!smp_commenced || need_resched)
schedule();
}
}
@@ -197,7 +197,9 @@ void show_regwindow(struct reg_window *rw)
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
+#ifdef __SMP__
static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
+#endif
void show_backtrace(void)
{
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 933a5acfa..635623fb3 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -799,7 +799,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
addr = 1;
case PTRACE_CONT: { /* restart after signal. */
- if ((unsigned long) data > NSIG) {
+ if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
@@ -851,7 +851,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
- if ((unsigned long) data > NSIG) {
+ if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
@@ -898,9 +898,7 @@ asmlinkage void syscall_trace(void)
current->pid, current->exit_code);
#endif
if (current->exit_code) {
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= (1 << (current->exit_code - 1));
- spin_unlock_irq(&current->sigmask_lock);
+ send_sig (current->exit_code, current, 1);
+ current->exit_code = 0;
}
- current->exit_code = 0;
}
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
index 8d46d487e..68f3dc9af 100644
--- a/arch/sparc/kernel/rtrap.S
+++ b/arch/sparc/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
+/* $Id: rtrap.S,v 1.49 1997/12/14 23:24:24 ecd Exp $
* rtrap.S: Return from Sparc trap low-level code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -65,27 +65,24 @@ C_LABEL(ret_trap_lockless_ipi):
wr %t_psr, 0x0, %psr
b ret_trap_kernel
- mov 1, %o0
+ nop
1:
- ld [%curptr + AOFF_task_processor], %o1
ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
- sll %o0, %o1, %o0
-
- andcc %g2, %o0, %g0
+ orcc %g2, %g0, %g0
be signal_p
- nop
+ ld [%curptr + AOFF_task_sigpending], %g2
call C_LABEL(schedule)
nop
+ ld [%curptr + AOFF_task_sigpending], %g2
signal_p:
- ld [%curptr + AOFF_task_signal], %g2
- ld [%curptr + AOFF_task_blocked], %o0
- andncc %g2, %o0, %g0
- be,a ret_trap_continue
+ cmp %g2, 0
+ bz,a ret_trap_continue
ld [%sp + REGWIN_SZ + PT_PSR], %t_psr
+ clr %o0
mov %l5, %o2
mov %l6, %o3
call C_LABEL(do_signal)
@@ -110,7 +107,8 @@ ret_trap_continue:
call C_LABEL(try_to_clear_window_buffer)
add %sp, REGWIN_SZ, %o0
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
ret_trap_nobufwins:
/* Load up the user's out registers so we can pull
@@ -179,7 +177,8 @@ ret_trap_unaligned_pc:
call C_LABEL(do_memaccess_unaligned)
nop
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
ret_trap_kernel:
/* Will the rett land us in the invalid window? */
@@ -228,7 +227,8 @@ ret_trap_user_stack_is_bolixed:
call C_LABEL(window_ret_fault)
add %sp, REGWIN_SZ, %o0
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
.globl C_LABEL(sun4c_rett_stackchk)
C_LABEL(sun4c_rett_stackchk):
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index a6b3f9e07..e53c343da 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.85 1997/05/27 06:45:54 davem Exp $
+/* $Id: setup.c,v 1.87 1997/12/18 02:42:42 ecd Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
#include <linux/blk.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/console.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -118,7 +119,9 @@ extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
unsigned int boot_flags;
#define BOOTME_DEBUG 0x1
#define BOOTME_SINGLE 0x2
-#define BOOTME_KGDB 0x4
+#define BOOTME_KGDBA 0x4
+#define BOOTME_KGDBB 0x8
+#define BOOTME_KGDB 0xc
#ifdef CONFIG_SUN_CONSOLE
extern char *console_fb_path;
@@ -188,15 +191,14 @@ __initfunc(static void boot_flags_init(char *commands))
process_switch(*commands++);
} else if (strlen(commands) >= 9
&& !strncmp(commands, "kgdb=tty", 8)) {
- boot_flags |= BOOTME_KGDB;
switch (commands[8]) {
#ifdef CONFIG_SUN_SERIAL
case 'a':
- rs_kgdb_hook(0);
+ boot_flags |= BOOTME_KGDBA;
prom_printf("KGDB: Using serial line /dev/ttya.\n");
break;
case 'b':
- rs_kgdb_hook(1);
+ boot_flags |= BOOTME_KGDBB;
prom_printf("KGDB: Using serial line /dev/ttyb.\n");
break;
#endif
@@ -207,7 +209,6 @@ __initfunc(static void boot_flags_init(char *commands))
#endif
default:
printk("KGDB: Unknown tty line.\n");
- boot_flags &= ~BOOTME_KGDB;
break;
}
commands += 9;
@@ -273,8 +274,6 @@ extern unsigned ramdisk_size;
extern int root_mountflags;
-extern void register_console(void (*proc)(const char *));
-
char saved_command_line[256];
char reboot_command[256];
enum sparc_cpu sparc_cpu_model;
@@ -283,6 +282,16 @@ struct tt_entry *sparc_ttable;
static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+static void prom_cons_write(struct console *con, const char *str, unsigned count)
+{
+ while (count--)
+ prom_printf("%c", *str++);
+}
+
+static struct console prom_console = {
+ "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
+};
+
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -335,7 +344,7 @@ __initfunc(void setup_arch(char **cmdline_p,
printk("SUN4U\n");
break;
case ap1000:
- register_console((void (*) (const char *))prom_printf);
+ register_console(&prom_console);
printk("AP1000\n");
packed = 1;
break;
@@ -345,16 +354,6 @@ __initfunc(void setup_arch(char **cmdline_p,
};
boot_flags_init(*cmdline_p);
- if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
- ((*(short *)linux_dbvec) != -1)) {
- printk("Booted under KADB. Syncing trap table.\n");
- (*(linux_dbvec->teach_debugger))();
- }
- if((boot_flags & BOOTME_KGDB)) {
- set_debug_traps();
- prom_printf ("Breakpoint!\n");
- breakpoint();
- }
idprom_init();
load_mmu();
@@ -410,6 +409,56 @@ __initfunc(void setup_arch(char **cmdline_p,
}
not_relevant:
+#ifdef CONFIG_SUN_SERIAL
+ *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#endif
+ {
+ extern int serial_console; /* in console.c, of course */
+#if !CONFIG_SUN_SERIAL
+ serial_console = 0;
+#else
+ switch (console_fb) {
+ case 0: /* Let get our io devices from prom */
+ {
+ int idev = prom_query_input_device();
+ int odev = prom_query_output_device();
+ if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+ serial_console = 0;
+ } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+ serial_console = 1;
+ } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+ serial_console = 2;
+ } else {
+ prom_printf("Inconsistent console\n");
+ prom_halt();
+ }
+ }
+ break;
+ case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
+ case 2: serial_console = 1; break; /* Force ttya as console */
+ case 3: serial_console = 2; break; /* Force ttyb as console */
+ }
+#endif
+ }
+
+ if ((boot_flags & BOOTME_KGDBA)) {
+ rs_kgdb_hook(0);
+ }
+ if ((boot_flags & BOOTME_KGDBB)) {
+ rs_kgdb_hook(1);
+ }
+
+ if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
+ ((*(short *)linux_dbvec) != -1)) {
+ printk("Booted under KADB. Syncing trap table.\n");
+ (*(linux_dbvec->teach_debugger))();
+ }
+ if((boot_flags & BOOTME_KGDB)) {
+ set_debug_traps();
+ prom_printf ("Breakpoint!\n");
+ breakpoint();
+ }
+
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = to_kdev_t(root_dev);
@@ -443,37 +492,6 @@ not_relevant:
init_task.mm->context = (unsigned long) NO_CONTEXT;
init_task.tss.kregs = &fake_swapper_regs;
-#ifdef CONFIG_SUN_SERIAL
- *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
-#endif
- {
- extern int serial_console; /* in console.c, of course */
-#if !CONFIG_SUN_SERIAL
- serial_console = 0;
-#else
- switch (console_fb) {
- case 0: /* Let get our io devices from prom */
- {
- int idev = prom_query_input_device();
- int odev = prom_query_output_device();
- if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
- serial_console = 1;
- } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
- serial_console = 2;
- } else {
- prom_printf("Inconsistent console\n");
- prom_halt();
- }
- }
- break;
- case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
- case 2: serial_console = 1; break; /* Force ttya as console */
- case 3: serial_console = 2; break; /* Force ttyb as console */
- }
-#endif
- }
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index fbb5578fa..5c10faa81 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
+/* $Id: signal.c,v 1.77 1997/12/22 03:06:32 ecd Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -24,9 +24,7 @@
#include <asm/svr4.h>
#include <asm/pgtable.h>
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
@@ -35,7 +33,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
unsigned long orig_o0, int ret_from_syscall);
/* This turned off for production... */
@@ -56,12 +54,13 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
* ---------------------------------- <-- New %sp
*/
struct signal_sframe {
- struct reg_window sig_window;
- int sig_num;
- int sig_code;
- struct sigcontext *sig_scptr;
- int sig_address;
- struct sigcontext sig_context;
+ struct reg_window sig_window;
+ int sig_num;
+ int sig_code;
+ struct sigcontext *sig_scptr;
+ int sig_address;
+ struct sigcontext sig_context;
+ unsigned int extramask[_NSIG_WORDS - 1];
};
/*
@@ -75,6 +74,7 @@ struct new_signal_frame {
__siginfo_t info;
__siginfo_fpu_t *fpu_save;
unsigned long insns [2] __attribute__ ((aligned (8)));
+ unsigned int extramask[_NSIG_WORDS - 1];
__siginfo_fpu_t fpu_state;
};
@@ -86,13 +86,15 @@ struct new_signal_frame {
* atomically swap in the new signal mask, and wait for a signal.
* This is really tricky on the Sparc, watch out...
*/
-asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
+asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
{
- unsigned long mask;
+ sigset_t saveset;
+ set &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock);
- mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
+ saveset = current->blocked;
+ siginitset(&current->blocked, set);
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
regs->pc = regs->npc;
@@ -112,7 +114,7 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
*/
regs->psr |= PSR_C;
regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(mask, regs, 0, 0))
+ if (do_signal(&saveset, regs, 0, 0))
return;
}
}
@@ -127,6 +129,52 @@ asmlinkage void do_sigsuspend (struct pt_regs *regs)
_sigpause_common(regs->u_regs[UREG_I0], regs);
}
+asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize,
+ struct pt_regs *regs)
+{
+ sigset_t oldset, set;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t)) {
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EINVAL;
+ return;
+ }
+
+ if (copy_from_user(&set, uset, sizeof(set))) {
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EFAULT;
+ return;
+ }
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ oldset = current->blocked;
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->pc = regs->npc;
+ regs->npc += 4;
+
+ /* Condition codes and return value where set here for sigpause,
+ * and so got used by setup_frame, which again causes sigreturn()
+ * to return -EINTR.
+ */
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ /*
+ * Return -EINTR and set condition code here,
+ * so the interrupted system call actually returns
+ * these.
+ */
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal(&oldset, regs, 0, 0))
+ return;
+ }
+}
static inline void
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
@@ -154,11 +202,12 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
(sizeof(unsigned long *)))*16));
}
-void do_new_sigreturn (struct pt_regs *regs)
+static inline void do_new_sigreturn (struct pt_regs *regs)
{
struct new_signal_frame *sf;
- unsigned long up_psr, pc, npc, mask;
-
+ unsigned long up_psr, pc, npc;
+ sigset_t set;
+
sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
/* 1. Make sure we are not getting garbage from the user */
@@ -173,7 +222,7 @@ void do_new_sigreturn (struct pt_regs *regs)
if ((pc | npc) & 3)
goto segv_and_exit;
-
+
/* 2. Restore the state */
up_psr = regs->psr;
copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
@@ -181,28 +230,36 @@ void do_new_sigreturn (struct pt_regs *regs)
/* User can only change condition codes and FPU enabling in %psr. */
regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
| (regs->psr & (PSR_ICC | PSR_EF));
-
+
if (sf->fpu_save)
restore_fpu_state(regs, sf->fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &sf->info.si_mask);
- current->blocked = (mask & _BLOCKABLE);
+ if (__get_user(set.sig[0], &sf->info.si_mask) ||
+ copy_from_user(&set.sig[1], &sf->extramask,
+ (_NSIG_WORDS-1) * sizeof(unsigned int)))
+ goto segv_and_exit;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
return;
segv_and_exit:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
}
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct sigcontext *scptr;
- unsigned long pc, npc, psr, mask;
+ unsigned long pc, npc, psr;
+ sigset_t set;
synchronize_user_stack();
@@ -225,8 +282,17 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &scptr->sigc_mask);
- current->blocked = (mask & _BLOCKABLE);
+ if (__get_user(set.sig[0], &scptr->sigc_mask) ||
+ /* Note that scptr + 1 points to extramask */
+ copy_from_user(&set.sig[1], scptr + 1,
+ (_NSIG_WORDS - 1) * sizeof(unsigned int)))
+ goto segv_and_exit;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ 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;
@@ -248,11 +314,15 @@ segv_and_exit:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
+}
+
+asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
+{
+ printk("XXX: FIXME: write do_rt_sigreturn\n");
}
/* Checks if the fp is valid */
-int invalid_frame_pointer (void *fp, int fplen)
+static inline int invalid_frame_pointer (void *fp, int fplen)
{
if ((((unsigned long) fp) & 7) ||
!__access_ok((unsigned long)fp, fplen) ||
@@ -263,8 +333,9 @@ int invalid_frame_pointer (void *fp, int fplen)
return 0;
}
-static void setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
- struct pt_regs *regs, int signr, unsigned long oldmask)
+static inline void
+setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
+ struct pt_regs *regs, int signr, sigset_t *oldset)
{
struct signal_sframe *sframep;
struct sigcontext *sc;
@@ -291,7 +362,9 @@ static void setup_frame(struct sigaction *sa, unsigned long pc, unsigned long np
/* We've already made sure frame pointer isn't in kernel space... */
__put_user(old_status, &sc->sigc_onstack);
- __put_user(oldmask, &sc->sigc_mask);
+ __put_user(oldset->sig[0], &sc->sigc_mask);
+ __copy_to_user(sframep->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
__put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
@@ -334,7 +407,6 @@ sigill_and_return:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
@@ -369,8 +441,9 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
current->used_math = 0;
}
-static void new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
- int signo, unsigned long oldmask)
+static inline void
+new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
struct new_signal_frame *sf;
int sigframe_size;
@@ -403,39 +476,51 @@ static void new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
sf->fpu_save = NULL;
}
- __put_user(oldmask, &sf->info.si_mask);
+ __put_user(oldset->sig[0], &sf->info.si_mask);
+ __copy_to_user(sf->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
sizeof (struct reg_window));
- /* 3. return to kernel instructions */
- __put_user(0x821020d8, &sf->insns [0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns [1]); /* t 0x10 */
-
- /* 4. signal handler back-trampoline and parameters */
+ /* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
- regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
- /* 5. signal handler */
- regs->pc = (unsigned long) sa->sa_handler;
+ /* 4. signal handler */
+ regs->pc = (unsigned long) ka->sa.sa_handler;
regs->npc = (regs->pc + 4);
- /* Flush instruction space. */
- flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+ /* 5. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
+
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+
+ /* Flush instruction space. */
+ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+ }
return;
sigill_and_return:
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
+static inline void
+new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset, siginfo_t *info)
+{
+ printk("XXX: FIXME: new_setup_rt_frame unimplemented\n");
+}
/* Setup a Solaris stack frame */
static inline void
setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
- struct pt_regs *regs, int signr, unsigned long oldmask)
+ struct pt_regs *regs, int signr, sigset_t *oldset)
{
svr4_signal_frame_t *sfp;
svr4_gregset_t *gr;
@@ -443,6 +528,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_mcontext_t *mc;
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
+ svr4_sigset_t setv;
int window = 0;
synchronize_user_stack();
@@ -470,7 +556,14 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* sc->sigc_onstack = old_status;
* anyways, it does not look like it is used for anything at all.
*/
- __put_user(oldmask, &uc->sigmask.sigbits [0]);
+ setv.sigbits[0] = oldset->sig[0];
+ setv.sigbits[1] = oldset->sig[1];
+ if (_NSIG_WORDS >= 4) {
+ setv.sigbits[2] = oldset->sig[2];
+ setv.sigbits[3] = oldset->sig[3];
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
__put_user(regs->pc, &((*gr) [SVR4_PC]));
@@ -547,13 +640,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
sigill_and_return:
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
+ svr4_sigset_t setv;
synchronize_user_stack();
@@ -566,9 +659,15 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
/* Setup convenience variables */
mc = &uc->mcontext;
gr = &mc->greg;
-
- /* We only have < 32 signals, fill the first slot only */
- __put_user(current->blocked, &uc->sigmask.sigbits [0]);
+
+ setv.sigbits[0] = current->blocked.sig[0];
+ setv.sigbits[1] = current->blocked.sig[1];
+ if (_NSIG_WORDS >= 4) {
+ setv.sigbits[2] = current->blocked.sig[2];
+ setv.sigbits[3] = current->blocked.sig[3];
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
@@ -593,8 +692,6 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
sigsegv_and_return:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
- return -EFAULT;
}
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
@@ -602,7 +699,9 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
{
struct thread_struct *tp = &current->tss;
svr4_gregset_t *gr;
- unsigned long pc, npc, psr, mask;
+ unsigned long pc, npc, psr;
+ sigset_t set;
+ svr4_sigset_t setv;
/* Fixme: restore windows, or is this already taken care of in
* svr4_setup_frame when sync_user_windows is done?
@@ -633,8 +732,19 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &c->sigmask.sigbits [0]);
- current->blocked = (mask & _BLOCKABLE);
+ if (__copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)))
+ goto sigsegv_and_return;
+ set.sig[0] = setv.sigbits[0];
+ set.sig[1] = setv.sigbits[1];
+ if (_NSIG_WORDS >= 4) {
+ set.sig[2] = setv.sigbits[2];
+ set.sig[3] = setv.sigbits[3];
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
regs->pc = pc;
regs->npc = npc | 1;
__get_user(regs->y, &((*gr) [SVR4_Y]));
@@ -650,27 +760,29 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
sigsegv_and_return:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
- return -EFAULT;
}
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs *regs,
- int svr4_signal)
+static inline void
+handle_signal(unsigned long signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
+ int svr4_signal)
{
- if(svr4_signal)
- setup_svr4_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
+ if (svr4_signal)
+ setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset);
else {
- if (current->tss.new_signal)
- new_setup_frame (sa, regs, signr, oldmask);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ new_setup_rt_frame(ka, regs, signr, oldset, info);
+ else if (current->tss.new_signal)
+ new_setup_frame (ka, regs, signr, oldset);
else
- setup_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
+ setup_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset);
}
- if(sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if(!(sa->sa_flags & SA_NOMASK)) {
+ if(ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+ if(!(ka->sa.sa_flags & SA_NOMASK)) {
spin_lock_irq(&current->sigmask_lock);
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked, signr);
spin_unlock_irq(&current->sigmask_lock);
}
}
@@ -699,22 +811,25 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
unsigned long orig_i0, int restart_syscall)
{
- unsigned long signr, mask = ~current->blocked;
- struct sigaction *sa;
+ unsigned long signr;
+ struct k_sigaction *ka;
+ siginfo_t info;
+
int svr4_signal = current->personality == PER_SVR4;
-
- while ((signr = current->signal & mask) != 0) {
- signr = ffz(~signr);
+ if (!oldset)
+ oldset = &current->blocked;
+
+ for (;;) {
spin_lock_irq(&current->sigmask_lock);
- current->signal &= ~(1 << signr);
+ signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sigmask_lock);
- sa = current->sig->action + signr;
- signr++;
+ if (!signr) break;
+
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
@@ -729,15 +844,26 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = 0;
if (signr == SIGSTOP)
continue;
- if (_S(signr) & current->blocked) {
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= _S(signr);
- spin_unlock_irq(&current->sigmask_lock);
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
continue;
}
- sa = current->sig->action + signr - 1;
}
- if(sa->sa_handler == SIG_IGN) {
+
+ ka = &current->sig->action[signr-1];
+
+ if(ka->sa.sa_handler == SIG_IGN) {
if(signr != SIGCHLD)
continue;
@@ -750,7 +876,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
;
continue;
}
- if(sa->sa_handler == SIG_DFL) {
+ if(ka->sa.sa_handler == SIG_DFL) {
+ unsigned long exit_code = signr;
+
if(current->pid == 1)
continue;
switch(signr) {
@@ -758,8 +886,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
continue;
case SIGTSTP: case SIGTTIN: case SIGTTOU:
- /* The operations performed by is_orphaned_pgrp()
- * are protected by the tasklist_lock.
+ /* The operations performed by
+ * is_orphaned_pgrp() are protected by
+ * the tasklist_lock.
*/
if (is_orphaned_pgrp(current->pgrp))
continue;
@@ -771,7 +900,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
/* notify_parent() is SMP safe */
- if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
@@ -782,7 +911,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
if(current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
+ exit_code |= 0x80;
unlock_kernel();
}
#ifdef DEBUG_SIGNALS
@@ -792,20 +921,16 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
#endif
/* fall through */
default:
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= _S(signr & 0x7f);
- spin_unlock_irq(&current->sigmask_lock);
-
+ lock_kernel();
+ sigaddset(&current->signal, signr);
current->flags |= PF_SIGNALED;
-
- lock_kernel(); /* 8-( */
- do_exit(signr);
- unlock_kernel();
+ do_exit(exit_code);
+ /* NOT REACHED */
}
}
if(restart_syscall)
- syscall_restart(orig_i0, regs, sa);
- handle_signal(signr, sa, oldmask, regs, svr4_signal);
+ syscall_restart(orig_i0, regs, &ka->sa);
+ handle_signal(signr, ka, &info, oldset, regs, svr4_signal);
return 1;
}
if(restart_syscall &&
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 17931fd55..15364d44f 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -3,6 +3,7 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h> /* for CONFIG_PROFILE */
#include <asm/head.h>
#include <linux/kernel.h>
@@ -66,16 +67,6 @@ volatile int cpu_logical_map[NR_CPUS];
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
volatile unsigned long ipi_count;
-#ifdef __SMP_PROF__
-volatile unsigned long smp_spins[NR_CPUS]={0};
-volatile unsigned long smp_spins_syscall[NR_CPUS]={0};
-volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0};
-volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0};
-volatile unsigned long smp_idle_count[1+NR_CPUS]={0,};
-#endif
-#if defined (__SMP_PROF__)
-volatile unsigned long smp_idle_map=0;
-#endif
volatile int smp_process_available=0;
@@ -558,7 +549,7 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
/* Reschedule call back. */
void smp_reschedule_irq(void)
{
- resched_force();
+ need_resched = 1;
}
/* Running cross calls. */
@@ -583,6 +574,8 @@ void smp_stop_cpu_irq(void)
/* Protects counters touched during level14 ticker */
spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_PROFILE
+
/* 32-bit Sparc specific profiling function. */
static inline void sparc_do_profile(unsigned long pc)
{
@@ -601,7 +594,7 @@ static inline void sparc_do_profile(unsigned long pc)
}
}
-volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,};
+#endif
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
@@ -614,8 +607,10 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
int cpu = smp_processor_id();
clear_profile_irq(mid_xlate[cpu]);
+#ifdef CONFIG_PROFILE
if(!user_mode(regs))
sparc_do_profile(regs->pc);
+#endif
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
if(current->pid) {
@@ -623,7 +618,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
if(--current->counter < 0) {
current->counter = 0;
- resched_force();
+ need_resched = 1;
}
spin_lock(&ticker_lock);
@@ -639,9 +634,6 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
}
prof_counter[cpu] = prof_multiplier[cpu];
}
-#ifdef __SMP_PROF__
- smp_local_timer_ticks[cpu]++;
-#endif
}
extern unsigned int lvl14_resolution;
diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c
index 008e9c450..e259ffade 100644
--- a/arch/sparc/kernel/sparc-stub.c
+++ b/arch/sparc/kernel/sparc-stub.c
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.20 1997/01/06 06:52:31 davem Exp $
+/* $Id: sparc-stub.c,v 1.22 1998/01/07 06:33:48 baccala Exp $
* sparc-stub.c: KGDB support for the Linux kernel.
*
* Modifications to run under Linux
@@ -323,7 +323,23 @@ mem2hex(char *mem, char *buf, int count)
unsigned char ch;
while (count-- > 0) {
- ch = *mem++;
+ /* This assembler code is basically: ch = *mem++;
+ * except that we use the SPARC/Linux exception table
+ * mechanism (see how "fixup" works in kernel_mna_trap_fault)
+ * to arrange for a "return 0" upon a memory fault
+ */
+ __asm__(
+ "1: ldub [%0], %1
+ inc %0
+ .section .fixup,#alloc,#execinstr
+ .align 4
+ 2: retl
+ mov 0, %%o0
+ .section __ex_table, #alloc
+ .align 4
+ .word 1b, 2b
+ .text"
+ : "=r" (mem), "=r" (ch) : "0" (mem));
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch & 0xf];
}
@@ -345,7 +361,19 @@ hex2mem(char *buf, char *mem, int count)
ch = hex(*buf++) << 4;
ch |= hex(*buf++);
- *mem++ = ch;
+ /* Assembler code is *mem++ = ch; with return 0 on fault */
+ __asm__(
+ "1: stb %1, [%0]
+ inc %0
+ .section .fixup,#alloc,#execinstr
+ .align 4
+ 2: retl
+ mov 0, %%o0
+ .section __ex_table, #alloc
+ .align 4
+ .word 1b, 2b
+ .text"
+ : "=r" (mem) : "r" (ch) , "0" (mem));
}
return mem;
}
@@ -387,13 +415,18 @@ set_debug_traps(void)
/* In case GDB is started before us, ack any packets (presumably
* "$?#xx") sitting there.
+ *
+ * I've found this code causes more problems than it solves,
+ * so that's why it's commented out. GDB seems to work fine
+ * now starting either before or after the kernel -bwb
*/
-
+#if 0
while((c = getDebugChar()) != '$');
while((c = getDebugChar()) != '#');
c = getDebugChar(); /* eat first csum byte */
c = getDebugChar(); /* eat second csum byte */
putDebugChar('+'); /* ack it */
+#endif
initialized = 1; /* connect! */
restore_flags(flags);
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index cf4146c4a..df3eac300 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,10 +1,12 @@
-/* $Id: sparc_ksyms.c,v 1.60 1997/06/17 13:25:13 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.61 1997/11/19 07:57:44 jj Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*/
+/* Tell string.h we don't want memcpy etc. as cpp defines */
+#define EXPORT_SYMTAB_STROPS
#define PROMLIB_INTERNAL
#include <linux/config.h>
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
new file mode 100644
index 000000000..f22fe1495
--- /dev/null
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -0,0 +1,483 @@
+/* $Id: sun4d_irq.c,v 1.3 1997/12/22 16:09:15 jj Exp $
+ * arch/sparc/kernel/sun4d_irq.c:
+ * SS1000/SC2000 interrupt handling.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Heavily based on arch/sparc/kernel/irq.c.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/smp.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/spinlock.h>
+#include <asm/sbus.h>
+#include <asm/sbi.h>
+
+struct sun4d_timer_regs *sun4d_timers;
+#define TIMER_IRQ 10
+
+#define MAX_STATIC_ALLOC 4
+extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+extern int static_irq_count;
+
+extern struct irqaction *irq_action[];
+
+struct sbus_action {
+ struct irqaction *action;
+ unsigned char lock;
+ unsigned char active;
+ unsigned char disabled;
+} *sbus_actions;
+
+static int pil_to_sbus[] = {
+ 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
+};
+
+static int nsbi;
+
+int sun4d_get_irq_list(char *buf)
+{
+ int i, j = 0, k = 0, len = 0, sbusl;
+ struct irqaction * action;
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ sbusl = pil_to_sbus[i];
+ if (!sbusl) {
+ action = *(i + irq_action);
+ if (!action)
+ continue;
+ } else {
+ for (j = 0; j < nsbi; j++) {
+ for (k = 0; k < 4; k++)
+ if ((action = sbus_actions [(j << 5) + (sbusl << 2) + k].action))
+ goto found_it;
+ }
+ continue;
+ }
+found_it: len += sprintf(buf+len, "%2d: %8d %c %s",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ action = action->next;
+ for (;;) {
+ for (; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ if (!sbusl) break;
+ k++;
+ if (k < 4)
+ action = sbus_actions [(j << 5) + (sbusl << 2) + k].action;
+ else {
+ j++;
+ if (j == nsbi) break;
+ k = 0;
+ action = sbus_actions [(j << 5) + (sbusl << 2)].action;
+ }
+ }
+ len += sprintf(buf+len, "\n");
+ }
+ return len;
+}
+
+void sun4d_free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **actionp;
+ struct irqaction *tmp = NULL;
+ unsigned long flags;
+
+ if (irq < 15)
+ actionp = irq + irq_action;
+ else
+ actionp = &(sbus_actions[irq - (1 << 5)].action);
+ action = *actionp;
+ if (!action) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ if (dev_id) {
+ for (; action; action = action->next) {
+ if (action->dev_id == dev_id)
+ break;
+ tmp = action;
+ }
+ if (!action) {
+ printk("Trying to free free shared IRQ%d\n",irq);
+ return;
+ }
+ } else if (action->flags & SA_SHIRQ) {
+ printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+ return;
+ }
+ if (action->flags & SA_STATIC_ALLOC)
+ {
+ /* This interrupt is marked as specially allocated
+ * so it is a bad idea to free it.
+ */
+ printk("Attempt to free statically allocated IRQ%d (%s)\n",
+ irq, action->name);
+ return;
+ }
+
+ save_and_cli(flags);
+ if (action && tmp)
+ tmp->next = action->next;
+ else
+ *actionp = action->next;
+
+ kfree_s(action, sizeof(struct irqaction));
+
+ if (!(*actionp))
+ disable_irq(irq);
+
+ restore_flags(flags);
+}
+
+extern void unexpected_irq(int, void *, struct pt_regs *);
+
+void sun4d_handler_irq(int irq, struct pt_regs * regs)
+{
+ struct irqaction * action;
+ int cpu = smp_processor_id();
+ /* SBUS IRQ level (1 - 7) */
+ int sbusl = pil_to_sbus[irq];
+
+ /* FIXME: Is this necessary?? */
+ cc_get_ipen();
+
+ cc_set_iclr(1 << irq);
+
+ irq_enter(cpu, irq, regs);
+ kstat.interrupts[irq]++;
+ if (!sbusl) {
+ action = *(irq + irq_action);
+ if (!action)
+ unexpected_irq(irq, 0, regs);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ } else {
+ int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
+ int lock;
+ int sbino;
+ struct sbus_action *actionp;
+ unsigned mask, slot;
+ int sbil = (sbusl << 2);
+
+ bw_clear_intr_mask(sbusl, bus_mask);
+
+ /* Loop for each pending SBI */
+ for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1)
+ if (bus_mask & 1) {
+ mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
+ mask &= (0xf << sbil);
+ actionp = sbus_actions + (sbino << 5) + (sbil);
+ /* Loop for each pending SBI slot */
+ for (slot = (1 << sbil); mask; slot <<= 1, actionp++)
+ if (mask & slot) {
+ mask &= ~slot;
+ action = actionp->action;
+ __asm__ __volatile__ ("ldstub [%1 + 4], %0"
+ : "=r" (lock) : "r" (actionp));
+
+ if (!lock) {
+ if (!action)
+ unexpected_irq(irq, 0, regs);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ actionp->lock = 0;
+ } else
+ actionp->active = 1;
+ release_sbi(SBI2DEVID(sbino), slot);
+ }
+ }
+ }
+ irq_exit(cpu, irq);
+}
+
+int sun4d_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ struct irqaction *action, *tmp = NULL, **actionp;
+ unsigned long flags;
+ int sbusl;
+ unsigned int *ret = NULL;
+ struct linux_sbus_device *sdev = NULL;
+
+ if(irq > 14)
+ return -EINVAL;
+
+ if (!handler)
+ return -EINVAL;
+
+ if (irqflags & SA_DCOOKIE) {
+ struct devid_cookie *d = (struct devid_cookie *)dev_id;
+
+ dev_id = d->real_dev_id;
+ sdev = (struct linux_sbus_device *)d->bus_cookie;
+ ret = &d->ret_ino;
+ }
+
+ sbusl = pil_to_sbus[irq];
+ if (sbusl && !sdev) {
+ printk ("Attempt to register SBUS IRQ %d without DCOOKIE\n", irq);
+ return -EINVAL;
+ }
+ if (sbusl) {
+ actionp = &(sbus_actions[(sdev->my_bus->board << 5) +
+ (sbusl << 2) + sdev->slot].action);
+ *ret = ((sdev->my_bus->board + 1) << 5) +
+ (sbusl << 2) + sdev->slot;
+ } else
+ actionp = irq + irq_action;
+ action = *actionp;
+
+ if (action) {
+ if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+ for (tmp = action; tmp->next; tmp = tmp->next);
+ } else {
+ return -EBUSY;
+ }
+ if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+ return -EBUSY;
+ }
+ action = NULL; /* Or else! */
+ }
+
+ save_and_cli(flags);
+
+ /* If this is flagged as statically allocated then we use our
+ * private struct which is never freed.
+ */
+ if (irqflags & SA_STATIC_ALLOC)
+ if (static_irq_count < MAX_STATIC_ALLOC)
+ action = &static_irqaction[static_irq_count++];
+ else
+ printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+
+ if (action == NULL)
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ GFP_KERNEL);
+
+ if (!action) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ if (tmp)
+ tmp->next = action;
+ else
+ *actionp = action;
+
+ if (ret) irq = *ret;
+
+ if (irq > NR_IRQS) {
+ struct sbus_action *s = sbus_actions + irq - (1 << 5);
+
+ if (s->disabled) {
+ s->disabled = 0;
+ s->active = 0;
+ s->lock = 0;
+ }
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void sun4d_disable_irq(unsigned int irq)
+{
+ struct sbus_action *s;
+
+ if (irq < NR_IRQS) {
+ /* FIXME */
+ printk ("Unable to disable IRQ %d\n", irq);
+ return;
+ }
+ s = sbus_actions + irq - (1 << 5);
+
+ if (s->disabled) return;
+ s->disabled = 1;
+ __asm__ __volatile__ ("
+1: ldstub [%0 + 4], %%g1
+ orcc %%g1, 0, %%g0
+ bne 1b"
+ : : "r" (s) : "g1", "cc");
+}
+
+static void sun4d_enable_irq(unsigned int irq)
+{
+ struct sbus_action *s;
+ struct irqaction *action;
+
+ if (irq < NR_IRQS)
+ /* FIXME */
+ return;
+ s = sbus_actions + irq - (1 << 5);
+
+ if (!s->disabled) return;
+ action = s->action;
+ s->disabled = 0;
+ while (s->active) {
+ s->active = 0;
+ while (action) {
+ /* FIXME: Hope no sbus intr handler uses regs */
+ action->handler(irq, action->dev_id, NULL);
+ action = action->next;
+ }
+ }
+ s->lock = 0;
+}
+
+#ifdef __SMP__
+
+/* +-------+-------------+-----------+------------------------------------+
+ * | bcast | devid | sid | levels mask |
+ * +-------+-------------+-----------+------------------------------------+
+ * 31 30 23 22 15 14 0
+ */
+#define IGEN_MESSAGE(bcast, devid, sid, levels) \
+ (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels))
+
+static void sun4d_send_ipi(int cpu, int level)
+{
+ cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1)));
+}
+
+static void sun4d_clear_ipi(int cpu, int level)
+{
+}
+
+static void sun4d_set_udt(int cpu)
+{
+}
+#endif
+
+static void sun4d_clear_clock_irq(void)
+{
+ volatile unsigned int clear_intr;
+ clear_intr = sun4d_timers->l10_timer_limit;
+}
+
+static void sun4d_clear_profile_irq(int cpu)
+{
+ bw_get_prof_limit(cpu);
+}
+
+static void sun4d_load_profile_irq(int cpu, unsigned int limit)
+{
+ bw_set_prof_limit(cpu, limit);
+}
+
+__initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)))
+{
+ int irq;
+ extern struct prom_cpuinfo linux_cpus[NCPUS];
+ int cpu;
+
+ /* Map the User Timer registers. */
+ sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+ PAGE_SIZE, "user timer", 0xf, 0x0);
+
+ sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
+ master_l10_counter = &sun4d_timers->l10_cur_count;
+ master_l10_limit = &sun4d_timers->l10_timer_limit;
+
+ irq = request_irq(TIMER_IRQ,
+ counter_fn,
+ (SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (irq) {
+ prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ prom_halt();
+ }
+
+ /* Enable user timer free run for CPU 0 in BW */
+ /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
+
+ for(cpu = 0; cpu < NCPUS; cpu++)
+ sun4d_load_profile_irq(linux_cpus[cpu].mid, 0);
+}
+
+__initfunc(unsigned long sun4d_init_sbi_irq(unsigned long memory_start))
+{
+ struct linux_sbus *sbus;
+ struct sbus_action *s;
+ int i;
+ unsigned mask;
+
+ nsbi = 0;
+ for_each_sbus(sbus)
+ nsbi++;
+ memory_start = ((memory_start + 7) & ~7);
+ sbus_actions = (struct sbus_action *)memory_start;
+ memory_start += (nsbi * 8 * 4 * sizeof(struct sbus_action));
+ memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
+ for (i = 0, s = sbus_actions; i < nsbi * 8 * 4; i++, s++) {
+ s->lock = 0xff;
+ s->disabled = 1;
+ }
+ for_each_sbus(sbus) {
+ /* Get rid of pending irqs from PROM */
+ mask = acquire_sbi(sbus->devid, 0xffffffff);
+ if (mask) {
+ printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
+ release_sbi(sbus->devid, mask);
+ }
+ }
+ return memory_start;
+}
+
+__initfunc(void sun4d_init_IRQ(void))
+{
+ __cli();
+
+ enable_irq = sun4d_enable_irq;
+ disable_irq = sun4d_disable_irq;
+ clear_clock_irq = sun4d_clear_clock_irq;
+ clear_profile_irq = sun4d_clear_profile_irq;
+ load_profile_irq = sun4d_load_profile_irq;
+ init_timers = sun4d_init_timers;
+#ifdef __SMP__
+ set_cpu_int = (void (*) (int, int))sun4d_send_ipi;
+ clear_cpu_int = (void (*) (int, int))sun4d_clear_ipi;
+ set_irq_udt = (void (*) (int))sun4d_set_udt;
+#endif
+ /* Cannot enable interrupts until OBP ticker is disabled. */
+}
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index d6420ec68..81db1a4ce 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -163,7 +163,8 @@ static void sun4m_enable_pil_irq(unsigned int pil)
sun4m_interrupts->clear = cpu_pil_to_imask[pil];
}
-void sun4m_send_ipi(int cpu, int level)
+#ifdef __SMP__
+static void sun4m_send_ipi(int cpu, int level)
{
unsigned long mask;
@@ -171,7 +172,7 @@ void sun4m_send_ipi(int cpu, int level)
sun4m_interrupts->cpu_intregs[cpu].set = mask;
}
-void sun4m_clear_ipi(int cpu, int level)
+static void sun4m_clear_ipi(int cpu, int level)
{
unsigned long mask;
@@ -179,10 +180,11 @@ void sun4m_clear_ipi(int cpu, int level)
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
}
-void sun4m_set_udt(int cpu)
+static void sun4m_set_udt(int cpu)
{
sun4m_interrupts->undirected_target = cpu;
}
+#endif
#define OBIO_INTR 0x20
#define TIMER_IRQ (OBIO_INTR | 10)
diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c
index cc0166a41..4f6b2accc 100644
--- a/arch/sparc/kernel/sunos_ioctl.c
+++ b/arch/sparc/kernel/sunos_ioctl.c
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.28 1997/02/15 01:17:05 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.29 1997/09/18 10:37:31 rth Exp $
* sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -45,8 +45,8 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
/* First handle an easy compat. case for tty ldisc. */
if(cmd == TIOCSETD) {
- int *p, ntty = N_TTY;
- int tmp, oldfs;
+ int *p, ntty = N_TTY, tmp;
+ mm_segment_t oldfs;
p = (int *) arg;
ret = -EFAULT;
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index d4044f88f..5b82aa8eb 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.35 1997/04/16 05:56:09 davem Exp $
+/* $Id: sys_sparc.c,v 1.38 1998/01/09 16:42:48 jj Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -17,6 +17,7 @@
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -248,53 +249,99 @@ sparc_breakpoint (struct pt_regs *regs)
unlock_kernel();
}
-extern void check_pending(int signum);
-
asmlinkage int
-sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+sparc_sigaction (int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
{
- struct sigaction new_sa, *p;
+ struct k_sigaction new_ka, old_ka;
+ int ret;
- if(signum < 0) {
+ if (sig < 0) {
current->tss.new_signal = 1;
- signum = -signum;
+ sig = -sig;
}
- if(signum<1 || signum>32)
- return -EINVAL;
- p = signum - 1 + current->sig->action;
- if(action) {
- if(verify_area(VERIFY_READ,action,sizeof(struct sigaction)))
+ if (act) {
+ unsigned long mask;
+
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
- return -EFAULT;
- if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- if(verify_area(VERIFY_READ, new_sa.sa_handler, 1))
- return -EFAULT;
- }
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.ka_restorer = NULL;
}
- if (oldaction) {
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
/* In the clone() case we could copy half consistant
* state to the user, however this could sleep and
* deadlock us if we held the signal lock on SMP. So for
* now I take the easy way out and do no locking.
*/
- if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- return -EFAULT;
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- *p = new_sa;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
+ return ret;
+}
+
+asmlinkage int
+sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
+ void *restorer, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (act) {
+ new_ka.ka_restorer = restorer;
+ if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
+ return -EFAULT;
}
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+/* Just in case some old old binary calls this. */
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+asmlinkage int sys_getdomainname(char *name, int len)
+{
+ int nlen = strlen(system_utsname.domainname);
+
+ if (nlen < len)
+ len = nlen;
+ if(len > __NEW_UTS_LEN)
+ return -EFAULT;
+ if(copy_to_user(name, system_utsname.domainname, len))
+ return -EFAULT;
return 0;
}
+
#ifndef CONFIG_AP1000
/* only AP+ systems have sys_aplib */
asmlinkage int sys_aplib(void)
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index f60ecbe9c..29f00f6b8 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
+/* $Id: sys_sunos.c,v 1.83 1997/12/14 23:24:28 ecd Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -348,35 +348,28 @@ asmlinkage long sunos_getdtablesize(void)
{
return SUNOS_NR_OPEN;
}
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
{
- unsigned long flags;
unsigned long old;
- lock_kernel();
- save_and_cli(flags);
- old = current->blocked;
- current->blocked |= (blk_mask & _BLOCKABLE);
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ old = current->blocked.sig[0];
+ current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return old;
}
asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
{
- unsigned long flags;
unsigned long retval;
- lock_kernel();
- save_and_cli(flags);
- retval = current->blocked;
- current->blocked = newmask & _BLOCKABLE;
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ retval = current->blocked.sig[0];
+ current->blocked.sig[0] = (newmask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return retval;
}
@@ -430,8 +423,6 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_dirent * lastdirent;
struct sunos_dirent_callback buf;
int error = -EBADF;
@@ -444,14 +435,6 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
@@ -464,7 +447,7 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(inode, file, &buf, sunos_filldir);
+ error = file->f_op->readdir(file, &buf, sunos_filldir);
if (error < 0)
goto out;
lastdirent = buf.previous;
@@ -520,8 +503,6 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_direntry * lastdirent;
struct sunos_direntry_callback buf;
int error = -EBADF;
@@ -534,14 +515,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
@@ -554,7 +527,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry);
+ error = file->f_op->readdir(file, &buf, sunos_filldirentry);
if (error < 0)
goto out;
lastdirent = buf.previous;
@@ -1254,58 +1227,47 @@ asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen)
#define SUNOS_SV_INTERRUPT 2
-extern void check_pending(int signum);
-
-asmlinkage int sunos_sigaction(int signum, const struct sigaction *action,
- struct sigaction *oldaction)
+asmlinkage int
+sunos_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
{
- struct sigaction new_sa, *p;
- const int sigaction_size = sizeof (struct sigaction) - sizeof (void *);
+ struct k_sigaction new_ka, old_ka;
+ int ret;
current->personality |= PER_BSD;
- if(signum < 1 || signum > 32)
- return -EINVAL;
- p = signum - 1 + current->sig->action;
+ if(act) {
+ old_sigset_t mask;
- if(action) {
- if(copy_from_user(&new_sa, action, sigaction_size))
- return -EFAULT;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- memset(&new_sa, 0, sizeof(struct sigaction));
- if(copy_from_user(&new_sa, action, sigaction_size))
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags))
return -EFAULT;
- if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- if(verify_area(VERIFY_READ, new_sa.sa_handler, 1))
- return -EFAULT;
- }
- new_sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ __get_user(mask, &act->sa_mask);
+ new_ka.sa.sa_restorer = NULL;
+ new_ka.ka_restorer = NULL;
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
}
- if (oldaction) {
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
/* In the clone() case we could copy half consistant
* state to the user, however this could sleep and
* deadlock us if we held the signal lock on SMP. So for
* now I take the easy way out and do no locking.
* But then again we don't support SunOS lwp's anyways ;-)
*/
- if (copy_to_user(oldaction, p, sigaction_size))
+ old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
return -EFAULT;
-
- if (oldaction->sa_flags & SA_RESTART)
- oldaction->sa_flags &= ~SA_RESTART;
- else
- oldaction->sa_flags |= SUNOS_SV_INTERRUPT;
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- *p = new_sa;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
- }
- return 0;
+ return ret;
}
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 055b85b21..5ea64d2a4 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $
+/* $Id: systbls.S,v 1.68 1997/12/24 17:26:38 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -30,11 +30,11 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_setuid), C_LABEL(sys_getuid)
/*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_pause)
-/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
- .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
+/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
+ .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
.long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
@@ -42,8 +42,8 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
.long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
.long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
- .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread)
+ .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
.long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
@@ -54,10 +54,10 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn)
+ .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask)
+ .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait)
+ .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
@@ -73,13 +73,13 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
- .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
/*150*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
.long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname)
+ .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
@@ -89,12 +89,12 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module)
.long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
- .long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
- .long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
+ .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
/*200*/ .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
.long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
+ .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
.long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
@@ -102,7 +102,7 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
.long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
.long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
- .long C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
+ .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
/* "We are the Knights of the Forest of Ni!!" */
@@ -125,7 +125,6 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_fdatasync)
.long C_LABEL(sys_nfsservctl)
/*255*/ .long C_LABEL(sys_aplib)
- .long C_LABEL(sys_prctl)
.long C_LABEL(sys_nis_syscall)
/* Now the SunOS syscall table. */
@@ -147,7 +146,7 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
.long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil)
+ .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
/*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
@@ -220,4 +219,3 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
/*250*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
- .long C_LABEL(sunos_nosys)
diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S
index 54cc7b460..6a8eba2a8 100644
--- a/arch/sparc/lib/memcpy.S
+++ b/arch/sparc/lib/memcpy.S
@@ -523,6 +523,15 @@ FUNC(memmove)
#endif /* FASTER_REVERSE */
+/* NOTE: This code is executed just for the cases,
+ where %src (=%o1) & 3 is != 0.
+ We need to align it to 4. So, for (%src & 3)
+ 1 we need to do ldub,lduh
+ 2 lduh
+ 3 just ldub
+ so even if it looks weird, the branches
+ are correct here. -jj
+ */
78: /* dword_align */
andcc %o1, 1, %g0
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 84cd1d2e2..bae5d323a 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.26 1997/06/24 15:48:06 jj Exp $
+# $Id: Makefile,v 1.27 1997/11/07 15:01:27 jj Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -10,7 +10,7 @@
O_TARGET := mm.o
O_OBJS := fault.o init.o sun4c.o srmmu.o hypersparc.o viking.o \
tsunami.o loadmmu.o generic.o asyncd.o extable.o \
- turbosparc.o
+ turbosparc.o iommu.o io-unit.o
include $(TOPDIR)/Rules.make
diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c
index 46635db97..d9b17deed 100644
--- a/arch/sparc/mm/asyncd.c
+++ b/arch/sparc/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.10 1997/05/15 21:14:24 davem Exp $
+/* $Id: asyncd.c,v 1.11 1997/12/14 23:24:34 ecd Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -239,7 +239,8 @@ int asyncd(void *unused)
current->session = 1;
current->pgrp = 1;
sprintf(current->comm, "asyncd");
- current->blocked = ~0UL; /* block all signals */
+ sigfillset(&current->blocked); /* block all signals */
+ recalc_sigpending(current);
/* Give asyncd a realtime priority. */
current->policy = SCHED_FIFO;
@@ -259,7 +260,9 @@ int asyncd(void *unused)
save_flags(flags); cli();
while (!async_queue) {
- current->signal = 0;
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
interruptible_sleep_on(&asyncd_wait);
}
diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S
index e6ba7b235..2c27bfdab 100644
--- a/arch/sparc/mm/hypersparc.S
+++ b/arch/sparc/mm/hypersparc.S
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.10 1997/05/27 19:29:58 jj Exp $
+/* $Id: hypersparc.S,v 1.12 1997/11/27 15:42:30 jj Exp $
* hypersparc.S: High speed Hypersparc mmu/cache operations.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -135,8 +135,7 @@ hypersparc_flush_cache_range:
mov SRMMU_CTX_REG, %g7
lda [%g7] ASI_M_MMUREGS, %o3
sta %o0, [%g7] ASI_M_MMUREGS
- sethi %hi(PAGE_SIZE), %g7 /* XXX ick, stupid stalls... */
- sub %o2, %g7, %o0
+ add %o2, -PAGE_SIZE, %o0
1:
or %o0, 0x400, %g7
lda [%g7] ASI_M_FLUSH_PROBE, %g7
@@ -157,10 +156,9 @@ hypersparc_flush_cache_range:
bne 2b
sta %g0, [%o2 + %g5] ASI_M_FLUSH_PAGE
3:
- sethi %hi(PAGE_SIZE), %g7
cmp %o2, %o1
bne 1b
- sub %o2, %g7, %o0
+ add %o2, -PAGE_SIZE, %o0
mov SRMMU_FAULT_STATUS, %g5
lda [%g5] ASI_M_MMUREGS, %g0
mov SRMMU_CTX_REG, %g7
@@ -191,10 +189,9 @@ hypersparc_flush_cache_page:
or %o1, 0x400, %o5
lda [%o5] ASI_M_FLUSH_PROBE, %g1
orcc %g0, %g1, %g0
- sethi %hi(PAGE_SIZE), %g7
be 2f
add %o4, %o4, %o5
- add %o1, %g7, %o1
+ sub %o1, -PAGE_SIZE, %o1
add %o4, %o5, %g1
add %o4, %g1, %g2
add %o4, %g2, %g3
@@ -242,9 +239,8 @@ hypersparc_flush_chunk:
orcc %g5, 0, %g0
be 2f
add %o4, %g1, %g2
- sethi %hi(PAGE_SIZE), %g5
add %o4, %g2, %g3
- add %o0, %g5, %o0
+ sub %o0, -PAGE_SIZE, %o0
add %o4, %g3, %g4
add %o4, %g4, %g5
add %o4, %g5, %g7
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 3dd0e470f..868fc2162 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.49 1997/04/17 21:49:31 jj Exp $
+/* $Id: init.c,v 1.50 1998/01/10 18:19:42 ecd Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -227,9 +227,10 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
addr = KERNBASE;
while(addr < start_mem) {
#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
+ if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end) {
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- else
+ num_physpages--;
+ } else
#endif
mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
addr += PAGE_SIZE;
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
new file mode 100644
index 000000000..519c124c9
--- /dev/null
+++ b/arch/sparc/mm/io-unit.c
@@ -0,0 +1,158 @@
+/* $Id: io-unit.c,v 1.5 1997/12/22 16:09:26 jj Exp $
+ * io-unit.c: IO-UNIT specific routines for memory management.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/pgtable.h>
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/io-unit.h>
+#include <asm/mxcc.h>
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
+#define MKIOPTE(phys) ((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
+
+unsigned long sun4d_dma_base;
+unsigned long sun4d_dma_vbase;
+unsigned long sun4d_dma_size;
+__initfunc(unsigned long
+iounit_init(int sbi_node, int io_node, unsigned long memory_start,
+ unsigned long memory_end, struct linux_sbus *sbus))
+{
+ iopte_t *xpt, *xptend;
+ unsigned long paddr;
+ struct iounit_struct *iounit;
+ struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+
+ memory_start = LONG_ALIGN(memory_start);
+ iounit = (struct iounit_struct *)memory_start;
+ memory_start += sizeof(struct iounit_struct);
+
+ prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
+ sizeof(iommu_promregs));
+ prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
+ xpt = (iopte_t *)
+ sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16),
+ "XPT", iommu_promregs[2].which_io, 0x0);
+ if(!xpt) panic("Cannot map External Page Table.");
+
+ sbus->iommu = (struct iommu_struct *)iounit;
+ iounit->page_table = xpt;
+
+ /* Initialize new table. */
+ paddr = IOUNIT_DMA_BASE - sun4d_dma_base;
+ for (xptend = xpt + (sun4d_dma_size >> PAGE_SHIFT);
+ xpt < xptend; paddr++)
+ *xpt++ = MKIOPTE(paddr);
+ for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
+ xpt < xptend;)
+ *xpt++ = 0;
+
+ return memory_start;
+}
+
+static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */
+#ifdef IOUNIT_DEBUG
+ if ((((unsigned long) vaddr) & PAGE_MASK) < sun4d_dma_vaddr ||
+ (((unsigned long) vaddr) & PAGE_MASK) + len > sun4d_dma_vbase + sun4d_dma_size)
+ panic("Using non-DMA memory for iounit_get_scsi_one");
+#endif
+ return (__u32)(sun4d_dma_base + mmu_v2p((long)vaddr));
+}
+
+static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ /* Viking MXCC is IO coherent, just need to translate the address to DMA handle */
+ for (; sz >= 0; sz--) {
+#ifdef IOUNIT_DEBUG
+ unsigned long page = ((unsigned long) sg[sz].addr) & PAGE_MASK;
+ if (page < sun4d_dma_vbase || page + sg[sz].len > sun4d_dma_vbase + sun4d_dma_size)
+ panic("Using non-DMA memory for iounit_get_scsi_sgl");
+#endif
+ sg[sz].dvma_addr = (__u32) (sun4d_dma_base + mmu_v2p((long)sg[sz].addr));;
+ }
+}
+
+static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+}
+
+static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+}
+
+#ifdef CONFIG_SBUS
+static void iounit_map_dma_area(unsigned long addr, int len)
+{
+ unsigned long page, end;
+ pgprot_t dvma_prot;
+ iopte_t *iopte;
+ struct linux_sbus *sbus;
+
+ dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
+ end = PAGE_ALIGN((addr + len));
+ while(addr < end) {
+ page = get_free_page(GFP_KERNEL);
+ if(!page) {
+ prom_printf("alloc_dvma: Cannot get a dvma page\n");
+ prom_halt();
+ } else {
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+ long i;
+
+ pgdp = pgd_offset(init_task.mm, addr);
+ pmdp = pmd_offset(pgdp, addr);
+ ptep = pte_offset(pmdp, addr);
+
+ set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
+
+ i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
+
+ for_each_sbus(sbus) {
+ struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
+
+ iopte = (iopte_t *)(iounit->page_table + i);
+ *iopte = __iopte(MKIOPTE(mmu_v2p(page)));
+ }
+ }
+ addr += PAGE_SIZE;
+ }
+ flush_cache_all();
+ flush_tlb_all();
+}
+#endif
+
+static char *iounit_lockarea(char *vaddr, unsigned long len)
+{
+ return vaddr;
+}
+
+static void iounit_unlockarea(char *vaddr, unsigned long len)
+{
+}
+
+__initfunc(void ld_mmu_iounit(void))
+{
+ mmu_lockarea = iounit_lockarea;
+ mmu_unlockarea = iounit_unlockarea;
+
+ mmu_get_scsi_one = iounit_get_scsi_one;
+ mmu_get_scsi_sgl = iounit_get_scsi_sgl;
+ mmu_release_scsi_one = iounit_release_scsi_one;
+ mmu_release_scsi_sgl = iounit_release_scsi_sgl;
+
+#ifdef CONFIG_SBUS
+ mmu_map_dma_area = iounit_map_dma_area;
+#endif
+}
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
new file mode 100644
index 000000000..301946326
--- /dev/null
+++ b/arch/sparc/mm/iommu.c
@@ -0,0 +1,284 @@
+/* $Id: iommu.c,v 1.4 1997/11/21 17:31:31 jj Exp $
+ * iommu.c: IOMMU specific routines for memory management.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/pgtable.h>
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/mxcc.h>
+
+/* srmmu.c */
+extern int viking_mxcc_present;
+extern void (*flush_page_for_dma)(unsigned long page);
+extern int flush_page_for_dma_global;
+/* viking.S */
+extern void viking_flush_page(unsigned long page);
+extern void viking_mxcc_flush_page(unsigned long page);
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
+#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ)
+
+static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu,
+ unsigned long kern_end)
+{
+ unsigned long first = page_offset;
+ unsigned long last = kern_end;
+ iopte_t *iopte = iommu->page_table;
+
+ iopte += ((first - iommu->start) >> PAGE_SHIFT);
+ while(first <= last) {
+ *iopte++ = __iopte(MKIOPTE(mmu_v2p(first)));
+ first += PAGE_SIZE;
+ }
+}
+
+__initfunc(unsigned long
+iommu_init(int iommund, unsigned long memory_start,
+ unsigned long memory_end, struct linux_sbus *sbus))
+{
+ unsigned int impl, vers, ptsize;
+ unsigned long tmp;
+ struct iommu_struct *iommu;
+ struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+
+ memory_start = LONG_ALIGN(memory_start);
+ iommu = (struct iommu_struct *) memory_start;
+ memory_start += sizeof(struct iommu_struct);
+ prom_getproperty(iommund, "reg", (void *) iommu_promregs,
+ sizeof(iommu_promregs));
+ iommu->regs = (struct iommu_regs *)
+ sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3),
+ "IOMMU registers", iommu_promregs[0].which_io, 0x0);
+ if(!iommu->regs)
+ panic("Cannot map IOMMU registers.");
+ impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28;
+ vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24;
+ tmp = iommu->regs->control;
+ tmp &= ~(IOMMU_CTRL_RNGE);
+ switch(page_offset & 0xf0000000) {
+ case 0xf0000000:
+ tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB);
+ iommu->plow = iommu->start = 0xf0000000;
+ break;
+ case 0xe0000000:
+ tmp |= (IOMMU_RNGE_512MB | IOMMU_CTRL_ENAB);
+ iommu->plow = iommu->start = 0xe0000000;
+ break;
+ case 0xd0000000:
+ case 0xc0000000:
+ tmp |= (IOMMU_RNGE_1GB | IOMMU_CTRL_ENAB);
+ iommu->plow = iommu->start = 0xc0000000;
+ break;
+ case 0xb0000000:
+ case 0xa0000000:
+ case 0x90000000:
+ case 0x80000000:
+ tmp |= (IOMMU_RNGE_2GB | IOMMU_CTRL_ENAB);
+ iommu->plow = iommu->start = 0x80000000;
+ break;
+ }
+ iommu->regs->control = tmp;
+ iommu_invalidate(iommu->regs);
+ iommu->end = 0xffffffff;
+
+ /* Allocate IOMMU page table */
+ ptsize = iommu->end - iommu->start + 1;
+ ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
+
+ /* Stupid alignment constraints give me a headache. */
+ memory_start = PAGE_ALIGN(memory_start);
+ memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1));
+ iommu->lowest = iommu->page_table = (iopte_t *) memory_start;
+ memory_start += ptsize;
+
+ /* Initialize new table. */
+ flush_cache_all();
+ memset(iommu->page_table, 0, ptsize);
+ iommu_map_dvma_pages_for_iommu(iommu, memory_end);
+ if(viking_mxcc_present) {
+ unsigned long start = (unsigned long) iommu->page_table;
+ unsigned long end = (start + ptsize);
+ while(start < end) {
+ viking_mxcc_flush_page(start);
+ start += PAGE_SIZE;
+ }
+ } else if(flush_page_for_dma == viking_flush_page) {
+ unsigned long start = (unsigned long) iommu->page_table;
+ unsigned long end = (start + ptsize);
+ while(start < end) {
+ viking_flush_page(start);
+ start += PAGE_SIZE;
+ }
+ }
+ flush_tlb_all();
+ iommu->regs->base = mmu_v2p((unsigned long) iommu->page_table) >> 4;
+ iommu_invalidate(iommu->regs);
+
+ sbus->iommu = iommu;
+ printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n",
+ impl, vers, iommu->page_table, ptsize);
+ return memory_start;
+}
+
+static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ return (__u32)vaddr;
+}
+
+static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ flush_page_for_dma(0);
+ return (__u32)vaddr;
+}
+
+static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+ unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
+
+ while(page < ((unsigned long)(vaddr + len))) {
+ flush_page_for_dma(page);
+ page += PAGE_SIZE;
+ }
+ return (__u32)vaddr;
+}
+
+static void iommu_get_scsi_sgl_noflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ for (; sz >= 0; sz--)
+ sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+}
+
+static void iommu_get_scsi_sgl_gflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ flush_page_for_dma(0);
+ for (; sz >= 0; sz--)
+ sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+}
+
+static void iommu_get_scsi_sgl_pflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+ unsigned long page, oldpage = 0;
+
+ while(sz >= 0) {
+ page = ((unsigned long) sg[sz].addr) & PAGE_MASK;
+ if (oldpage == page)
+ page += PAGE_SIZE; /* We flushed that page already */
+ while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) {
+ flush_page_for_dma(page);
+ page += PAGE_SIZE;
+ }
+ sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+ sz--;
+ oldpage = page - PAGE_SIZE;
+ }
+}
+
+static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+}
+
+static void iommu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+}
+
+#ifdef CONFIG_SBUS
+static void iommu_map_dma_area(unsigned long addr, int len)
+{
+ unsigned long page, end;
+ pgprot_t dvma_prot;
+ struct iommu_struct *iommu = SBus_chain->iommu;
+ iopte_t *iopte = iommu->page_table;
+ iopte_t *iopte_first = iopte;
+
+ if(viking_mxcc_present)
+ dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
+ else
+ dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+
+ iopte += ((addr - iommu->start) >> PAGE_SHIFT);
+ end = PAGE_ALIGN((addr + len));
+ while(addr < end) {
+ page = get_free_page(GFP_KERNEL);
+ if(!page) {
+ prom_printf("alloc_dvma: Cannot get a dvma page\n");
+ prom_halt();
+ } else {
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ pgdp = pgd_offset(init_task.mm, addr);
+ pmdp = pmd_offset(pgdp, addr);
+ ptep = pte_offset(pmdp, addr);
+
+ set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
+
+ iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+ }
+ addr += PAGE_SIZE;
+ }
+ flush_cache_all();
+ if(viking_mxcc_present) {
+ unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
+ unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
+ while(start < end) {
+ viking_mxcc_flush_page(start);
+ start += PAGE_SIZE;
+ }
+ } else if(flush_page_for_dma == viking_flush_page) {
+ unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
+ unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
+ while(start < end) {
+ viking_flush_page(start);
+ start += PAGE_SIZE;
+ }
+ }
+ flush_tlb_all();
+ iommu_invalidate(iommu->regs);
+}
+#endif
+
+static char *iommu_lockarea(char *vaddr, unsigned long len)
+{
+ return vaddr;
+}
+
+static void iommu_unlockarea(char *vaddr, unsigned long len)
+{
+}
+
+__initfunc(void ld_mmu_iommu(void))
+{
+ mmu_lockarea = iommu_lockarea;
+ mmu_unlockarea = iommu_unlockarea;
+
+ if (!flush_page_for_dma) {
+ /* IO coherent chip */
+ mmu_get_scsi_one = iommu_get_scsi_one_noflush;
+ mmu_get_scsi_sgl = iommu_get_scsi_sgl_noflush;
+ } else if (flush_page_for_dma_global) {
+ /* flush_page_for_dma flushes everything, no matter of what page is it */
+ mmu_get_scsi_one = iommu_get_scsi_one_gflush;
+ mmu_get_scsi_sgl = iommu_get_scsi_sgl_gflush;
+ } else {
+ mmu_get_scsi_one = iommu_get_scsi_one_pflush;
+ mmu_get_scsi_sgl = iommu_get_scsi_sgl_pflush;
+ }
+ mmu_release_scsi_one = iommu_release_scsi_one;
+ mmu_release_scsi_sgl = iommu_release_scsi_sgl;
+
+#ifdef CONFIG_SBUS
+ mmu_map_dma_area = iommu_map_dma_area;
+#endif
+}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 8c3358a64..b16e3cc1e 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.151 1997/08/28 11:10:54 jj Exp $
+/* $Id: srmmu.c,v 1.156 1997/11/28 14:23:42 jj Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -25,11 +25,11 @@
#include <asm/cache.h>
#include <asm/oplib.h>
#include <asm/sbus.h>
-#include <asm/iommu.h>
#include <asm/asi.h>
#include <asm/msi.h>
#include <asm/a.out.h>
#include <asm/mmu_context.h>
+#include <asm/io-unit.h>
/* Now the cpu specific definitions. */
#include <asm/viking.h>
@@ -47,6 +47,10 @@ int vac_badbits;
extern unsigned long sparc_iobase_vaddr;
+extern unsigned long sun4d_dma_base;
+extern unsigned long sun4d_dma_size;
+extern unsigned long sun4d_dma_vbase;
+
#ifdef __SMP__
#define FLUSH_BEGIN(mm)
#define FLUSH_END
@@ -55,10 +59,14 @@ extern unsigned long sparc_iobase_vaddr;
#define FLUSH_END }
#endif
+static int phys_mem_contig;
+long page_contig_offset;
+
static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
-static void (*flush_page_for_dma)(unsigned long page);
+void (*flush_page_for_dma)(unsigned long page);
+int flush_page_for_dma_global = 1;
static void (*flush_chunk)(unsigned long chunk);
#ifdef __SMP__
static void (*local_flush_page_for_dma)(unsigned long page);
@@ -93,37 +101,13 @@ static struct srmmu_trans *srmmu_p2v_hash[SRMMU_HASHSZ];
#define srmmu_ahashfn(addr) ((addr) >> 24)
-static int viking_mxcc_present = 0;
-
-void srmmu_frob_mem_map(unsigned long start_mem)
-{
- unsigned long bank_start, bank_end;
- unsigned long addr;
- int i;
-
- /* First, mark all pages as invalid. */
- for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE)
- mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
-
- start_mem = PAGE_ALIGN(start_mem);
- for(i = 0; srmmu_map[i].size; i++) {
- bank_start = srmmu_map[i].vbase;
- bank_end = bank_start + srmmu_map[i].size;
- while(bank_start < bank_end) {
- if((bank_start >= KERNBASE) &&
- (bank_start < start_mem)) {
- bank_start += PAGE_SIZE;
- continue;
- }
- mem_map[MAP_NR(bank_start)].flags &= ~(1<<PG_reserved);
- bank_start += PAGE_SIZE;
- }
- }
-}
+int viking_mxcc_present = 0;
/* Physical memory can be _very_ non-contiguous on the sun4m, especially
* the SS10/20 class machines and with the latest openprom revisions.
* So we have to do a quick lookup.
+ * We use the same for SS1000/SC2000 as a fall back, when phys memory is
+ * non-contiguous.
*/
static inline unsigned long srmmu_v2p(unsigned long vaddr)
{
@@ -145,6 +129,21 @@ static inline unsigned long srmmu_p2v(unsigned long paddr)
return 0xffffffffUL;
}
+/* Physical memory on most SS1000/SC2000 can be contiguous, so we handle that case
+ * as a special case to make things faster.
+ */
+static inline unsigned long srmmu_c_v2p(unsigned long vaddr)
+{
+ if (vaddr >= KERNBASE) return vaddr - KERNBASE;
+ return (vaddr - page_contig_offset);
+}
+
+static inline unsigned long srmmu_c_p2v(unsigned long paddr)
+{
+ if (paddr < (0xfd000000 - KERNBASE)) return paddr + KERNBASE;
+ return (paddr + page_contig_offset);
+}
+
/* In general all page table modifications should use the V8 atomic
* swap instruction. This insures the mmu and the cpu are in sync
* with respect to ref/mod bits in the page tables.
@@ -158,6 +157,37 @@ static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)
/* Functions really use this, not srmmu_swap directly. */
#define srmmu_set_entry(ptr, newentry) srmmu_swap((unsigned long *) (ptr), (newentry))
+__initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
+{
+ unsigned long bank_start, bank_end;
+ unsigned long addr;
+ int i;
+
+ /* First, mark all pages as invalid. */
+ for(addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE)
+ mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
+
+ start_mem = PAGE_ALIGN(start_mem);
+ for(i = 0; srmmu_map[i].size; i++) {
+ bank_start = srmmu_map[i].vbase;
+ bank_end = bank_start + srmmu_map[i].size;
+ while(bank_start < bank_end) {
+ if((bank_start >= KERNBASE) &&
+ (bank_start < start_mem)) {
+ bank_start += PAGE_SIZE;
+ continue;
+ }
+ mem_map[MAP_NR(bank_start)].flags &= ~(1<<PG_reserved);
+ bank_start += PAGE_SIZE;
+ }
+ }
+ if (sparc_cpu_model == sun4d) {
+ for (addr = PAGE_OFFSET; MAP_NR(addr) < max_mapnr; addr += PAGE_SIZE)
+ if (addr < sun4d_dma_vbase || addr >= sun4d_dma_vbase + sun4d_dma_size)
+ clear_bit(PG_DMA, &mem_map[MAP_NR(addr)].flags);
+ }
+}
+
/* The very generic SRMMU page table operations. */
static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
@@ -181,6 +211,15 @@ static unsigned long srmmu_pmd_page(pmd_t pmd)
static unsigned long srmmu_pte_page(pte_t pte)
{ return srmmu_device_memory(pte_val(pte))?~0:srmmu_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
+static unsigned long srmmu_c_pgd_page(pgd_t pgd)
+{ return srmmu_device_memory(pgd_val(pgd))?~0:srmmu_c_p2v((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_c_pmd_page(pmd_t pmd)
+{ return srmmu_device_memory(pmd_val(pmd))?~0:srmmu_c_p2v((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_c_pte_page(pte_t pte)
+{ return srmmu_device_memory(pte_val(pte))?~0:srmmu_c_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
+
static int srmmu_pte_none(pte_t pte)
{ return !(pte_val(pte) & 0xFFFFFFF); }
static int srmmu_pte_present(pte_t pte)
@@ -227,6 +266,9 @@ static pte_t srmmu_pte_mkyoung(pte_t pte) { return __pte(pte_val(pte) | SRMM
static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
{ return __pte(((srmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); }
+static pte_t srmmu_c_mk_pte(unsigned long page, pgprot_t pgprot)
+{ return __pte(((srmmu_c_v2p(page)) >> 4) | pgprot_val(pgprot)); }
+
static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
{ return __pte(((page) >> 4) | pgprot_val(pgprot)); }
@@ -250,6 +292,21 @@ static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) ptep) >> 4)));
}
+static void srmmu_c_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
+{
+ set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pgdp) >> 4)));
+}
+
+static void srmmu_c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{
+ set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) pmdp) >> 4)));
+}
+
+static void srmmu_c_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+ set_pte((pte_t *)pmdp, (SRMMU_ET_PTD | (srmmu_c_v2p((unsigned long) ptep) >> 4)));
+}
+
static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
{
return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot));
@@ -273,6 +330,18 @@ static pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
}
+/* Find an entry in the second-level page table.. */
+static pmd_t *srmmu_c_pmd_offset(pgd_t * dir, unsigned long address)
+{
+ return (pmd_t *) srmmu_c_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+}
+
+/* Find an entry in the third-level page table.. */
+static pte_t *srmmu_c_pte_offset(pmd_t * dir, unsigned long address)
+{
+ return (pte_t *) srmmu_c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+}
+
/* This must update the context table entry for this process. */
static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
{
@@ -560,7 +629,7 @@ static pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
pmd_set(pmd, BAD_PAGETABLE);
return NULL;
}
- return (pte_t *) srmmu_pmd_page(*pmd) + address;
+ return (pte_t *) pmd_page(*pmd) + address;
}
static void srmmu_pmd_free_kernel(pmd_t *pmd)
@@ -617,7 +686,7 @@ static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
pmd_set(pmd, BAD_PAGETABLE);
return NULL;
}
- return ((pte_t *) srmmu_pmd_page(*pmd)) + address;
+ return ((pte_t *) pmd_page(*pmd)) + address;
}
/* Real three-level page tables on SRMMU. */
@@ -646,7 +715,7 @@ static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
return NULL;
}
- return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+ return (pmd_t *) pgd_page(*pgd) + address;
}
static void srmmu_pgd_free(pgd_t *pgd)
@@ -789,8 +858,8 @@ void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_ty
physaddr &= PAGE_MASK;
pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
- pmdp = srmmu_pmd_offset(pgdp, virt_addr);
- ptep = srmmu_pte_offset(pmdp, virt_addr);
+ pmdp = pmd_offset(pgdp, virt_addr);
+ ptep = pte_offset(pmdp, virt_addr);
tmp = (physaddr >> 4) | SRMMU_ET_PTE;
/* I need to test whether this is consistent over all
@@ -814,23 +883,14 @@ void srmmu_unmapioaddr(unsigned long virt_addr)
pte_t *ptep;
pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
- pmdp = srmmu_pmd_offset(pgdp, virt_addr);
- ptep = srmmu_pte_offset(pmdp, virt_addr);
+ pmdp = pmd_offset(pgdp, virt_addr);
+ ptep = pte_offset(pmdp, virt_addr);
/* No need to flush uncacheable page. */
- set_pte(ptep, srmmu_mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
+ set_pte(ptep, mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
flush_tlb_all();
}
-static char *srmmu_lockarea(char *vaddr, unsigned long len)
-{
- return vaddr;
-}
-
-static void srmmu_unlockarea(char *vaddr, unsigned long len)
-{
-}
-
/* This is used in many routines below. */
#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
@@ -844,7 +904,7 @@ static void srmmu_unlockarea(char *vaddr, unsigned long len)
*/
struct task_struct *srmmu_alloc_task_struct(void)
{
- return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0);
+ return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1);
}
static void srmmu_free_task_struct(struct task_struct *tsk)
@@ -1131,10 +1191,12 @@ static void cypress_flush_chunk(unsigned long chunk)
cypress_flush_page_to_ram(chunk);
}
+#if NOTUSED
/* Cypress is also IO cache coherent. */
static void cypress_flush_page_for_dma(unsigned long page)
{
}
+#endif
/* Cypress has unified L2 VIPT, from which both instructions and data
* are stored. It does not have an onboard icache of any sort, therefore
@@ -1220,6 +1282,9 @@ extern void viking_flush_sig_insns(struct mm_struct *mm, unsigned long addr);
extern void viking_flush_page(unsigned long page);
extern void viking_mxcc_flush_page(unsigned long page);
extern void viking_flush_chunk(unsigned long chunk);
+extern void viking_c_flush_page(unsigned long page);
+extern void viking_c_mxcc_flush_page(unsigned long page);
+extern void viking_c_flush_chunk(unsigned long chunk);
extern void viking_mxcc_flush_chunk(unsigned long chunk);
extern void viking_flush_tlb_all(void);
extern void viking_flush_tlb_mm(struct mm_struct *mm);
@@ -1345,184 +1410,6 @@ static void hypersparc_init_new_context(struct mm_struct *mm)
srmmu_set_context(mm->context);
}
-/* IOMMU things go here. */
-
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
-#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
-#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ)
-
-static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu,
- unsigned long kern_end)
-{
- unsigned long first = page_offset;
- unsigned long last = kern_end;
- iopte_t *iopte = iommu->page_table;
-
- iopte += ((first - iommu->start) >> PAGE_SHIFT);
- while(first <= last) {
- *iopte++ = __iopte(MKIOPTE(srmmu_v2p(first)));
- first += PAGE_SIZE;
- }
-}
-
-unsigned long iommu_init(int iommund, unsigned long memory_start,
- unsigned long memory_end, struct linux_sbus *sbus)
-{
- unsigned int impl, vers, ptsize;
- unsigned long tmp;
- struct iommu_struct *iommu;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-
- memory_start = LONG_ALIGN(memory_start);
- iommu = (struct iommu_struct *) memory_start;
- memory_start += sizeof(struct iommu_struct);
- prom_getproperty(iommund, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs));
- iommu->regs = (struct iommu_regs *)
- sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3),
- "IOMMU registers", iommu_promregs[0].which_io, 0x0);
- if(!iommu->regs)
- panic("Cannot map IOMMU registers.");
- impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28;
- vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24;
- tmp = iommu->regs->control;
- tmp &= ~(IOMMU_CTRL_RNGE);
- switch(page_offset & 0xf0000000) {
- case 0xf0000000:
- tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB);
- iommu->plow = iommu->start = 0xf0000000;
- break;
- case 0xe0000000:
- tmp |= (IOMMU_RNGE_512MB | IOMMU_CTRL_ENAB);
- iommu->plow = iommu->start = 0xe0000000;
- break;
- case 0xd0000000:
- case 0xc0000000:
- tmp |= (IOMMU_RNGE_1GB | IOMMU_CTRL_ENAB);
- iommu->plow = iommu->start = 0xc0000000;
- break;
- case 0xb0000000:
- case 0xa0000000:
- case 0x90000000:
- case 0x80000000:
- tmp |= (IOMMU_RNGE_2GB | IOMMU_CTRL_ENAB);
- iommu->plow = iommu->start = 0x80000000;
- break;
- }
- iommu->regs->control = tmp;
- iommu_invalidate(iommu->regs);
- iommu->end = 0xffffffff;
-
- /* Allocate IOMMU page table */
- ptsize = iommu->end - iommu->start + 1;
- ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
-
- /* Stupid alignment constraints give me a headache. */
- memory_start = PAGE_ALIGN(memory_start);
- memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1));
- iommu->lowest = iommu->page_table = (iopte_t *) memory_start;
- memory_start += ptsize;
-
- /* Initialize new table. */
- flush_cache_all();
- memset(iommu->page_table, 0, ptsize);
- srmmu_map_dvma_pages_for_iommu(iommu, memory_end);
- if(viking_mxcc_present) {
- unsigned long start = (unsigned long) iommu->page_table;
- unsigned long end = (start + ptsize);
- while(start < end) {
- viking_mxcc_flush_page(start);
- start += PAGE_SIZE;
- }
- } else if(flush_page_for_dma == viking_flush_page) {
- unsigned long start = (unsigned long) iommu->page_table;
- unsigned long end = (start + ptsize);
- while(start < end) {
- viking_flush_page(start);
- start += PAGE_SIZE;
- }
- }
- flush_tlb_all();
- iommu->regs->base = srmmu_v2p((unsigned long) iommu->page_table) >> 4;
- iommu_invalidate(iommu->regs);
-
- sbus->iommu = iommu;
- printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n",
- impl, vers, iommu->page_table, ptsize);
- return memory_start;
-}
-
-void iommu_sun4d_init(int sbi_node, struct linux_sbus *sbus)
-{
- u32 *iommu;
- struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-
- prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
- sizeof(iommu_promregs));
- iommu = (u32 *)
- sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16),
- "XPT", iommu_promregs[2].which_io, 0x0);
- if(!iommu)
- panic("Cannot map External Page Table.");
-
- /* Initialize new table. */
- flush_cache_all();
- memset(iommu, 0, 16 * PAGE_SIZE);
- if(viking_mxcc_present) {
- unsigned long start = (unsigned long) iommu;
- unsigned long end = (start + 16 * PAGE_SIZE);
- while(start < end) {
- viking_mxcc_flush_page(start);
- start += PAGE_SIZE;
- }
- } else if(flush_page_for_dma == viking_flush_page) {
- unsigned long start = (unsigned long) iommu;
- unsigned long end = (start + 16 * PAGE_SIZE);
- while(start < end) {
- viking_flush_page(start);
- start += PAGE_SIZE;
- }
- }
- flush_tlb_all();
-
- sbus->iommu = (struct iommu_struct *)iommu;
-}
-
-static __u32 srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
-{
- unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
-
- while(page < ((unsigned long)(vaddr + len))) {
- flush_page_for_dma(page);
- page += PAGE_SIZE;
- }
- return (__u32)vaddr;
-}
-
-static void srmmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
-{
- unsigned long page;
-
- while(sz >= 0) {
- page = ((unsigned long) sg[sz].addr) & PAGE_MASK;
- while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) {
- flush_page_for_dma(page);
- page += PAGE_SIZE;
- }
- sg[sz].dvma_addr = (__u32) (sg[sz].addr);
- sz--;
- }
-}
-
-static void srmmu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
-{
-}
-
-static void srmmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
-{
-}
-
static unsigned long mempool;
/* NOTE: All of this startup code assumes the low 16mb (approx.) of
@@ -1652,63 +1539,6 @@ void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end)
}
}
-#ifdef CONFIG_SBUS
-static void srmmu_map_dma_area(unsigned long addr, int len)
-{
- unsigned long page, end;
- pgprot_t dvma_prot;
- struct iommu_struct *iommu = SBus_chain->iommu;
- iopte_t *iopte = iommu->page_table;
- iopte_t *iopte_first = iopte;
-
- if(viking_mxcc_present)
- dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
- else
- dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
-
- iopte += ((addr - iommu->start) >> PAGE_SHIFT);
- end = PAGE_ALIGN((addr + len));
- while(addr < end) {
- page = get_free_page(GFP_KERNEL);
- if(!page) {
- prom_printf("alloc_dvma: Cannot get a dvma page\n");
- prom_halt();
- } else {
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
-
- pgdp = srmmu_pgd_offset(init_task.mm, addr);
- pmdp = srmmu_pmd_offset(pgdp, addr);
- ptep = srmmu_pte_offset(pmdp, addr);
-
- set_pte(ptep, pte_val(srmmu_mk_pte(page, dvma_prot)));
-
- iopte_val(*iopte++) = MKIOPTE(srmmu_v2p(page));
- }
- addr += PAGE_SIZE;
- }
- flush_cache_all();
- if(viking_mxcc_present) {
- unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
- unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
- while(start < end) {
- viking_mxcc_flush_page(start);
- start += PAGE_SIZE;
- }
- } else if(flush_page_for_dma == viking_flush_page) {
- unsigned long start = ((unsigned long) iopte_first) & PAGE_MASK;
- unsigned long end = PAGE_ALIGN(((unsigned long) iopte));
- while(start < end) {
- viking_flush_page(start);
- start += PAGE_SIZE;
- }
- }
- flush_tlb_all();
- iommu_invalidate(iommu->regs);
-}
-#endif
-
/* #define DEBUG_MAP_KERNEL */
#ifdef DEBUG_MAP_KERNEL
@@ -2068,6 +1898,59 @@ check_and_return:
srmmu_p2v_hash[srmmu_ahashfn(addr)] = &srmmu_map[entry];
}
+ page_contig_offset = page_offset - (0xfd000000 - KERNBASE);
+ phys_mem_contig = 1;
+ for(entry = 0; srmmu_map[entry].size; entry++)
+ if (srmmu_map[entry].pbase != srmmu_c_v2p (srmmu_map[entry].vbase)) {
+ phys_mem_contig = 0;
+ break;
+ }
+ if (phys_mem_contig) {
+ printk ("SRMMU: Physical memory is contiguous, bypassing VA<->PA hashes\n");
+ pte_page = srmmu_c_pte_page;
+ pmd_page = srmmu_c_pmd_page;
+ pgd_page = srmmu_c_pgd_page;
+ mk_pte = srmmu_c_mk_pte;
+ pte_offset = srmmu_c_pte_offset;
+ pmd_offset = srmmu_c_pmd_offset;
+ if (ctxd_set == srmmu_ctxd_set)
+ ctxd_set = srmmu_c_ctxd_set;
+ pgd_set = srmmu_c_pgd_set;
+ pmd_set = srmmu_c_pmd_set;
+ mmu_v2p = srmmu_c_v2p;
+ mmu_p2v = srmmu_c_p2v;
+ if (flush_chunk == viking_flush_chunk)
+ flush_chunk = viking_c_flush_chunk;
+ }
+
+ if (sparc_cpu_model == sun4d) {
+ int i, j = -1;
+ unsigned long bank_start, bank_end;
+
+ sun4d_dma_vbase = 0;
+ sun4d_dma_size = IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE;
+ for (i = 0; srmmu_map[i].size; i++) {
+ bank_start = srmmu_map[i].vbase;
+ bank_end = bank_start + srmmu_map[i].size;
+ if (bank_start <= KERNBASE && bank_end > KERNBASE)
+ j = i;
+ else if (srmmu_map[i].size >= sun4d_dma_size) {
+ sun4d_dma_vbase = srmmu_map[i].vbase;
+ break;
+ }
+ }
+ if (!sun4d_dma_vbase && j != -1) {
+ if (srmmu_map[j].size >= sun4d_dma_size + 0x1000000)
+ sun4d_dma_vbase = srmmu_map[j].vbase + 0x1000000;
+ else {
+ sun4d_dma_vbase = srmmu_map[j].vbase;
+ if (srmmu_map[j].size < sun4d_dma_size)
+ sun4d_dma_size = srmmu_map[j].size;
+ }
+ }
+ sun4d_dma_base = IOUNIT_DMA_BASE - srmmu_v2p(sun4d_dma_vbase);
+ }
+
return; /* SUCCESS! */
}
@@ -2104,7 +1987,7 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */
if (sparc_cpu_model == sun4d)
- num_contexts = 65536; /* We now it is Viking */
+ num_contexts = 65536; /* We know it is Viking */
else {
/* Find the number of contexts on the srmmu. */
cpunode = prom_getchild(prom_root_node);
@@ -2218,8 +2101,8 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
{
if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
struct vm_area_struct *vmaring;
- struct dentry *dentry;
- struct inode *inode = NULL;
+ struct file *file;
+ struct inode *inode;
unsigned long flags, offset, vaddr, start;
int alias_found = 0;
pgd_t *pgdp;
@@ -2228,11 +2111,10 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
save_and_cli(flags);
- dentry = vma->vm_dentry;
- if(dentry)
- inode = dentry->d_inode;
- if (!inode)
+ file = vma->vm_file;
+ if (!file)
goto done;
+ inode = file->f_dentry->d_inode;
offset = (address & PAGE_MASK) - vma->vm_start;
vmaring = inode->i_mmap;
do {
@@ -2381,11 +2263,6 @@ static void poke_hypersparc(void)
hyper_flush_whole_icache();
clear = srmmu_get_faddr();
clear = srmmu_get_fstatus();
-
-#ifdef __SMP__
- /* Avoid unnecessary cross calls. */
- flush_page_for_dma = local_flush_page_for_dma;
-#endif
}
__initfunc(static void init_hypersparc(void))
@@ -2407,7 +2284,7 @@ __initfunc(static void init_hypersparc(void))
flush_page_to_ram = hypersparc_flush_page_to_ram;
flush_sig_insns = hypersparc_flush_sig_insns;
- flush_page_for_dma = hypersparc_flush_page_for_dma;
+ flush_page_for_dma = NULL /* hypersparc_flush_page_for_dma */;
flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */
@@ -2480,7 +2357,7 @@ __initfunc(static void init_cypress_common(void))
flush_page_to_ram = cypress_flush_page_to_ram;
flush_sig_insns = cypress_flush_sig_insns;
- flush_page_for_dma = cypress_flush_page_for_dma;
+ flush_page_for_dma = NULL /* cypress_flush_page_for_dma */;
sparc_update_rootmmu_dir = cypress_update_rootmmu_dir;
update_mmu_cache = srmmu_vac_update_mmu_cache;
@@ -2671,7 +2548,7 @@ __initfunc(static void init_turbosparc(void))
#endif
flush_sig_insns = turbosparc_flush_sig_insns;
- flush_page_for_dma = hypersparc_flush_page_for_dma;
+ flush_page_for_dma = NULL /* turbosparc_flush_page_for_dma */;
poke_srmmu = poke_turbosparc;
}
@@ -2761,6 +2638,9 @@ static void poke_viking(void)
#ifdef __SMP__
/* Avoid unnecessary cross calls. */
flush_cache_all = local_flush_cache_all;
+ flush_cache_mm = local_flush_cache_mm;
+ flush_cache_range = local_flush_cache_range;
+ flush_cache_page = local_flush_cache_page;
flush_page_to_ram = local_flush_page_to_ram;
flush_sig_insns = local_flush_sig_insns;
flush_page_for_dma = local_flush_page_for_dma;
@@ -2796,6 +2676,9 @@ __initfunc(static void init_viking(void))
* which we use the IOMMU.
*/
flush_page_for_dma = viking_flush_page;
+ /* Also, this is so far the only chip which actually uses
+ the page argument to flush_page_for_dma */
+ flush_page_for_dma_global = 0;
} else {
srmmu_name = "TI Viking/MXCC";
viking_mxcc_present = 1;
@@ -2803,7 +2686,7 @@ __initfunc(static void init_viking(void))
flush_chunk = viking_mxcc_flush_chunk; /* local flush _only_ */
/* MXCC vikings lack the DMA snooping bug. */
- flush_page_for_dma = viking_flush_page_for_dma;
+ flush_page_for_dma = NULL /* viking_flush_page_for_dma */;
}
flush_cache_all = viking_flush_cache_all;
@@ -2951,9 +2834,12 @@ static void smp_flush_page_for_dma(unsigned long page)
#endif
-/* Load up routines and constants for sun4m mmu */
+/* Load up routines and constants for sun4m and sun4d mmu */
__initfunc(void ld_mmu_srmmu(void))
{
+ extern void ld_mmu_iommu(void);
+ extern void ld_mmu_iounit(void);
+
/* First the constants */
pmd_shift = SRMMU_PMD_SHIFT;
pmd_size = SRMMU_PMD_SIZE;
@@ -3031,18 +2917,7 @@ __initfunc(void ld_mmu_srmmu(void))
pte_mkyoung = srmmu_pte_mkyoung;
update_mmu_cache = srmmu_update_mmu_cache;
destroy_context = srmmu_destroy_context;
- mmu_lockarea = srmmu_lockarea;
- mmu_unlockarea = srmmu_unlockarea;
-
- mmu_get_scsi_one = srmmu_get_scsi_one;
- mmu_get_scsi_sgl = srmmu_get_scsi_sgl;
- mmu_release_scsi_one = srmmu_release_scsi_one;
- mmu_release_scsi_sgl = srmmu_release_scsi_sgl;
-
-#ifdef CONFIG_SBUS
- mmu_map_dma_area = srmmu_map_dma_area;
-#endif
-
+
mmu_info = srmmu_mmu_info;
mmu_v2p = srmmu_v2p;
mmu_p2v = srmmu_p2v;
@@ -3085,6 +2960,11 @@ __initfunc(void ld_mmu_srmmu(void))
flush_tlb_page = smp_flush_tlb_page;
flush_page_to_ram = smp_flush_page_to_ram;
flush_sig_insns = smp_flush_sig_insns;
- flush_page_for_dma = smp_flush_page_for_dma;
+ if (flush_page_for_dma)
+ flush_page_for_dma = smp_flush_page_for_dma;
#endif
+ if (sparc_cpu_model == sun4d)
+ ld_mmu_iounit();
+ else
+ ld_mmu_iommu();
}
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 7ffca1033..c70753fa4 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1185,7 +1185,7 @@ static struct task_struct *sun4c_alloc_task_struct(void)
unsigned long addr, pages;
int entry;
- pages = __get_free_pages(GFP_KERNEL, 1, 0);
+ pages = __get_free_pages(GFP_KERNEL, 1);
if(!pages)
return (struct task_struct *) 0;
diff --git a/arch/sparc/mm/turbosparc.S b/arch/sparc/mm/turbosparc.S
index 5660d4f84..415f09056 100644
--- a/arch/sparc/mm/turbosparc.S
+++ b/arch/sparc/mm/turbosparc.S
@@ -1,5 +1,5 @@
-/* $Id: turbosparc.S,v 1.1 1997/07/18 06:26:22 ralf Exp $
- * turbosparc.S: High speed Hypersparc mmu/cache operations.
+/* $Id: turbosparc.S,v 1.2 1998/03/16 08:40:31 ralf Exp $
+ * turbosparc.S: High speed TurboSparc mmu/cache operations.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index 19d426ec7..b05b7b416 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -1,7 +1,8 @@
-/* $Id: viking.S,v 1.3 1997/05/04 10:02:14 ecd Exp $
+/* $Id: viking.S,v 1.6 1997/11/27 15:42:32 jj Exp $
* viking.S: High speed Viking cache/mmu operations
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <asm/ptrace.h>
@@ -36,6 +37,20 @@
.globl viking_flush_tlb_all, viking_flush_tlb_mm
.globl viking_flush_tlb_range, viking_flush_tlb_page
+ .globl viking_c_mxcc_flush_page
+ .globl viking_c_flush_page, viking_c_flush_chunk
+
+viking_c_flush_page:
+viking_c_flush_chunk:
+ sethi %hi(KERNBASE), %g2
+ cmp %o0, %g2
+ bgeu 2f
+ sub %o0, %g2, %g3
+ sethi %hi(C_LABEL(page_contig_offset)), %g2
+ ld [%g2 + %lo(C_LABEL(page_contig_offset))], %g2
+ ba 2f
+ sub %o0, %g2, %g3
+
viking_flush_page:
viking_flush_chunk:
sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
@@ -56,13 +71,14 @@ viking_flush_chunk:
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
add %g2, %o0, %g3
- srl %g3, 12, %g1 ! ppage >> 12
+2: srl %g3, 12, %g1 ! ppage >> 12
clr %o1 ! set counter, 0 - 127
sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3
sethi %hi(0x80000000), %o4
sethi %hi(VIKING_PTAG_VALID | VIKING_PTAG_DIRTY), %o5
- sethi %hi(PAGE_SIZE), %o0
+ sethi %hi(2*PAGE_SIZE), %o0
+ sethi %hi(PAGE_SIZE), %g7
clr %o2 ! block counter, 0 - 3
5:
sll %o1, 5, %g4
@@ -83,20 +99,16 @@ viking_flush_chunk:
add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5)
ld [%g2], %g3
+ ld [%g2 + %g7], %g3
add %g2, %o0, %g2
ld [%g2], %g3
+ ld [%g2 + %g7], %g3
add %g2, %o0, %g2
ld [%g2], %g3
+ ld [%g2 + %g7], %g3
add %g2, %o0, %g2
ld [%g2], %g3
- add %g2, %o0, %g2
- ld [%g2], %g3
- add %g2, %o0, %g2
- ld [%g2], %g3
- add %g2, %o0, %g2
- ld [%g2], %g3
- add %g2, %o0, %g2
- ld [%g2], %g3
+ ld [%g2 + %g7], %g3
b 8f
inc %o1
@@ -115,6 +127,15 @@ viking_flush_chunk:
retl
nop
+viking_c_mxcc_flush_page:
+ sethi %hi(KERNBASE), %g2
+ cmp %o0, %g2
+ bgeu 2f
+ sub %o0, %g2, %g3
+ sethi %hi(C_LABEL(page_contig_offset)), %g2
+ ld [%g2 + %lo(C_LABEL(page_contig_offset))], %g2
+ ba 2f
+ sub %o0, %g2, %g3
viking_mxcc_flush_page:
sethi %hi(C_LABEL(srmmu_v2p_hash)), %g2
@@ -134,17 +155,12 @@ viking_mxcc_flush_page:
ld [%g3], %o1
sub %o0, %o1, %g2
ld [%g3 + 4], %o0
- sethi %hi(PAGE_SIZE), %g4
add %g2, %o0, %g3
- add %g3, %g4, %g3 ! ppage + PAGE_SIZE
-
+2: sub %g3, -PAGE_SIZE, %g3 ! ppage + PAGE_SIZE
mov 0x10, %g2 ! set cacheable bit
- sethi %hi(MXCC_SRCSTREAM), %o2
- or %o2, %lo(MXCC_SRCSTREAM), %o2
- sethi %hi(MXCC_DESSTREAM), %o3
+ sethi %hi(MXCC_SRCSTREAM), %o3 ! assume %hi(MXCC_SRCSTREAM) == %hi(MXCC_DESTSTREAM)
+ or %o3, %lo(MXCC_SRCSTREAM), %o2
or %o3, %lo(MXCC_DESSTREAM), %o3
-
-5:
sub %g3, MXCC_STREAM_SIZE, %g3
6:
stda %g2, [%o2] ASI_M_MXCC
@@ -168,7 +184,6 @@ viking_flush_cache_page:
nop
viking_flush_tlb_all:
- WINDOW_FLUSH(%g4, %g5)
mov 0x400, %g1
retl
sta %g0, [%g1] ASI_M_FLUSH_PROBE
@@ -179,16 +194,15 @@ viking_flush_tlb_mm:
lda [%g1] ASI_M_MMUREGS, %g5
#ifndef __SMP__
cmp %o1, -1
- be viking_flush_tlb_mm_out
+ be 1f
#endif
- WINDOW_FLUSH(%g2, %g3)
-
mov 0x300, %g2
sta %o1, [%g1] ASI_M_MMUREGS
sta %g0, [%g2] ASI_M_FLUSH_PROBE
-viking_flush_tlb_mm_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+1: retl
+ nop
viking_flush_tlb_range:
mov SRMMU_CTX_REG, %g1
@@ -196,42 +210,39 @@ viking_flush_tlb_range:
lda [%g1] ASI_M_MMUREGS, %g5
#ifndef __SMP__
cmp %o3, -1
- be viking_flush_tlb_range_out
+ be 2f
#endif
- WINDOW_FLUSH(%g2, %g3)
-
srl %o1, SRMMU_PGDIR_SHIFT, %o1
sta %o3, [%g1] ASI_M_MMUREGS
sll %o1, SRMMU_PGDIR_SHIFT, %o1
sethi %hi(1 << SRMMU_PGDIR_SHIFT), %o4
add %o1, 0x200, %o1
sta %g0, [%o1] ASI_M_FLUSH_PROBE
-1:
- add %o1, %o4, %o1
+1: add %o1, %o4, %o1
cmp %o1, %o2
blu,a 1b
sta %g0, [%o1] ASI_M_FLUSH_PROBE
-viking_flush_tlb_range_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+2: retl
+ nop
viking_flush_tlb_page:
ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
- and %o1, PAGE_MASK, %o1
lda [%g1] ASI_M_MMUREGS, %g5
#ifndef __SMP__
cmp %o3, -1
- be viking_flush_tlb_page_out
+ be 1f
#endif
- WINDOW_FLUSH(%g2, %g3)
-
+ and %o1, PAGE_MASK, %o1
sta %o3, [%g1] ASI_M_MMUREGS
sta %g0, [%o1] ASI_M_FLUSH_PROBE
-viking_flush_tlb_page_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+1: retl
+ nop
viking_flush_page_to_ram:
viking_flush_page_for_dma:
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index 1d458c0d1..7f7b1da54 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -1,7 +1,8 @@
-/* $Id: ranges.c,v 1.8 1997/02/04 07:28:29 davem Exp $
+/* $Id: ranges.c,v 1.10 1997/12/19 12:37:18 jj Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/init.h>
@@ -22,7 +23,9 @@ prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
for(regc=0; regc < nregs; regc++) {
for(rngc=0; rngc < nranges; rngc++)
- if(regp[regc].which_io == rangep[rngc].ot_child_space)
+ if(regp[regc].which_io == rangep[rngc].ot_child_space &&
+ regp[regc].phys_addr >= rangep[rngc].ot_child_base &&
+ regp[regc].phys_addr + regp[regc].reg_size <= rangep[rngc].ot_child_base + rangep[rngc].or_size)
break; /* Fount it */
if(rngc==nranges) /* oops */
prom_printf("adjust_regs: Could not find range with matching bus type...\n");
@@ -39,10 +42,15 @@ prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
for(rng1c=0; rng1c < nranges1; rng1c++) {
for(rng2c=0; rng2c < nranges2; rng2c++)
- if(ranges1[rng1c].ot_child_space ==
- ranges2[rng2c].ot_child_space) break;
+ if(ranges1[rng1c].ot_parent_space == ranges2[rng2c].ot_child_space &&
+ ranges1[rng1c].ot_parent_base >= ranges2[rng2c].ot_child_base &&
+ ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base > 0U)
+ break;
if(rng2c == nranges2) /* oops */
prom_printf("adjust_ranges: Could not find matching bus type...\n");
+ else if (ranges1[rng1c].ot_parent_base + ranges1[rng1c].or_size > ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size)
+ ranges1[rng1c].or_size =
+ ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base;
ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space;
ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base;
}
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c
index 295ce5355..616180e81 100644
--- a/arch/sparc/prom/tree.c
+++ b/arch/sparc/prom/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.19 1997/06/27 14:52:54 jj Exp $
+/* $Id: tree.c,v 1.22 1997/09/25 02:19:22 davem Exp $
* tree.c: Basic device tree traversal/scanning for the Linux
* prom library.
*
@@ -229,36 +229,40 @@ int prom_getname (int node, char *buffer, int len)
return 0;
}
-/* Return the first property type for node 'node'.
- */
-char * prom_firstprop(int node, char *buffer)
+/* Interal version of nextprop that does not alter return values. */
+char * __prom_nextprop(int node, char * oprop)
{
unsigned long flags;
- char *ret;
+ char *prop;
- if(node == -1) return "";
- save_flags(flags); cli();
- ret = prom_nodeops->no_nextprop(node, (char *) 0x0);
+ save_and_cli(flags);
+ prop = prom_nodeops->no_nextprop(node, oprop);
restore_current();
restore_flags(flags);
- return ret;
+
+ return prop;
+}
+
+/* Return the first property name for node 'node'. */
+/* buffer is unused argument, but as v9 uses it, we need to have the same interface */
+char * prom_firstprop(int node, char *bufer)
+{
+ if (node == 0 || node == -1)
+ return "";
+
+ return __prom_nextprop(node, "");
}
/* Return the property type string after property type 'oprop'
- * at node 'node' . Returns NULL string if no more
+ * at node 'node' . Returns empty string if no more
* property types for this node.
*/
char * prom_nextprop(int node, char *oprop, char *buffer)
{
- char *ret;
- unsigned long flags;
+ if (node == 0 || node == -1)
+ return "";
- if(node == -1) return "";
- save_flags(flags); cli();
- ret = prom_nodeops->no_nextprop(node, oprop);
- restore_current();
- restore_flags(flags);
- return ret;
+ return __prom_nextprop(node, oprop);
}
int prom_finddevice(char *name)