diff options
Diffstat (limited to 'arch/sparc')
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 ®s->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(¤t->sigmask_lock); - current->signal |= (1 << (current->exit_code - 1)); - spin_unlock_irq(¤t->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(¤t->sigmask_lock); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, set); + recalc_sigpending(current); spin_unlock_irq(¤t->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(¤t->sigmask_lock); + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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 = ¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked, signr); spin_unlock_irq(¤t->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 = ¤t->blocked; + + for (;;) { spin_lock_irq(¤t->sigmask_lock); - current->signal &= ~(1 << signr); + signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->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(¤t->sigmask_lock); - current->signal |= _S(signr); - spin_unlock_irq(¤t->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(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if(sa->sa_handler == SIG_IGN) { + + ka = ¤t->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(¤t->sigmask_lock); - current->signal |= _S(signr & 0x7f); - spin_unlock_irq(¤t->sigmask_lock); - + lock_kernel(); + sigaddset(¤t->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(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->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(¤t->sigmask_lock); + old = current->blocked.sig[0]; + current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + retval = current->blocked.sig[0]; + current->blocked.sig[0] = (newmask & _BLOCKABLE); + spin_unlock_irq(¤t->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(¤t->sig->siglock); - *p = new_sa; - check_pending(signum); - spin_unlock_irq(¤t->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(¤t->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(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->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) |