From 32d4fbac4766ebe2676df0995628b4a4975f5d8d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:12:53 -0500 Subject: [PATCH] Import 2.1.23 --- CREDITS | 9 + Documentation/cdrom/cdrom-standard.tex | 6 +- Makefile | 14 +- Rules.make | 6 + arch/alpha/kernel/alpha_ksyms.c | 12 + arch/alpha/kernel/bios32.c | 6 + arch/alpha/kernel/entry.S | 16 +- arch/alpha/kernel/osf_sys.c | 233 ++-- arch/alpha/kernel/process.c | 19 +- arch/alpha/kernel/ptrace.c | 86 +- arch/alpha/kernel/signal.c | 30 +- arch/alpha/kernel/traps.c | 17 +- arch/alpha/mm/init.c | 5 + arch/i386/Makefile | 1 - arch/i386/kernel/Makefile | 31 +- arch/i386/kernel/entry.S | 172 +-- arch/i386/kernel/hexify.c | 31 - arch/i386/kernel/i386_ksyms.c | 5 +- arch/i386/kernel/ioport.c | 33 +- arch/i386/kernel/irq.c | 10 + arch/i386/kernel/ldt.c | 20 +- arch/i386/kernel/process.c | 56 +- arch/i386/kernel/ptrace.c | 107 +- arch/i386/kernel/signal.c | 31 +- arch/i386/kernel/smp.c | 49 +- arch/i386/kernel/sys_i386.c | 104 +- arch/i386/kernel/trampoline.S | 165 +-- arch/i386/kernel/trampoline32.S | 20 - arch/i386/kernel/traps.c | 51 +- arch/i386/kernel/vm86.c | 78 +- arch/i386/lib/Makefile | 2 +- arch/i386/lib/locks.S | 33 + arch/i386/mm/fault.c | 14 +- arch/i386/mm/init.c | 5 + arch/m68k/kernel/m68k_ksyms.c | 46 +- arch/m68k/kernel/process.c | 29 +- arch/m68k/kernel/ptrace.c | 106 +- arch/m68k/kernel/sys_m68k.c | 223 ++-- arch/m68k/mm/init.c | 5 + arch/mips/kernel/ipc.c | 88 +- arch/mips/kernel/signal.c | 33 +- arch/mips/kernel/syscall.c | 45 +- arch/mips/kernel/sysmips.c | 33 +- arch/mips/mm/init.c | 5 + arch/ppc/kernel/process.c | 56 +- arch/ppc/kernel/ptrace.c | 121 +- arch/ppc/kernel/signal.c | 317 ++--- arch/ppc/kernel/stubs.c | 42 +- arch/ppc/kernel/syscalls.c | 133 ++- arch/ppc/mm/init.c | 5 + arch/sparc/Makefile | 9 +- arch/sparc/ap1000/Makefile | 20 + arch/sparc/ap1000/apinline.h | 86 ++ arch/sparc/ap1000/aplib.c | 496 ++++++++ arch/sparc/ap1000/apmmu.c | 1190 ++++++++++++++++++ arch/sparc/ap1000/approm.c | 148 +++ arch/sparc/ap1000/bnet.c | 1204 +++++++++++++++++++ arch/sparc/ap1000/dma.c | 74 ++ arch/sparc/ap1000/hw.c | 185 +++ arch/sparc/ap1000/irq.c | 64 + arch/sparc/ap1000/kgdb.c | 78 ++ arch/sparc/ap1000/mpp.c | 82 ++ arch/sparc/ap1000/msc.c | 1263 ++++++++++++++++++++ arch/sparc/ap1000/sync.c | 55 + arch/sparc/ap1000/timer.c | 126 ++ arch/sparc/ap1000/tnet.c | 709 +++++++++++ arch/sparc/ap1000/util.c | 436 +++++++ arch/sparc/config.in | 4 +- arch/sparc/defconfig | 4 +- arch/sparc/kernel/Makefile | 13 +- arch/sparc/kernel/entry.S | 120 +- arch/sparc/kernel/finitobj.S | 9 - arch/sparc/kernel/head.S | 23 +- arch/sparc/kernel/initobj.S | 18 - arch/sparc/kernel/irq.c | 21 +- arch/sparc/kernel/process.c | 43 +- arch/sparc/kernel/ptrace.c | 136 ++- arch/sparc/kernel/rirq.S | 289 ----- arch/sparc/kernel/rtrap.S | 32 +- arch/sparc/kernel/setup.c | 11 +- arch/sparc/kernel/signal.c | 243 ++-- arch/sparc/kernel/smp.c | 188 ++- arch/sparc/kernel/solaris.c | 39 +- arch/sparc/kernel/sparc-stub.c | 6 +- arch/sparc/kernel/sparc_ksyms.c | 42 +- arch/sparc/kernel/sun4m_irq.c | 1 - arch/sparc/kernel/sunos_ioctl.c | 118 +- arch/sparc/kernel/sys_solaris.c | 22 +- arch/sparc/kernel/sys_sparc.c | 157 ++- arch/sparc/kernel/sys_sunos.c | 638 +++++----- arch/sparc/kernel/systbls.S | 300 +---- arch/sparc/kernel/time.c | 4 +- arch/sparc/kernel/traps.c | 61 +- arch/sparc/kernel/unaligned.c | 18 +- arch/sparc/kernel/windows.c | 4 + arch/sparc/kernel/wof.S | 4 +- arch/sparc/kernel/wuf.S | 4 +- arch/sparc/lib/Makefile | 28 +- arch/sparc/lib/atomic.S | 84 ++ arch/sparc/lib/bitops.S | 126 ++ arch/sparc/lib/locks.S | 114 ++ arch/sparc/lib/memcpy.S | 1337 +++++++++++++++++---- arch/sparc/lib/memset.S | 37 +- arch/sparc/mm/fault.c | 22 +- arch/sparc/mm/init.c | 24 +- arch/sparc/mm/srmmu.c | 451 ++++--- arch/sparc/vmlinux.lds | 62 + arch/sparc64/Makefile | 9 +- arch/sparc64/defconfig | 2 + arch/sparc64/kernel/finitobj.S | 6 - arch/sparc64/kernel/head.S | 23 +- arch/sparc64/kernel/initobj.S | 15 - arch/sparc64/kernel/signal32.c | 159 +-- arch/sparc64/kernel/ttable.S | 8 +- arch/sparc64/mm/init.c | 24 +- arch/sparc64/prom/k1275d.c | 14 +- arch/sparc64/vmlinux.lds | 68 ++ drivers/ap1000/Makefile | 29 + drivers/ap1000/am79c830.h | 276 +++++ drivers/ap1000/am79c864.h | 162 +++ drivers/ap1000/ap.c | 318 +++++ drivers/ap1000/apfddi-reg.h | 14 + drivers/ap1000/apfddi.c | 702 +++++++++++ drivers/ap1000/apfddi.h | 142 +++ drivers/ap1000/bif.c | 289 +++++ drivers/ap1000/ddv.c | 1008 ++++++++++++++++ drivers/ap1000/ddv_util.c | 116 ++ drivers/ap1000/mac.c | 1177 ++++++++++++++++++ drivers/ap1000/mac.h | 82 ++ drivers/ap1000/plc.c | 393 ++++++ drivers/ap1000/plc.h | 53 + drivers/ap1000/ringbuf.c | 327 +++++ drivers/ap1000/smt-types.h | 167 +++ drivers/block/acsi_slm.c | 2 +- drivers/block/floppy.c | 3 +- drivers/block/hd.c | 2 +- drivers/block/ide-tape.c | 2 +- drivers/block/ide.c | 2 +- drivers/block/loop.c | 2 +- drivers/block/ps2esdi.c | 2 +- drivers/block/rd.c | 4 +- drivers/block/xd.c | 2 +- drivers/block/z2ram.c | 2 +- drivers/cdrom/aztcd.c | 4 +- drivers/cdrom/bpcd.c | 2 +- drivers/cdrom/cdrom.c | 2 +- drivers/cdrom/cdu31a.c | 2 +- drivers/cdrom/gscd.c | 2 +- drivers/cdrom/mcd.c | 2 +- drivers/cdrom/mcdx.c | 6 +- drivers/cdrom/optcd.c | 4 +- drivers/cdrom/sbpcd.c | 2 +- drivers/cdrom/sjcd.c | 2 +- drivers/cdrom/sonycd535.c | 2 +- drivers/char/atarimouse.c | 13 +- drivers/char/atixlmouse.c | 11 +- drivers/char/busmouse.c | 15 +- drivers/char/console.c | 100 +- drivers/char/fbmem.c | 2 +- drivers/char/ftape/kernel-interface.c | 10 +- drivers/char/lp.c | 2 +- drivers/char/lp_m68k.c | 2 +- drivers/char/misc.c | 2 +- drivers/char/msbusmouse.c | 11 +- drivers/char/selection.h | 46 +- drivers/char/tga.c | 5 + drivers/char/tpqic02.c | 8 +- drivers/char/tty_io.c | 21 + drivers/char/vc_screen.c | 4 +- drivers/char/vga.c | 5 + drivers/char/vt.c | 12 +- drivers/net/Makefile | 12 +- drivers/net/README.multicast | 2 +- drivers/net/Space.c | 26 +- drivers/net/ppp.c | 87 +- drivers/net/slip.c | 4 +- drivers/net/strip.c | 2 +- drivers/net/sunhme.h | 2 +- drivers/net/sunlance.c | 178 ++- drivers/sbus/audio/Config.in | 11 + drivers/sbus/audio/Makefile | 36 + drivers/sbus/audio/amd7930.c | 372 ++++++ drivers/sbus/audio/audio.c | 271 +++++ drivers/sbus/audio/audio.h | 75 ++ drivers/sbus/audio/bounce.c | 150 --- drivers/sbus/audio/bounce.h | 23 - drivers/sbus/audio/cs4231.c | 518 ++++++++ drivers/sbus/audio/cs4231.h | 138 +++ drivers/sbus/char/openprom.c | 22 +- drivers/sbus/char/rtc.c | 19 +- drivers/sbus/char/suncons.c | 15 +- drivers/sbus/char/sunfb.c | 4 +- drivers/sbus/char/sunkbd.c | 15 +- drivers/sbus/char/sunmouse.c | 13 +- drivers/scsi/ChangeLog | 125 +- drivers/scsi/a2091.h | 6 +- drivers/scsi/a3000.h | 6 +- drivers/scsi/advansys.h | 6 +- drivers/scsi/aha152x.h | 6 +- drivers/scsi/esp.h | 2 +- drivers/scsi/gvp11.h | 6 +- drivers/scsi/hosts.h | 110 +- drivers/scsi/ibmmca.h | 4 +- drivers/scsi/ide-scsi.c | 4 +- drivers/scsi/ide-scsi.h | 2 +- drivers/scsi/in2000.h | 2 +- drivers/scsi/qlogicisp.h | 2 +- drivers/scsi/qlogicpti.h | 4 +- drivers/scsi/scsi.c | 587 ++++----- drivers/scsi/scsi_module.c | 2 +- drivers/scsi/sd.c | 545 ++++----- drivers/scsi/sg.c | 140 +-- drivers/scsi/sr.c | 280 ++--- drivers/scsi/st.c | 117 +- drivers/sound/dev_table.h | 7 +- drivers/sound/soundcard.c | 8 +- fs/affs/dir.c | 2 +- fs/affs/file.c | 4 +- fs/binfmt_aout.c | 121 +- fs/binfmt_elf.c | 231 ++-- fs/binfmt_java.c | 4 +- fs/binfmt_script.c | 2 +- fs/buffer.c | 71 +- fs/dquot.c | 46 +- fs/exec.c | 13 +- fs/ext2/dir.c | 2 +- fs/ext2/file.c | 2 +- fs/fat/dir.c | 2 +- fs/fat/file.c | 4 +- fs/fcntl.c | 82 +- fs/filesystems.c | 15 +- fs/hpfs/hpfs_fs.c | 4 +- fs/ioctl.c | 34 +- fs/isofs/dir.c | 2 +- fs/isofs/file.c | 2 +- fs/locks.c | 39 +- fs/minix/dir.c | 2 +- fs/minix/file.c | 2 +- fs/namei.c | 35 +- fs/ncpfs/dir.c | 2 +- fs/ncpfs/file.c | 2 +- fs/ncpfs/sock.c | 11 +- fs/nfs/dir.c | 2 +- fs/nfs/file.c | 2 +- fs/nfs/inode.c | 5 +- fs/nfs/nfsroot.c | 8 +- fs/open.c | 288 +++-- fs/proc/Makefile | 10 +- fs/proc/array.c | 8 +- fs/proc/base.c | 2 +- fs/proc/fd.c | 2 +- fs/proc/link.c | 2 +- fs/proc/mem.c | 2 +- fs/proc/net.c | 2 +- fs/proc/openpromfs.c | 26 +- fs/proc/root.c | 12 +- fs/proc/scsi.c | 2 +- fs/read_write.c | 35 +- fs/readdir.c | 44 +- fs/romfs/inode.c | 4 +- fs/select.c | 28 +- fs/smbfs/dir.c | 2 +- fs/smbfs/file.c | 2 +- fs/stat.c | 57 +- fs/super.c | 83 +- fs/sysv/dir.c | 2 +- fs/sysv/file.c | 2 +- fs/ufs/ufs_dir.c | 4 +- fs/ufs/ufs_file.c | 4 +- fs/ufs/ufs_super.c | 2 +- fs/ufs/ufs_symlink.c | 4 +- fs/umsdos/dir.c | 2 +- fs/umsdos/file.c | 4 +- fs/umsdos/rdir.c | 2 +- fs/umsdos/symlink.c | 2 +- include/asm-alpha/cache.h | 12 + include/asm-alpha/ipsum.h | 45 - include/asm-alpha/namei.h | 21 + include/asm-alpha/processor.h | 12 +- include/asm-alpha/smp_lock.h | 15 + include/asm-alpha/uaccess.h | 28 + include/asm-i386/cache.h | 16 + include/asm-i386/irq.h | 173 +-- include/asm-i386/namei.h | 21 + include/asm-i386/processor.h | 12 +- include/asm-i386/smp.h | 50 +- include/asm-i386/smp_lock.h | 97 +- include/asm-i386/system.h | 3 - include/asm-i386/uaccess.h | 28 + include/asm-m68k/cache.h | 12 + include/asm-m68k/processor.h | 12 +- include/asm-mips/cache.h | 12 + include/asm-mips/processor.h | 3 + include/asm-ppc/cache.h | 12 + include/asm-ppc/processor.h | 25 +- include/asm-sparc/ap1000/DdvReqTable.h | 107 ++ include/asm-sparc/ap1000/apbif.h | 205 ++++ include/asm-sparc/ap1000/aplib.h | 119 ++ include/asm-sparc/ap1000/apreg.h | 619 ++++++++++ include/asm-sparc/ap1000/apservice.h | 111 ++ include/asm-sparc/ap1000/pgtapmmu.h | 140 +++ include/asm-sparc/asmmacro.h | 156 +-- include/asm-sparc/atomic.h | 158 +-- include/asm-sparc/bitops.h | 202 +--- include/asm-sparc/ptrace.h | 9 +- include/asm-sparc/semaphore.h | 26 +- include/asm-sparc/sigcontext.h | 11 +- include/asm-sparc/smp.h | 20 +- include/asm-sparc/smp_lock.h | 164 ++- include/asm-sparc/string.h | 13 +- include/asm-sparc/system.h | 48 +- include/asm-sparc/termios.h | 2 +- include/asm-sparc/uaccess.h | 2 +- include/asm-sparc/unistd.h | 16 +- include/asm-sparc64/sigcontext.h | 25 +- include/asm-sparc64/termios.h | 2 +- include/asm-sparc64/uaccess.h | 2 +- include/linux/binfmts.h | 2 +- include/linux/etherdevice.h | 12 +- include/linux/init.h | 55 + include/linux/ioport.h | 5 + include/linux/locks.h | 6 - include/linux/mm.h | 2 + include/linux/module.h | 55 +- include/linux/mpp.h | 18 + include/linux/personality.h | 2 +- include/linux/proc_fs.h | 3 +- include/linux/sched.h | 9 +- include/linux/slab.h | 60 + include/linux/smp_lock.h | 3 - include/linux/tasks.h | 6 + init/main.c | 94 +- ipc/msg.c | 129 +- ipc/sem.c | 187 +-- ipc/shm.c | 176 +-- kernel/exec_domain.c | 33 +- kernel/exit.c | 89 +- kernel/fork.c | 44 +- kernel/info.c | 11 +- kernel/itimer.c | 27 +- kernel/ksyms.c | 11 +- kernel/module.c | 197 +-- kernel/printk.c | 164 +-- kernel/resource.c | 61 + kernel/sched.c | 208 ++-- kernel/signal.c | 83 +- kernel/softirq.c | 10 +- kernel/sys.c | 484 +++++--- kernel/sysctl.c | 13 +- kernel/time.c | 72 +- mm/Makefile | 2 +- mm/filemap.c | 27 +- mm/mlock.c | 53 +- mm/mmap.c | 79 +- mm/mprotect.c | 31 +- mm/mremap.c | 38 +- mm/page_alloc.c | 9 +- mm/slab.c | 1526 ++++++++++++++++++++++++ mm/swapfile.c | 35 +- mm/vmscan.c | 15 +- net/802/Makefile | 2 +- net/appletalk/ddp.c | 2 +- net/ax25/af_ax25.c | 2 +- net/core/scm.c | 1 - net/core/sock.c | 19 +- net/ethernet/eth.c | 8 +- net/ipv4/arp.c | 15 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv6/af_inet6.c | 6 +- net/ipv6/raw.c | 4 +- net/ipv6/tcp_ipv6.c | 4 +- net/ipv6/udp.c | 4 +- net/ipx/af_ipx.c | 2 +- net/netbeui/netbeui.c | 7 +- net/netrom/af_netrom.c | 2 +- net/netsyms.c | 31 +- net/rose/af_rose.c | 2 +- net/socket.c | 446 ++++--- net/x25/af_x25.c | 2 +- scripts/mkdep.c | 10 + 381 files changed, 25641 insertions(+), 6953 deletions(-) delete mode 100644 arch/i386/kernel/hexify.c delete mode 100644 arch/i386/kernel/trampoline32.S create mode 100644 arch/i386/lib/locks.S create mode 100644 arch/sparc/ap1000/Makefile create mode 100644 arch/sparc/ap1000/apinline.h create mode 100644 arch/sparc/ap1000/aplib.c create mode 100644 arch/sparc/ap1000/apmmu.c create mode 100644 arch/sparc/ap1000/approm.c create mode 100644 arch/sparc/ap1000/bnet.c create mode 100644 arch/sparc/ap1000/dma.c create mode 100644 arch/sparc/ap1000/hw.c create mode 100644 arch/sparc/ap1000/irq.c create mode 100644 arch/sparc/ap1000/kgdb.c create mode 100644 arch/sparc/ap1000/mpp.c create mode 100644 arch/sparc/ap1000/msc.c create mode 100644 arch/sparc/ap1000/sync.c create mode 100644 arch/sparc/ap1000/timer.c create mode 100644 arch/sparc/ap1000/tnet.c create mode 100644 arch/sparc/ap1000/util.c delete mode 100644 arch/sparc/kernel/finitobj.S delete mode 100644 arch/sparc/kernel/initobj.S delete mode 100644 arch/sparc/kernel/rirq.S create mode 100644 arch/sparc/lib/atomic.S create mode 100644 arch/sparc/lib/bitops.S create mode 100644 arch/sparc/lib/locks.S create mode 100644 arch/sparc/vmlinux.lds delete mode 100644 arch/sparc64/kernel/finitobj.S delete mode 100644 arch/sparc64/kernel/initobj.S create mode 100644 arch/sparc64/vmlinux.lds create mode 100644 drivers/ap1000/Makefile create mode 100644 drivers/ap1000/am79c830.h create mode 100644 drivers/ap1000/am79c864.h create mode 100644 drivers/ap1000/ap.c create mode 100644 drivers/ap1000/apfddi-reg.h create mode 100644 drivers/ap1000/apfddi.c create mode 100644 drivers/ap1000/apfddi.h create mode 100644 drivers/ap1000/bif.c create mode 100644 drivers/ap1000/ddv.c create mode 100644 drivers/ap1000/ddv_util.c create mode 100644 drivers/ap1000/mac.c create mode 100644 drivers/ap1000/mac.h create mode 100644 drivers/ap1000/plc.c create mode 100644 drivers/ap1000/plc.h create mode 100644 drivers/ap1000/ringbuf.c create mode 100644 drivers/ap1000/smt-types.h create mode 100644 drivers/sbus/audio/Config.in create mode 100644 drivers/sbus/audio/Makefile create mode 100644 drivers/sbus/audio/amd7930.c create mode 100644 drivers/sbus/audio/audio.c create mode 100644 drivers/sbus/audio/audio.h delete mode 100644 drivers/sbus/audio/bounce.c delete mode 100644 drivers/sbus/audio/bounce.h create mode 100644 drivers/sbus/audio/cs4231.c create mode 100644 drivers/sbus/audio/cs4231.h create mode 100644 include/asm-alpha/cache.h delete mode 100644 include/asm-alpha/ipsum.h create mode 100644 include/asm-alpha/namei.h create mode 100644 include/asm-alpha/smp_lock.h create mode 100644 include/asm-i386/cache.h create mode 100644 include/asm-i386/namei.h create mode 100644 include/asm-m68k/cache.h create mode 100644 include/asm-mips/cache.h create mode 100644 include/asm-ppc/cache.h create mode 100644 include/asm-sparc/ap1000/DdvReqTable.h create mode 100644 include/asm-sparc/ap1000/apbif.h create mode 100644 include/asm-sparc/ap1000/aplib.h create mode 100644 include/asm-sparc/ap1000/apreg.h create mode 100644 include/asm-sparc/ap1000/apservice.h create mode 100644 include/asm-sparc/ap1000/pgtapmmu.h create mode 100644 include/linux/init.h create mode 100644 include/linux/mpp.h create mode 100644 include/linux/slab.h create mode 100644 mm/slab.c diff --git a/CREDITS b/CREDITS index 8c4f27213858..e40754171525 100644 --- a/CREDITS +++ b/CREDITS @@ -664,6 +664,15 @@ S: Reading S: RG6 2NU S: United Kingdom +N: Jakub Jelinek +E: jj@sunsite.mff.cuni.cz +W: http://sunsite.mff.cuni.cz/~jj +D: Sparc hacker, SILO, mc +D: Maintain sunsite.mff.cuni.cz +S: Na Orechovce 7 +S: 160 00 Praha 6 +S: Czech Republic + N: Michael K. Johnson E: johnsonm@redhat.com W: http://www.redhat.com/~johnsonm diff --git a/Documentation/cdrom/cdrom-standard.tex b/Documentation/cdrom/cdrom-standard.tex index 0c0aaa2f542b..5c9e91de86f1 100644 --- a/Documentation/cdrom/cdrom-standard.tex +++ b/Documentation/cdrom/cdrom-standard.tex @@ -1,5 +1,5 @@ \documentclass{article} -\def\version{$Id: cdrom-standard.tex,v 1.6 1996/12/23 21:17:44 david Exp $} +\def\version{$Id: cdrom-standard.tex,v 1.6 1996/12/29 20:45:18 davem Exp $} \evensidemargin=0pt \oddsidemargin=0pt @@ -994,6 +994,10 @@ $ \version\ $ \def\versionlog{ $Log: cdrom-standard.tex,v $ +Revision 1.6 1996/12/29 20:45:18 davem +Merge to 2.1.18, versioned module symbols are +disabled until new modutils is released. + Revision 1.6 1996/12/23 21:17:44 david Added reasons for speed selection. diff --git a/Makefile b/Makefile index 9cb80e05ada3..c71332b13b6a 100644 --- a/Makefile +++ b/Makefile @@ -176,12 +176,19 @@ vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs $(ARCHIVES) \ $(FILESYSTEMS) \ $(DRIVERS) \ - $(LIBS) -o vmlinux + $(LIBS) \ + -o vmlinux $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\(\.\.ng$$\)' | sort > System.map symlinks: rm -f include/asm ( cd include ; ln -sf asm-$(ARCH) asm) + @if [ ! -d modules ]; then \ + mkdir modules; \ + fi + @if [ ! -d include/linux/modules ]; then \ + mkdir include/linux/modules; \ + fi oldconfig: symlinks $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in @@ -315,7 +322,7 @@ clean: archclean rm -f core `find . -type f -name 'core' -print` rm -f vmlinux System.map rm -f .tmp* drivers/sound/configure - rm -f modules/* + rm -f `find modules/ -type f -print` rm -f submenu* mrproper: clean @@ -331,7 +338,8 @@ mrproper: clean rm -f .depend `find . -name .depend -print` rm -f .hdepend scripts/mkdep rm -f $(TOPDIR)/include/linux/modversions.h - rm -f $(TOPDIR)/include/linux/modules/* + rm -rf $(TOPDIR)/include/linux/modules + rm -rf modules distclean: mrproper diff --git a/Rules.make b/Rules.make index bcd520ce7eb9..87a0d671dec7 100644 --- a/Rules.make +++ b/Rules.make @@ -107,6 +107,9 @@ modules: $(ALL_MOBJS) dummy ifdef MOD_SUB_DIRS set -e; for i in $(MOD_SUB_DIRS); do $(MAKE) -C $$i modules; done endif +ifdef MOD_IN_SUB_DIRS + set -e; for i in $(MOD_IN_SUB_DIRS); do $(MAKE) -C $$i modules; done +endif ifneq "$(strip $(MOD_LIST_NAME))" "" rm -f $$TOPDIR/modules/$(MOD_LIST_NAME) ifdef MOD_SUB_DIRS @@ -116,6 +119,9 @@ endif ifneq "$(strip $(ALL_MOBJS))" "" echo $(ALL_MOBJS) >> $$TOPDIR/modules/$(MOD_LIST_NAME) endif +ifneq "$(strip $(MOD_TO_LIST))" "" + echo $(MOD_TO_LIST) >> $$TOPDIR/modules/$(MOD_LIST_NAME) +endif endif ifneq "$(strip $(ALL_MOBJS))" "" echo $(PDWN) diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 9a644a22f4a4..446eda06270f 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -10,9 +10,15 @@ #include #include #include +#include +#include +#include + #include #include #include +#include +#include extern void bcopy (const char *src, char *dst, int len); @@ -58,6 +64,7 @@ EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strchr); @@ -72,6 +79,11 @@ EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(hwrpb); EXPORT_SYMBOL(wrusp); EXPORT_SYMBOL(__kernel_thread); +EXPORT_SYMBOL(start_thread); + +EXPORT_SYMBOL(csum_tcpudp_magic); +EXPORT_SYMBOL(ip_fast_csum); +EXPORT_SYMBOL(ip_compute_csum); /* * The following are specially called from the uaccess assembly stubs. diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index 01751697f4ea..a85071b7134f 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -24,6 +24,8 @@ * within the United States, $35 abroad. */ #include +#include +#include #if 0 # define DBG_DEVS(args) printk args @@ -1217,6 +1219,7 @@ asmlinkage int sys_pciconfig_read( unsigned int uint; long err = 0; + lock_kernel(); switch (len) { case 1: err = pcibios_read_config_byte(bus, dfn, off, &ubyte); @@ -1240,6 +1243,7 @@ asmlinkage int sys_pciconfig_read( err = -EINVAL; break; } + unlock_kernel(); return err; } asmlinkage int sys_pciconfig_write( @@ -1254,6 +1258,7 @@ asmlinkage int sys_pciconfig_write( unsigned int uint; long err = 0; + lock_kernel(); switch (len) { case 1: err = get_user(ubyte, buf); @@ -1286,6 +1291,7 @@ asmlinkage int sys_pciconfig_write( err = -EINVAL; break; } + unlock_kernel(); return err; } diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index c08bab0008af..284cd22a55b2 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -199,6 +199,8 @@ entIF: .align 3 .ent kernel_clone kernel_clone: + .frame $30, 0, $26 + .prologue 0 subq $30,6*8,$30 stq $31,0($30) stq $26,8($30) @@ -221,17 +223,19 @@ kernel_clone: .globl __kernel_thread .ent __kernel_thread __kernel_thread: + .frame $30, 4*8, $26 subq $30,4*8,$30 - stq $9,0($30) - stq $10,8($30) - stq $26,16($30) + stq $10,16($30) + stq $9,8($30) + stq $26,0($30) + .prologue 0 bis $17,$17,$9 /* save fn */ bis $18,$18,$10 /* save arg */ bsr $26,kernel_clone bne $20,1f /* $20 is non-zero in child */ - ldq $9,0($30) - ldq $10,8($30) - ldq $26,16($30) + ldq $26,0($30) + ldq $9,8($30) + ldq $10,16($30) addq $30,4*8,$30 ret $31,($26),1 /* this is in child: look out as we don't have any stack here.. */ diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 5dc11cb035cd..7c6bc1b5c72b 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -52,12 +54,15 @@ asmlinkage int osf_set_program_attributes( unsigned long text_start, unsigned long text_len, unsigned long bss_start, unsigned long bss_len) { - struct mm_struct *mm = current->mm; + struct mm_struct *mm; + lock_kernel(); + mm = current->mm; mm->end_code = bss_start + bss_len; mm->brk = bss_start + bss_len; printk("set_program_attributes(%lx %lx %lx %lx)\n", text_start, text_len, bss_start, bss_len); + unlock_kernel(); return 0; } @@ -151,12 +156,17 @@ asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4, extern int sys_getpriority(int, int); int prio; + /* + * We don't need to aquire the kernel lock here, because + * all of these operations are local. sys_getpriority + * will get the lock as required.. + */ prio = sys_getpriority(which, who); - if (prio < 0) - return prio; - - regs.r0 = 0; /* special return: no errors */ - return 20 - prio; + if (prio >= 0) { + regs.r0 = 0; /* special return: no errors */ + prio = 20 - prio; + } + return prio; } @@ -168,25 +178,39 @@ asmlinkage unsigned long sys_madvise(void) return 0; } +/* + * No need to aquire the kernel lock, we're local.. + */ asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs) { - (®s)->r20 = current->euid; - return current->uid; + struct task_struct * tsk = current; + (®s)->r20 = tsk->euid; + return tsk->uid; } asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs) { - (®s)->r20 = current->egid; - return current->gid; + struct task_struct * tsk = current; + (®s)->r20 = tsk->egid; + return tsk->gid; } asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs) { - (®s)->r20 = current->p_opptr->pid; - return current->pid; + struct task_struct *tsk = current; + + /* + * This isn't strictly "local" any more and we should actually + * aquire the kernel lock. The "p_opptr" pointer might change + * if the parent goes away (or due to ptrace). But any race + * isn't actually going to matter, as if the parent happens + * to change we can happily return either of the pids. + */ + (®s)->r20 = tsk->p_opptr->pid; + return tsk->pid; } asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, @@ -194,15 +218,20 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, unsigned long off) { struct file *file = NULL; + unsigned long ret = -EBADF; + lock_kernel(); if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags); if (!(flags & MAP_ANONYMOUS)) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - return do_mmap(file, addr, len, prot, flags, off); + ret = do_mmap(file, addr, len, prot, flags, off); +out: + unlock_kernel(); + return ret; } @@ -245,22 +274,27 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b struct inode *inode; int retval; + lock_kernel(); if (bufsiz > sizeof(struct osf_statfs)) bufsiz = sizeof(struct osf_statfs); retval = verify_area(VERIFY_WRITE, buffer, bufsiz); if (retval) - return retval; + goto out; retval = namei(path, &inode); if (retval) - return retval; + goto out; + retval = -ENOSYS; if (!inode->i_sb->s_op->statfs) { iput(inode); - return -ENOSYS; + goto out; } inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); linux_to_osf_statfs(&linux_stat, buffer); iput(inode); - return 0; + retval = 0; +out: + unlock_kernel(); + return retval; } asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz) @@ -270,20 +304,27 @@ asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned struct inode *inode; int retval; + lock_kernel(); retval = verify_area(VERIFY_WRITE, buffer, bufsiz); if (retval) - return retval; + goto out; if (bufsiz > sizeof(struct osf_statfs)) bufsiz = sizeof(struct osf_statfs); + retval = -EBADF; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + retval = -ENOENT; if (!(inode = file->f_inode)) - return -ENOENT; + goto out; + retval = -ENOSYS; if (!inode->i_sb->s_op->statfs) - return -ENOSYS; + goto out; inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); linux_to_osf_statfs(&linux_stat, buffer); - return 0; + retval = 0; +out: + unlock_kernel(); + return retval; } /* @@ -431,9 +472,9 @@ static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags) asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data) { - int retval; + int retval = -EINVAL; - retval = -EINVAL; + lock_kernel(); switch (typenr) { case 1: retval = osf_ufs_mount(path, (struct ufs_args *) data, flag); @@ -447,12 +488,18 @@ asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data) default: printk("osf_mount(%ld, %x)\n", typenr, flag); } + unlock_kernel(); return retval; } asmlinkage int osf_umount(char *path, int flag) { - return sys_umount(path); + int ret; + + lock_kernel(); + ret = sys_umount(path); + unlock_kernel(); + return ret; } /* @@ -466,11 +513,12 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain) unsigned long ticks; int retval; + lock_kernel(); retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep)); if (retval) - return retval; + goto out; if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain)))) - return retval; + goto out; copy_from_user(&tmp, sleep, sizeof(*sleep)); ticks = tmp.tv_usec; ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ); @@ -478,8 +526,9 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain) current->timeout = ticks + jiffies; current->state = TASK_INTERRUPTIBLE; schedule(); + retval = 0; if (!remain) - return 0; + goto out; ticks = jiffies; if (ticks < current->timeout) ticks = current->timeout - ticks; @@ -489,26 +538,38 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain) tmp.tv_sec = ticks / HZ; tmp.tv_usec = ticks % HZ; copy_to_user(remain, &tmp, sizeof(*remain)); - return 0; +out: + unlock_kernel(); + return retval; } asmlinkage int osf_utsname(char *name) { - int error = verify_area(VERIFY_WRITE, name, 5 * 32); + int error; + + lock_kernel(); + error = verify_area(VERIFY_WRITE, name, 5 * 32); if (error) - return error; + goto out; copy_to_user(name + 0, system_utsname.sysname, 32); copy_to_user(name + 32, system_utsname.nodename, 32); copy_to_user(name + 64, system_utsname.release, 32); copy_to_user(name + 96, system_utsname.version, 32); copy_to_user(name + 128, system_utsname.machine, 32); - return 0; +out: + unlock_kernel(); + return error; } asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat) { + int ret; + /* for now, simply ignore lowat and hiwat... */ - return sys_swapon(path, flags); + lock_kernel(); + ret = sys_swapon(path, flags); + unlock_kernel(); + return ret; } asmlinkage unsigned long sys_getpagesize(void) @@ -527,11 +588,15 @@ asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5, int fd[2]; int error; + lock_kernel(); error = do_pipe(fd); if (error) - return error; + goto out; (®s)->r20 = fd[1]; - return fd[0]; + error = fd[0]; +out: + unlock_kernel(); + return error; } /* @@ -542,9 +607,10 @@ asmlinkage int osf_getdomainname(char *name, int namelen) unsigned len; int i, error; + lock_kernel(); error = verify_area(VERIFY_WRITE, name, namelen); if (error) - return error; + goto out; len = namelen; if (namelen > 32) @@ -555,23 +621,29 @@ asmlinkage int osf_getdomainname(char *name, int namelen) if (system_utsname.domainname[i] == '\0') break; } - return 0; +out: + unlock_kernel(); + return error; } asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg) { unsigned long raddr; - int err; + long err; + lock_kernel(); err = sys_shmat(shmid, shmaddr, shmflg, &raddr); if (err) - return err; + goto out; /* * This works because all user-level addresses are * non-negative longs! */ - return raddr; + err = raddr; +out: + unlock_kernel(); + return err; } @@ -645,46 +717,44 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args) long error; int *min_buf_size_ptr; + lock_kernel(); switch (code) { case PL_SET: error = verify_area(VERIFY_READ, &args->set.nbytes, sizeof(args->set.nbytes)); - if (error) - return error; - return args->set.nbytes; - + if (!error) + error = args->set.nbytes; + break; case PL_FSET: error = verify_area(VERIFY_READ, &args->fset.nbytes, sizeof(args->fset.nbytes)); - if (error) - return error; - return args->fset.nbytes; - + if (!error) + error = args->fset.nbytes; + break; case PL_GET: get_user(min_buf_size_ptr, &args->get.min_buf_size); error = verify_area(VERIFY_WRITE, min_buf_size_ptr, sizeof(*min_buf_size_ptr)); - if (error) - return error; - put_user(0, min_buf_size_ptr); - return 0; - + if (!error) + put_user(0, min_buf_size_ptr); + break; case PL_FGET: get_user(min_buf_size_ptr, &args->fget.min_buf_size); error = verify_area(VERIFY_WRITE, min_buf_size_ptr, sizeof(*min_buf_size_ptr)); - if (error) - return error; - put_user(0, min_buf_size_ptr); - return 0; - + if (!error) + put_user(0, min_buf_size_ptr); + break; case PL_DEL: case PL_FDEL: - return 0; - + error = 0; + break; default: - return -EOPNOTSUPP; - } + error = -EOPNOTSUPP; + break; + }; + unlock_kernel(); + return error; } /* @@ -701,6 +771,7 @@ asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long si asmlinkage unsigned long sys_create_module(char *, unsigned long); long retval; + lock_kernel(); retval = sys_create_module(module_name, size); /* * we get either a module address or an error number, @@ -709,10 +780,12 @@ asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long si * much larger. */ if (retval + 1000 > 0) - return retval; + goto out; /* tell entry.S:syscall_error that this is NOT an error: */ regs.r0 = 0; +out: + unlock_kernel(); return retval; } @@ -731,21 +804,26 @@ asmlinkage long osf_sysinfo(int command, char *buf, long count) }; unsigned long offset; char *res; - long len; + long len, err = -EINVAL; + lock_kernel(); offset = command-1; if (offset >= sizeof(sysinfo_table)/sizeof(char *)) { /* Digital unix has a few unpublished interfaces here */ printk("sysinfo(%d)", command); - return -EINVAL; + goto out; } res = sysinfo_table[offset]; len = strlen(res)+1; if (len > count) len = count; if (copy_to_user(buf, res, len)) - return -EFAULT; - return 0; + err = -EFAULT; + else + err = 0; +out: + unlock_kernel(); + return err; } asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned long nbytes, @@ -753,15 +831,17 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned { extern unsigned long rdfpcr(void); unsigned long fpcw; + unsigned long ret = -EOPNOTSUPP; + lock_kernel(); switch (op) { case 45: /* GSI_IEEE_FP_CONTROL */ /* build and return current fp control word: */ fpcw = current->tss.flags & IEEE_TRAP_ENABLE_MASK; fpcw |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK; put_user(fpcw, (unsigned long *) buffer); - return 0; - + ret = 0; + break; case 46: /* GSI_IEEE_STATE_AT_SIGNAL */ /* * Not sure anybody will ever use this weird stuff. These @@ -769,11 +849,11 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned * be used when a signal handler starts executing. */ break; - default: break; } - return -EOPNOTSUPP; + unlock_kernel(); + return ret; } @@ -781,15 +861,17 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, unsigned int *start, void *arg) { unsigned long fpcw; + unsigned long ret = -EOPNOTSUPP; + lock_kernel(); switch (op) { case 14: /* SSI_IEEE_FP_CONTROL */ /* update trap enable bits: */ get_user(fpcw, (unsigned long *) buffer); current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK; current->tss.flags |= (fpcw & IEEE_TRAP_ENABLE_MASK); - return 0; - + ret = 0; + break; case 15: /* SSI_IEEE_STATE_AT_SIGNAL */ case 16: /* SSI_IEEE_IGNORE_STATE_AT_SIGNAL */ /* @@ -800,5 +882,6 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, unsigned default: break; } - return -EOPNOTSUPP; + unlock_kernel(); + return ret; } diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 73b239ea492c..370f25aca67d 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,9 @@ #include #include +/* + * No need to aquire the kernel lock, we're entirely local.. + */ asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) @@ -41,14 +46,21 @@ asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; for (;;) { schedule(); } + ret = 0; +out: + unlock_kernel(); + return ret; } void hard_reset_now(void) @@ -246,10 +258,13 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, int error; char * filename; + lock_kernel(); error = getname((char *) a0, &filename); if (error) - return error; + goto out; error = do_execve(filename, (char **) a1, (char **) a2, ®s); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index d03744a68562..019fb6b952c3 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -487,27 +489,30 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs) { struct task_struct *child; - struct user * dummy; - - dummy = NULL; + long ret; + lock_kernel(); DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", request, pid, addr, data)); + ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; if (request == PTRACE_ATTACH) { + ret = -EPERM; if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || @@ -515,10 +520,10 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, (current->gid != child->egid) || (current->gid != child->sgid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -526,20 +531,22 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) { DBG(DBG_MEM, ("child not traced\n")); - return -ESRCH; + goto out; } if (child->state != TASK_STOPPED) { DBG(DBG_MEM, ("child process not stopped\n")); if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) { DBG(DBG_MEM, ("child not parent of this process\n")); - return -ESRCH; + goto out; } switch (request) { @@ -547,37 +554,41 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); + ret = read_long(child, addr, &tmp); DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); - if (res < 0) - return res; + if (ret < 0) + goto out; regs.r0 = 0; /* special return: no errors */ - return tmp; + ret = tmp; + goto out; } /* read register number ADDR. */ case PTRACE_PEEKUSR: regs.r0 = 0; /* special return: no errors */ DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0)); - return get_reg(child, addr); + ret = get_reg(child, addr); + goto out; /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data)); - return write_long(child, addr, data); + ret = write_long(child, addr, data); + goto out; case PTRACE_POKEUSR: /* write the specified register */ DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data)); - return put_reg(child, addr, data); + ret = put_reg(child, addr, data); + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -586,7 +597,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, wake_up_process(child); /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); - return data; + ret = data; + goto out; } /* @@ -601,23 +613,27 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, } /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); - return 0; + ret = 0; + goto out; } case PTRACE_SINGLESTEP: { /* execute single instruction. */ + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; child->debugreg[4] = -1; /* mark single-stepping */ child->flags &= ~PF_TRACESYS; wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -626,19 +642,25 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, SET_LINKS(child); /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt(child); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -651,4 +673,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; +out: + unlock_kernel(); } diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 9e6ca449d52e..68236dc8ff9e 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +40,9 @@ extern int ptrace_cancel_bpt (struct task_struct *child); * * We change the range to -1 .. 1 in order to let gcc easily * use the conditional move instructions. + * + * Note that we don't need to aquire the kernel lock for SMP + * operation, as all of this is local to this thread. */ asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask, long a2, long a3, long a4, long a5, struct pt_regs regs) @@ -73,14 +78,20 @@ asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask, */ asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw) { - unsigned long oldmask = current->blocked; + unsigned long oldmask; + + lock_kernel(); + oldmask = current->blocked; current->blocked = mask & _BLOCKABLE; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(oldmask,regs, sw, 0, 0)) - return -EINTR; + goto out; } +out: + unlock_kernel(); + return -EINTR; } /* @@ -93,6 +104,7 @@ asmlinkage void do_sigreturn(struct sigcontext * sc, int i; /* verify that it's a good sigcontext before using it */ + lock_kernel(); if (verify_area(VERIFY_READ, sc, sizeof(*sc))) do_exit(SIGSEGV); get_user(ps, &sc->sc_ps); @@ -145,6 +157,7 @@ asmlinkage void do_sigreturn(struct sigcontext * sc, /* send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) send_sig(SIGTRAP, current, 1); + unlock_kernel(); } /* @@ -279,10 +292,13 @@ asmlinkage int do_signal(unsigned long oldmask, struct switch_stack * sw, unsigned long r0, unsigned long r19) { - unsigned long mask = ~current->blocked; + unsigned long mask; unsigned long signr, single_stepping; struct sigaction * sa; + int ret; + lock_kernel(); + mask = ~current->blocked; single_stepping = ptrace_cancel_bpt(current); while ((signr = current->signal & mask) != 0) { @@ -356,7 +372,8 @@ asmlinkage int do_signal(unsigned long oldmask, if (single_stepping) { ptrace_set_bpt(current); /* re-set breakpoint */ } - return 1; + ret = 1; + goto out; } if (r0 && (regs->r0 == ERESTARTNOHAND || @@ -369,5 +386,8 @@ asmlinkage int do_signal(unsigned long oldmask, if (single_stepping) { ptrace_set_bpt(current); /* re-set breakpoint */ } - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index cdda7b2ba872..7fd0f6417208 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -21,15 +21,16 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err, unsigned long *r9_15) { long i; - unsigned long sp; + unsigned long sp, ra; unsigned int * pc; if (regs->ps & 8) return; printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); sp = (unsigned long) (regs+1); + __get_user(ra, (unsigned long *)sp); printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps); - printk("rp = [<%016lx>] sp = %016lx\n", regs->r26, sp); + printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra); printk("r0 = %016lx r1 = %016lx\n", regs->r0, regs->r1); printk("r2 = %016lx r3 = %016lx\n", regs->r2, regs->r3); printk("r4 = %016lx r5 = %016lx\n", regs->r4, regs->r5); @@ -49,13 +50,17 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err, printk("r20= %016lx r21= %016lx\n", regs->r20, regs->r21); printk("r22= %016lx r23= %016lx\n", regs->r22, regs->r23); printk("r24= %016lx r25= %016lx\n", regs->r24, regs->r25); - printk("r26= %016lx r27= %016lx\n", regs->r26, regs->r27); - printk("r28= %016lx r29= %016lx\n", regs->r28, regs->gp); + printk("r27= %016lx r28= %016lx\n", regs->r27, regs->r28); + printk("gp = %016lx sp = %016lx\n", regs->gp, sp); printk("Code:"); pc = (unsigned int *) regs->pc; - for (i = -3; i < 6; i++) - printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>'); + for (i = -3; i < 6; i++) { + unsigned int insn; + if (__get_user(insn, pc+i)) + break; + printk("%c%08x%c",i?' ':'<',insn,i?' ':'>'); + } printk("\n"); do_exit(SIGSEGV); } diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 6ce0af805c0c..94237dbf4cf0 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -171,6 +171,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) return; } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { int i; diff --git a/arch/i386/Makefile b/arch/i386/Makefile index b01e565a6cee..3bfbd89b044d 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -111,7 +111,6 @@ install: vmlinux archclean: @$(MAKEBOOT) clean - $(MAKE) -C arch/$(ARCH)/kernel clean archdep: @$(MAKEBOOT) dep diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 430e0b07eefb..e04fb5efb776 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,9 +7,6 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -#.S.s: -# $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s - ifdef SMP .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o @@ -31,7 +28,7 @@ endif ifdef SMP -O_OBJS += smp.o +O_OBJS += smp.o trampoline.o head.o: head.S $(TOPDIR)/include/linux/tasks.h $(CC) -D__ASSEMBLY__ -D__SMP__ -traditional -c $*.S -o $*.o @@ -43,30 +40,4 @@ head.o: head.S $(TOPDIR)/include/linux/tasks.h endif -hexify: - $(HOSTCC) hexify.c -o hexify - -smp.c: trampoline.hex - -trampoline.hex: trampoline hexify - (dd if=trampoline bs=1 skip=32 | ./hexify >trampoline.hex ) - -trampoline: trampoline.o trampoline32.o - $(LD86) -s -o $@ trampoline.o trampoline32.o - -trampoline.o: trampoline.s - $(AS86) -o $@ $< - -trampoline32.o: trampoline32.s - $(AS386) -o $@ $< - -trampoline.s: trampoline.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile - $(CPP) -D__SMP__ -traditional $< -o $@ - -trampoline32.s: trampoline32.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile - $(CPP) -D__SMP__ -traditional $< -o $@ - -clean: - rm -f trampoline hexify trampoline.hex - include $(TOPDIR)/Rules.make diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 9e7294272c78..c76b0866da67 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -97,98 +97,7 @@ ENOSYS = 38 mov %dx,%ds; \ mov %dx,%es; -#ifdef __SMP__ - -#define GET_PROCESSOR_ID \ - movl SYMBOL_NAME(apic_reg), %edx; \ - movl 32(%edx), %eax;\ - movl %eax,SYMBOL_NAME(apic_retval); \ - shrl $24,%eax; \ - andb $0x0F,%al; - -/* - * Get the processor ID multiplied by 4 - */ - -#define GET_PROCESSOR_OFFSET(x) \ - movl SYMBOL_NAME(apic_reg), x ; \ - movl 32( x ), x ; \ - shrl $22, x ; \ - andl $0x3C, x ; - -/* macro LEAVE_KERNEL decrements kernel_counter and resets kernel_flag and - saves processor variables if zero */ -#define LEAVE_KERNEL \ - pushfl; \ - cli; \ - GET_PROCESSOR_ID \ - btrl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \ - decl SYMBOL_NAME(syscall_count); \ - decl SYMBOL_NAME(kernel_counter); \ - jnz 1f; \ - movb $(NO_PROC_ID), SYMBOL_NAME(active_kernel_processor); \ - lock; \ - btrl $0, SYMBOL_NAME(kernel_flag); \ -1: popfl; - -/* macro ENTER_KERNEL waits for entering the kernel, increments - kernel_counter, and reloads the processor variables if necessary - uses : %eax, %edx (pushed and popped) - - Note: We go to great pains to minimise the number of locked operations. - We want to spin without locking, and lock when we attempt an update. - The pentium has a MESI cache so the spin without lock will exit when - another CPU write invalidates our cache, and the lock is avoided when - possible so we don't play ping-pong games with the cache line. - -*/ - -#ifndef __SMP_PROF__ - -#define SMP_PROF_A -#define SMP_PROF_B - -#else - -#define SMP_PROF_A movl $0,SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4); -#define SMP_PROF_B incl SYMBOL_NAME(smp_spins_syscall)(,%eax,4); \ - incl SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4); -#endif - -#define ENTER_KERNEL \ - pushl %eax; \ - pushl %edx; \ - pushfl; \ - cli; \ - GET_PROCESSOR_ID \ - btsl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \ - SMP_PROF_A \ -1: lock; \ - btsl $0, SYMBOL_NAME(kernel_flag); \ - jnc 3f; \ - cmpb SYMBOL_NAME(active_kernel_processor), %al; \ - je 4f; \ -2: SMP_PROF_B \ - btl %al, SYMBOL_NAME(smp_invalidate_needed); \ - jnc 5f; \ - lock; \ - btrl %al, SYMBOL_NAME(smp_invalidate_needed); \ - jnc 5f; \ - movl %cr3,%edx; \ - movl %edx,%cr3; \ -5: btl $0, SYMBOL_NAME(kernel_flag); \ - jc 2b; \ - jmp 1b; \ -3: movb %al, SYMBOL_NAME(active_kernel_processor); \ -4: incl SYMBOL_NAME(kernel_counter); \ - incl SYMBOL_NAME(syscall_count); \ - popfl; \ - popl %edx; \ - popl %eax; - - #define RESTORE_ALL \ - LEAVE_KERNEL \ popl %ebx; \ popl %ecx; \ popl %edx; \ @@ -201,38 +110,30 @@ ENOSYS = 38 addl $4,%esp; \ iret -#define GET_CURRENT \ - GET_PROCESSOR_OFFSET(%ebx) \ - movl SYMBOL_NAME(current_set)(%ebx),%ebx +#ifdef __SMP__ +/* Get the processor ID multiplied by 4 */ +#define GET_PROCESSOR_OFFSET(reg) \ + movl SYMBOL_NAME(apic_reg), reg; \ + movl 32(reg), reg; \ + shrl $22, reg; \ + andl $0x3C, reg; + +#define GET_CURRENT(reg) \ + GET_PROCESSOR_OFFSET(reg) \ + movl SYMBOL_NAME(current_set)(reg),reg #else -#define GET_CURRENT \ - movl SYMBOL_NAME(current_set),%ebx +#define GET_CURRENT(reg) \ + movl SYMBOL_NAME(current_set),reg -#define RESTORE_ALL \ - popl %ebx; \ - popl %ecx; \ - popl %edx; \ - popl %esi; \ - popl %edi; \ - popl %ebp; \ - popl %eax; \ - pop %ds; \ - pop %es; \ - addl $4,%esp; \ - iret #endif - ENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL - GET_CURRENT -#ifdef __SMP__ - ENTER_KERNEL -#endif + GET_CURRENT(%ebx) movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. @@ -240,12 +141,7 @@ ENTRY(lcall7) movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%eax -#ifdef __SMP__ - GET_PROCESSOR_OFFSET(%edx) # Processor offset into edx - movl SYMBOL_NAME(current_set)(,%edx),%edx -#else - movl SYMBOL_NAME(current_set),%edx -#endif + GET_CURRENT(%edx) pushl %eax movl exec_domain(%edx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain @@ -253,12 +149,23 @@ ENTRY(lcall7) popl %eax jmp ret_from_sys_call +#ifdef __SMP__ + ALIGN + .globl ret_from_smpfork +ret_from_smpfork: + GET_CURRENT(%ebx) + movl $NO_PROC_ID, SYMBOL_NAME(active_kernel_processor) + lock + btrl $0, SYMBOL_NAME(kernel_flag) + sti + jmp 9f +#endif /* __SMP__ */ + ALIGN handle_bottom_half: - incl SYMBOL_NAME(intr_count) - call SYMBOL_NAME(do_bottom_half) - decl SYMBOL_NAME(intr_count) - jmp 9f + pushl $9f + jmp SYMBOL_NAME(do_bottom_half) + ALIGN reschedule: pushl $ret_from_sys_call @@ -267,10 +174,7 @@ reschedule: ENTRY(system_call) pushl %eax # save orig_eax SAVE_ALL - GET_CURRENT -#ifdef __SMP__ - ENTER_KERNEL -#endif + GET_CURRENT(%ebx) cmpl $(NR_syscalls),%eax jae badsys testb $0x20,flags(%ebx) # PF_TRACESYS @@ -280,9 +184,7 @@ ENTRY(system_call) ALIGN .globl ret_from_sys_call ret_from_sys_call: -#ifdef __SMP__ - GET_CURRENT -#endif + GET_CURRENT(%ebx) cmpl $0,SYMBOL_NAME(intr_count) jne 1f 9: movl SYMBOL_NAME(bh_mask),%eax @@ -358,10 +260,7 @@ error_code: movl $(KERNEL_DS),%edx mov %dx,%ds mov %dx,%es - GET_CURRENT -#ifdef __SMP__ - ENTER_KERNEL -#endif + GET_CURRENT(%ebx) call *%ecx addl $8,%esp jmp ret_from_sys_call @@ -374,10 +273,7 @@ ENTRY(coprocessor_error) ENTRY(device_not_available) pushl $-1 # mark this as an int SAVE_ALL - GET_CURRENT -#ifdef __SMP__ - ENTER_KERNEL -#endif + GET_CURRENT(%ebx) pushl $ret_from_sys_call movl %cr0,%eax testl $0x4,%eax # EM (math emulation bit) diff --git a/arch/i386/kernel/hexify.c b/arch/i386/kernel/hexify.c deleted file mode 100644 index daa331fec26b..000000000000 --- a/arch/i386/kernel/hexify.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - - -void main() -{ - int c; - int comma=0; - int count=0; - while((c=getchar())!=EOF) - { - unsigned char x=c; - if(comma) - printf(","); - else - comma=1; - if(count==8) - { - count=0; - printf("\n"); - } - if(count==0) - printf("\t"); - printf("0x%02X",c); - count++; - } - if(count) - printf("\n"); - exit(0); -} - - diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index bcb86de8ea44..0b4f04c76078 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -12,6 +13,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +extern void __lock_kernel(void); /* platform dependent support */ EXPORT_SYMBOL(EISA_bus); @@ -28,11 +30,10 @@ EXPORT_SYMBOL_NOVERS(__up_wakeup); #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(syscall_count); EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(kernel_counter); EXPORT_SYMBOL(active_kernel_processor); EXPORT_SYMBOL(smp_invalidate_needed); +EXPORT_SYMBOL_NOVERS(__lock_kernel); #endif #ifdef CONFIG_MCA diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index bcefeef9b8ac..43ad07572a70 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) @@ -50,15 +53,19 @@ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_ */ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { - if (from + num <= from) - return -EINVAL; - if (from + num > IO_BITMAP_SIZE*32) - return -EINVAL; - if (!suser()) - return -EPERM; + int ret = -EINVAL; + lock_kernel(); + if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) + goto out; + ret = -EPERM; + if (!suser()) + goto out; set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } unsigned int *stack; @@ -79,11 +86,17 @@ asmlinkage int sys_iopl(long ebx,long ecx,long edx, long eflags, long esp, long ss) { unsigned int level = ebx; + int ret = -EINVAL; + lock_kernel(); if (level > 3) - return -EINVAL; + goto out; + ret = -EPERM; if (!suser()) - return -EPERM; + goto out; *(&eflags) = (eflags & 0xffffcfff) | (level << 12); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 541af11289b9..962021b1d3f0 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -346,6 +348,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) struct irqaction * action = *(irq + irq_action); int do_random = 0; + lock_kernel(); + intr_count++; #ifdef __SMP__ if(smp_threads_ready && active_kernel_processor!=smp_processor_id()) panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id()); @@ -362,6 +366,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) } if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); + intr_count--; + unlock_kernel(); } /* @@ -374,6 +380,8 @@ asmlinkage void do_fast_IRQ(int irq) struct irqaction * action = *(irq + irq_action); int do_random = 0; + lock_kernel(); + intr_count++; #ifdef __SMP__ /* IRQ 13 is allowed - that's a flush tlb */ if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13) @@ -391,6 +399,8 @@ asmlinkage void do_fast_IRQ(int irq) } if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); + intr_count--; + unlock_kernel(); } int setup_x86_irq(int irq, struct irqaction * new) diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 5d46baae5d10..09a8c4a67088 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -117,11 +119,17 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) { + int ret; + + lock_kernel(); if (func == 0) - return read_ldt(ptr, bytecount); - if (func == 1) - return write_ldt(ptr, bytecount, 1); - if (func == 0x11) - return write_ldt(ptr, bytecount, 0); - return -ENOSYS; + ret = read_ldt(ptr, bytecount); + else if (func == 1) + ret = write_ldt(ptr, bytecount, 1); + else if (func == 0x11) + ret = write_ldt(ptr, bytecount, 0); + else + ret = -ENOSYS; + unlock_kernel(); + return ret; } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 8d6ded0d4335..92a2fff9b6d7 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,7 +36,11 @@ #include #include +#ifdef __SMP__ +asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork"); +#else asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); +#endif #ifdef CONFIG_APM extern int apm_do_idle(void); @@ -91,9 +97,11 @@ static void hard_idle(void) asmlinkage int sys_idle(void) { unsigned long start_idle = 0; + int ret = -EPERM; + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; for (;;) @@ -118,6 +126,10 @@ asmlinkage int sys_idle(void) start_idle = 0; schedule(); } + ret = 0; +out: + unlock_kernel(); + return ret; } #else @@ -129,15 +141,21 @@ asmlinkage int sys_idle(void) asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if(current->pid != 0) - return -EPERM; + goto out; #ifdef __SMP_PROF__ smp_spins_sys_idle[smp_processor_id()]+= smp_spins_syscall_cur[smp_processor_id()]; #endif current->counter= -100; schedule(); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } /* @@ -150,9 +168,10 @@ int cpu_idle(void *unused) { if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched) __asm("hlt"); - if(0==(0x7fffffff & smp_process_available)) + if(0==(read_smp_counter(&smp_process_available))) continue; - while(0x80000000 & smp_process_available); + while(0x80000000 & smp_process_available) + ; cli(); while(set_bit(31,&smp_process_available)) while(test_bit(31,&smp_process_available)) @@ -163,7 +182,7 @@ int cpu_idle(void *unused) if(clear_bit(smp_processor_id(), &smp_invalidate_needed)) local_flush_tlb(); } - if (0==(0x7fffffff & smp_process_available)){ + if (0==(read_smp_counter(&smp_process_available))) { clear_bit(31,&smp_process_available); sti(); continue; @@ -473,13 +492,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, p->tss.tr = _TSS(nr); childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; p->tss.esp = (unsigned long) childregs; +#ifdef __SMP__ + p->tss.eip = (unsigned long) ret_from_smpfork; + p->tss.eflags = regs->eflags & 0xffffcdff; /* iopl always 0 for a new process */ +#else p->tss.eip = (unsigned long) ret_from_sys_call; + p->tss.eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */ +#endif p->tss.ebx = (unsigned long) p; *childregs = *regs; childregs->eax = 0; childregs->esp = esp; p->tss.back_link = 0; - p->tss.eflags = regs->eflags & 0xffffcfff; /* iopl is always 0 for a new process */ p->tss.ldt = _LDT(nr); if (p->ldt) { p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); @@ -568,19 +592,28 @@ void dump_thread(struct pt_regs * regs, struct user * dump) asmlinkage int sys_fork(struct pt_regs regs) { - return do_fork(SIGCHLD, regs.esp, ®s); + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, regs.esp, ®s); + unlock_kernel(); + return ret; } asmlinkage int sys_clone(struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; + int ret; + lock_kernel(); clone_flags = regs.ebx; newsp = regs.ecx; if (!newsp) newsp = regs.esp; - return do_fork(clone_flags, newsp, ®s); + ret = do_fork(clone_flags, newsp, ®s); + unlock_kernel(); + return ret; } /* @@ -591,10 +624,13 @@ asmlinkage int sys_execve(struct pt_regs regs) int error; char * filename; + lock_kernel(); error = getname((char *) regs.ebx, &filename); if (error) - return error; + goto out; error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index e6f44243e7fe..fdb4088ffa41 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -362,26 +364,29 @@ static unsigned long getreg(struct task_struct *child, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - struct user * dummy; - int i; - - dummy = NULL; + struct user * dummy = NULL; + int i, ret; + lock_kernel(); + ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; + ret = -EPERM; if (request == PTRACE_ATTACH) { if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || @@ -389,10 +394,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->gid != child->egid) || (current->gid != child->sgid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -400,37 +405,39 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - return -ESRCH; + goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) - return -ESRCH; + goto out; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); - if (res < 0) - return res; - return put_user(tmp,(unsigned long *) data); + ret = read_long(child, addr, &tmp); + if (ret >= 0) + ret = put_user(tmp,(unsigned long *) data); + goto out; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; + ret = -EIO; if ((addr & 3) || addr < 0 || addr > sizeof(struct user) - 3) - return -EIO; + goto out; tmp = 0; /* Default return condition */ if(addr < 17*sizeof(long)) @@ -441,21 +448,26 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) addr = addr >> 2; tmp = child->debugreg[addr]; }; - return put_user(tmp,(unsigned long *) data); + ret = put_user(tmp,(unsigned long *) data); + goto out; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + ret = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; if ((addr & 3) || addr < 0 || addr > sizeof(struct user) - 3) - return -EIO; + goto out; - if (addr < 17*sizeof(long)) - return putreg(child, addr, data); + if (addr < 17*sizeof(long)) { + ret = putreg(child, addr, data); + goto out; + } /* We need to be very careful here. We implicitly want to modify a portion of the task_struct, and we @@ -470,26 +482,30 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if(addr < (long) &dummy->u_debugreg[4] && ((unsigned long) data) >= 0xbffffffd) return -EIO; + ret = -EIO; if(addr == (long) &dummy->u_debugreg[7]) { data &= ~DR_CONTROL_RESERVED; for(i=0; i<4; i++) if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) - return -EIO; + goto out; }; addr -= (long) &dummy->u_debugreg; addr = addr >> 2; child->debugreg[addr] = data; - return 0; + ret = 0; + goto out; }; - return -EIO; + ret = -EIO; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ long tmp; + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -499,7 +515,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET,tmp); - return 0; + ret = 0; + goto out; } /* @@ -510,35 +527,39 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_KILL: { long tmp; + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; + goto out; wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); - return 0; + goto out; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ long tmp; + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; child->flags &= ~PF_TRACESYS; tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ long tmp; + ret = -EIO; if ((unsigned long) data > NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -548,19 +569,25 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -573,4 +600,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; +out: + unlock_kernel(); } diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 14cd82f6642b..68fa03e1c326 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -30,8 +32,11 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) { unsigned long mask; - struct pt_regs * regs = (struct pt_regs *) &restart; + struct pt_regs * regs; + int res = -EINTR; + lock_kernel(); + regs = (struct pt_regs *) &restart; mask = current->blocked; current->blocked = set & _BLOCKABLE; regs->eax = -EINTR; @@ -39,8 +44,11 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(mask,regs)) - return -EINTR; + goto out; } +out: + unlock_kernel(); + return res; } static inline void restore_i387_hard(struct _fpstate *buf) @@ -100,7 +108,9 @@ if ( (tmp & 0xfffc) /* not a NULL selectors */ \ __asm__("mov %w0,%%" #seg: :"r" (tmp)); } struct sigcontext * context; struct pt_regs * regs; + int res; + lock_kernel(); regs = (struct pt_regs *) &__unused; context = (struct sigcontext *) regs->esp; if (verify_area(VERIFY_READ, context, sizeof(*context))) @@ -126,7 +136,9 @@ __asm__("mov %w0,%%" #seg: :"r" (tmp)); } goto badframe; restore_i387(buf); } - return context->eax; + res = context->eax; + unlock_kernel(); + return res; badframe: do_exit(SIGSEGV); } @@ -295,10 +307,13 @@ static void handle_signal(unsigned long signr, struct sigaction *sa, */ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) { - unsigned long mask = ~current->blocked; + unsigned long mask; unsigned long signr; struct sigaction * sa; + int res; + lock_kernel(); + mask = ~current->blocked; while ((signr = current->signal & mask)) { /* * This stops gcc flipping out. Otherwise the assembler @@ -371,7 +386,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) } } handle_signal(signr, sa, oldmask, regs); - return 1; + res = 1; + goto out; } /* Did we come from a system call? */ @@ -384,5 +400,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) regs->eip -= 2; } } - return 0; + res = 0; +out: + unlock_kernel(); + return res; } diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 8744071775c0..e5a52e754e49 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -21,6 +21,7 @@ * Erich Boleyn : MP v1.4 and additional changes. * Matthias Sattler : Changes for 2.1 kernel map. * Michel Lespinasse : Changes for 2.1 kernel map. + * Michael Chastain : Change trampoline.S to gnu as. * */ @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -140,7 +143,7 @@ volatile unsigned long smp_idle_map=0; /* Map for idle processors */ #endif volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */ -volatile unsigned long smp_process_available=0; +volatile int smp_process_available=0; /*#define SMP_DEBUG*/ @@ -506,9 +509,8 @@ int smp_scan_config(unsigned long base, unsigned long length) * Trampoline 80x86 program as an array. */ -static unsigned char trampoline_data[]={ -#include "trampoline.hex" -}; +extern unsigned char trampoline_data []; +extern unsigned char trampoline_end []; /* * Currently trivial. Write the real->protected mode @@ -518,7 +520,7 @@ static unsigned char trampoline_data[]={ static void install_trampoline(unsigned char *mp) { - memcpy(mp,trampoline_data,sizeof(trampoline_data)); + memcpy(mp, trampoline_data, trampoline_end - trampoline_data); } /* @@ -634,19 +636,25 @@ void smp_callin(void) * Until we are ready for SMP scheduling */ load_ldt(0); -/* printk("Testing faulting...\n"); - *(long *)0=1; OOPS... */ local_flush_tlb(); - while(!smp_commenced); + while(!task[cpuid] || current_set[cpuid] != task[cpuid]) + barrier(); + + if (cpu_number_map[cpuid] == -1) + while(1); + + local_flush_tlb(); + load_TR(cpu_number_map[cpuid]); + + while(!smp_commenced) + barrier(); local_flush_tlb(); - if (cpu_number_map[cpuid] == -1) - while(1); SMP_PRINTK(("Commenced..\n")); local_flush_tlb(); - load_TR(cpu_number_map[cpuid]); + sti(); } /* @@ -1253,27 +1261,20 @@ void smp_flush_tlb(void) void smp_reschedule_irq(int cpl, struct pt_regs *regs) { -/*#define DEBUGGING_SMP_RESCHED*/ -#ifdef DEBUGGING_SMP_RESCHED - static int ct=0; - if(ct==0) - { - printk("Beginning scheduling on CPU#%d\n",smp_processor_id()); - udelay(1000000); - ct=1; - } -#endif + lock_kernel(); + intr_count++; if(smp_processor_id()!=active_kernel_processor) panic("SMP Reschedule on CPU #%d, but #%d is active.\n", smp_processor_id(), active_kernel_processor); need_resched=1; - /* - * Clear the IPI - */ + /* Clear the IPI */ apic_read(APIC_SPIV); /* Dummy read */ apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */ + + intr_count--; + unlock_kernel(); } /* diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index 8ff3753e0a4e..70c09380437e 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,11 +30,13 @@ asmlinkage int sys_pipe(unsigned long * fildes) int fd[2]; int error; + lock_kernel(); error = do_pipe(fd); if (!error) { if (copy_to_user(fildes, fd, 2*sizeof(int))) error = -EFAULT; } + unlock_kernel(); return error; } @@ -53,18 +57,22 @@ struct mmap_arg_struct { asmlinkage int old_mmap(struct mmap_arg_struct *arg) { - int error; + int error = -EFAULT; struct file * file = NULL; struct mmap_arg_struct a; + lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; + goto out; if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) - return -EBADF; + goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); +out: + unlock_kernel(); return error; } @@ -79,10 +87,15 @@ struct sel_arg_struct { asmlinkage int old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; + int ret = -EFAULT; + lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); + goto out; + ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +out: + unlock_kernel(); + return ret; } /* @@ -92,53 +105,68 @@ asmlinkage int old_select(struct sel_arg_struct *arg) */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; + lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; + ret = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + ret = -EFAULT; if (get_user(fourth.__pad, (void **) ptr)) - return -EFAULT; - return sys_semctl (first, second, third, fourth); + goto out; + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; + ret = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + ret = -EFAULT; if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -146,25 +174,35 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; - return put_user (raddr, (ulong *) third); + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; + ret = put_user (raddr, (ulong *) third); + goto out; } case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; } diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S index c5c4efb7a5f3..63bc51c5ea30 100644 --- a/arch/i386/kernel/trampoline.S +++ b/arch/i386/kernel/trampoline.S @@ -1,86 +1,107 @@ -! -! Trampoline.S Derived from Setup.S by Linus Torvalds -! -! Entry: CS:IP point to the start of our code, we are -! in real mode with no stack, but the rest of the -! trampoline page to make our stack and everything else -! is a mystery. -! -! In fact we don't actually need a stack so we don't -! set one up. -! -! We jump into the boot/compressed/head.S code. So you'd -! better be running a compressed kernel image or you -! won't get very far. -! -#define __ASSEMBLY__ +/* + * + * Trampoline.S Derived from Setup.S by Linus Torvalds + * + * 4 Jan 1997 Michael Chastain: changed to gnu as. + * + * Entry: CS:IP point to the start of our code, we are + * in real mode with no stack, but the rest of the + * trampoline page to make our stack and everything else + * is a mystery. + * + * In fact we don't actually need a stack so we don't + * set one up. + * + * We jump into the boot/compressed/head.S code. So you'd + * better be running a compressed kernel image or you + * won't get very far. + * + * On entry to trampoline_data, the processor is in real mode + * with 16-bit addressing and 16-bit data. CS has some value + * and IP is zero. Thus, data addresses need to be absolute + * (no relocation) and are taken with regard to r_base. + * + * On the transition to protected mode, this page appears at + * address 8192, so protected mode addresses are with regard + * to p_base. + * + * If you work on this file, check the object module with objdump + * --full-contents --reloc to make sure there are no relocation + * entries. + */ + +#include #include -.text - extrn startup32 - -entry start -start: -! nop -! jmp start ! Test - mov ax,cs ! Code and data in the same place - mov ds,ax ! - mov cx,ax ! Pass stack info to the 32bit boot - add cx,cx - add cx,cx - add cx,cx - add cx,cx ! Segment -> Offset - add cx, #4096 ! End of page is wanted - mov bx,#1 ! Flag an SMP trampoline - cli ! We should be safe anyway - - lidt idt_48 ! load idt with 0,0 - lgdt gdt_48 ! load gdt with whatever is appropriate - - xor ax,ax - inc ax ! protected mode (PE) bit - lmsw ax ! Into protected mode +.data + +.code16 + +ENTRY(trampoline_data) +r_base = . +p_base = . - 8192 + + mov %cs, %ax # Code and data in the same place + mov %ax, %ds + + mov %ax, %cx # Pass stack info to the 32bit boot + shl $4, %cx # Segment -> Offset + add $4096, %cx # End of page is wanted + + mov $1, %bx # Flag an SMP trampoline + cli # We should be safe anyway + + movl $0xA5A5A5A5, trampoline_data - r_base + # write marker for master knows we're running + + lidt idt_48 - r_base # load idt with 0, 0 + lgdt gdt_48 - r_base # load gdt with whatever is appropriate + + xor %ax, %ax + inc %ax # protected mode (PE) bit + lmsw %ax # into protected mode jmp flush_instr flush_instr: - jmpi 8192+startup32,KERNEL_CS ! Jump to the 32bit trampoline code -! jmpi 0x100000,KERNEL_CS ! Jump into the 32bit startup -! .byte 0x66,0x67 ! 32bit -! .byte 0xea,0x00,0x00,0x10,0x00,0x10,0x00 !jmpi .0x100000,KERNEL_CS + ljmp $KERNEL_CS, $0x00100000 + # jump to startup_32 + +idt_48: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L +gdt_48: + .word 0x0800 # gdt limit = 2048, 256 GDT entries + .word gdt - p_base, 0x0 # gdt base = gdt (first SMP CPU) + # we load the others with first table + # saves rewriting gdt_48 for each gdt: - .word 0,0,0,0 ! dummy + .word 0, 0, 0, 0 # dummy - .word 0,0,0,0 ! unused + .word 0, 0, 0, 0 # unused -!walken modif - .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 ! base address=0 - .word 0x9A00 ! code read/exec - .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) +# walken modif - .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 ! base address=0 - .word 0x9200 ! data read/write - .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit) -!walken modif + .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) + .word 0x0000 # base address = 0 + .word 0x9A00 # code read / exec + .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) -! .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) -! .word 0x0000 ! base address=0 -! .word 0x9A00 ! code read/exec -! .word 0x00C0 ! granularity=4096, 386 + .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) + .word 0x0000 # base address = 0 + .word 0x9200 # data read / write + .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) -! .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) -! .word 0x0000 ! base address=0 -! .word 0x9200 ! data read/write -! .word 0x00C0 ! granularity=4096, 386 +# walken modif -idt_48: - .word 0 ! idt limit=0 - .word 0,0 ! idt base=0L +# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) +# .word 0x0000 # base address = 0 +# .word 0x9A00 # code read / exec +# .word 0x00C0 # granularity = 4096, 386 -gdt_48: - .word 0x800 ! gdt limit=2048, 256 GDT entries - .word 8192+gdt,0x0 ! gdt base = 8192+gdt (first SMP CPU) - ! we load the others with the first table - ! saves rewriting gdt_48 for each +# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) +# .word 0x0000 # base address = 0 +# .word 0x9200 # data read / write +# .word 0x00C0 # granularity = 4096, 386 +.globl SYMBOL_NAME(trampoline_end) +SYMBOL_NAME_LABEL(trampoline_end) diff --git a/arch/i386/kernel/trampoline32.S b/arch/i386/kernel/trampoline32.S deleted file mode 100644 index fafa972a057d..000000000000 --- a/arch/i386/kernel/trampoline32.S +++ /dev/null @@ -1,20 +0,0 @@ -! -! 32bit side of the trampoline code -! -#define __ASSEMBLY__ -#include -! -! -! Anything but a relative address here will be wrong by 8K... -! - .globl startup32 -.text -startup32: -! Run the kernel - mov eax,#KERNEL_DS - mov ds,ax - mov eax,#0xA5A5A5A5 - mov [8192],eax - jmpi 0x100000,KERNEL_CS -l1: - .byte 0xEA,0x00,0x00,0x10,0x00,0x10,0x00 diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 5f2dae994ffc..d62c1b3a7286 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -38,24 +40,29 @@ static inline void console_verbose(void) #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + lock_kernel(); \ tsk->tss.error_code = error_code; \ tsk->tss.trap_no = trapnr; \ force_sig(signr, tsk); \ die_if_kernel(str,regs,error_code); \ + unlock_kernel(); \ } #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + lock_kernel(); \ if (regs->eflags & VM_MASK) { \ if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \ - return; \ + goto out; \ /* else fall through */ \ } \ tsk->tss.error_code = error_code; \ tsk->tss.trap_no = trapnr; \ force_sig(signr, tsk); \ die_if_kernel(str,regs,error_code); \ +out: \ + unlock_kernel(); \ } #define get_seg_byte(seg,addr) ({ \ @@ -194,18 +201,22 @@ DO_ERROR(18, SIGSEGV, "reserved", reserved, current) asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { + lock_kernel(); if (regs->eflags & VM_MASK) { handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); - return; + goto out; } die_if_kernel("general protection",regs,error_code); current->tss.error_code = error_code; current->tss.trap_no = 13; force_sig(SIGSEGV, current); +out: + unlock_kernel(); } asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { + lock_kernel(); #ifdef CONFIG_SMP_NMI_INVAL smp_flush_tlb_rcv(); #else @@ -215,13 +226,15 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code) printk("power saving mode enabled.\n"); #endif #endif + unlock_kernel(); } asmlinkage void do_debug(struct pt_regs * regs, long error_code) { + lock_kernel(); if (regs->eflags & VM_MASK) { handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); - return; + goto out; } force_sig(SIGTRAP, current); current->tss.trap_no = 1; @@ -231,9 +244,11 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); - return; + goto out; } die_if_kernel("debug",regs,error_code); +out: + unlock_kernel(); } /* @@ -245,6 +260,7 @@ void math_error(void) { struct task_struct * task; + lock_kernel(); clts(); #ifdef __SMP__ task = current; @@ -253,7 +269,7 @@ void math_error(void) last_task_used_math = NULL; if (!task) { __asm__("fnclex"); - return; + goto out; } #endif /* @@ -266,18 +282,26 @@ void math_error(void) force_sig(SIGFPE, task); task->tss.trap_no = 16; task->tss.error_code = 0; +#ifndef __SMP__ +out: +#endif + unlock_kernel(); } asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { + lock_kernel(); ignore_irq13 = 1; math_error(); + unlock_kernel(); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, long error_code) { + lock_kernel(); printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); + unlock_kernel(); } /* @@ -289,6 +313,7 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, */ asmlinkage void math_state_restore(void) { + lock_kernel(); __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ /* @@ -301,7 +326,7 @@ asmlinkage void math_state_restore(void) */ #ifndef __SMP__ if (last_task_used_math == current) - return; + goto out; if (last_task_used_math) __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387)); else @@ -320,16 +345,22 @@ asmlinkage void math_state_restore(void) current->used_math = 1; } current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */ +#ifndef __SMP__ +out: +#endif + unlock_kernel(); } #ifndef CONFIG_MATH_EMULATION asmlinkage void math_emulate(long arg) { - printk("math-emulation not enabled and no coprocessor found.\n"); - printk("killing %s.\n",current->comm); - force_sig(SIGFPE,current); - schedule(); + lock_kernel(); + printk("math-emulation not enabled and no coprocessor found.\n"); + printk("killing %s.\n",current->comm); + force_sig(SIGFPE,current); + schedule(); + unlock_kernel(); } #endif /* CONFIG_MATH_EMULATION */ diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index cf47f4b31321..e964fb98713a 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -62,8 +64,10 @@ asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) { + struct pt_regs *ret; unsigned long tmp; + lock_kernel(); if (!current->tss.vm86_info) { printk("no vm86_info: BAD\n"); do_exit(SIGSEGV); @@ -79,7 +83,9 @@ asmlinkage struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) } current->tss.esp0 = current->saved_kernel_stack; current->saved_kernel_stack = 0; - return KVM86->regs32; + ret = KVM86->regs32; + unlock_kernel(); + return ret; } static void mark_screen_rdonly(struct task_struct * tsk) @@ -126,21 +132,27 @@ asmlinkage int sys_vm86old(struct vm86_struct * v86) * This remains on the stack until we * return to 32 bit user space. */ - struct task_struct *tsk = current; - int tmp; + struct task_struct *tsk; + int tmp, ret = -EPERM; + lock_kernel(); + tsk = current; if (tsk->saved_kernel_stack) - return -EPERM; + goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, (long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2); + ret = -EFAULT; if (tmp) - return -EFAULT; + goto out; memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus); info.regs32 = (struct pt_regs *) &v86; tsk->tss.vm86_info = v86; do_sys_vm86(&info, tsk); - return 0; /* we never return here */ + ret = 0; /* we never return here */ +out: + unlock_kernel(); + return ret; } @@ -151,37 +163,46 @@ asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86) * This remains on the stack until we * return to 32 bit user space. */ - struct task_struct *tsk = current; - int tmp; + struct task_struct *tsk; + int tmp, ret; + lock_kernel(); + tsk = current; switch (subfunction) { case VM86_REQUEST_IRQ: case VM86_FREE_IRQ: case VM86_GET_IRQ_BITS: case VM86_GET_AND_RESET_IRQ: - return do_vm86_irq_handling(subfunction,(int)v86); + ret = do_vm86_irq_handling(subfunction,(int)v86); + goto out; case VM86_PLUS_INSTALL_CHECK: /* NOTE: on old vm86 stuff this will return the error from verify_area(), because the subfunction is interpreted as (invalid) address to vm86_struct. So the installation check works. */ - return 0; + ret = 0; + goto out; } /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */ + ret = -EPERM; if (tsk->saved_kernel_stack) - return -EPERM; + goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, (long)&info.regs32 - (long)&info.regs.VM86_REGS_PART2); + ret = -EFAULT; if (tmp) - return -EFAULT; + goto out; info.regs32 = (struct pt_regs *) &subfunction; info.vm86plus.is_vm86pus = 1; tsk->tss.vm86_info = (struct vm86_struct *)v86; do_sys_vm86(&info, tsk); - return 0; /* we never return here */ + ret = 0; /* we never return here */ +out: + unlock_kernel(); + return ret; } @@ -232,6 +253,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk tsk->tss.screen_bitmap = info->screen_bitmap; if (info->flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(tsk); + unlock_kernel(); __asm__ __volatile__( "xorl %%eax,%%eax; mov %%ax,%%fs; mov %%ax,%%gs\n\t" "movl %0,%%esp\n\t" @@ -247,6 +269,7 @@ static inline void return_to_32bit(struct kernel_vm86_regs * regs16, int retval) regs32 = save_v86_state(regs16); regs32->eax = retval; + unlock_kernel(); __asm__ __volatile__("movl %0,%%esp\n\t" "jmp ret_from_sys_call" : : "r" (regs32), "b" (current)); @@ -408,20 +431,27 @@ cannot_handle: int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno) { + int ret; + + lock_kernel(); if (VMPI.is_vm86pus) { if ( (trapno==3) || (trapno==1) ) return_to_32bit(regs, VM86_TRAP + (trapno << 8)); do_int(regs, trapno, (unsigned char *) (regs->ss << 4), SP(regs)); - return 1; + ret = 1; + goto out; } + ret = 0; if (trapno !=1) - return 0; /* we let this handle by the calling routine */ + goto out; /* we let this handle by the calling routine */ if (current->flags & PF_PTRACED) current->blocked &= ~(1 << (SIGTRAP-1)); send_sig(SIGTRAP, current, 1); current->tss.trap_no = trapno; current->tss.error_code = error_code; - return 0; +out: + unlock_kernel(); + return ret; } @@ -436,8 +466,9 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) #define VM86_FAULT_RETURN \ if (VMPI.force_return_for_pic && (VEFLAGS & IF_MASK)) \ return_to_32bit(regs, VM86_PICRETURN); \ - return; + goto out; + lock_kernel(); csp = (unsigned char *) (regs->cs << 4); ssp = (unsigned char *) (regs->ss << 4); sp = SP(regs); @@ -501,7 +532,7 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) return_to_32bit(regs, VM86_INTx + (intno << 8)); } do_int(regs, intno, ssp, sp); - return; + goto out; } /* iret */ @@ -534,6 +565,8 @@ void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code) default: return_to_32bit(regs, VM86_UNKNOWN); } +out: + unlock_kernel(); } /* ---------------- vm86 special IRQ passing stuff ----------------- */ @@ -554,18 +587,19 @@ static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) { int irq_bit; unsigned long flags; + lock_kernel(); save_flags(flags); cli(); irq_bit = 1 << intno; - if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) { - restore_flags(flags); - return; - } + if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) + goto out; irqbits |= irq_bit; if (vm86_irqs[intno].sig) send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); /* else user will poll for IRQs */ +out: restore_flags(flags); + unlock_kernel(); } static inline void free_vm86_irq(int irqnumber) diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index cf54dd7df623..7ea3f1e29195 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -11,6 +11,6 @@ else endif L_TARGET = lib.a -L_OBJS = checksum.o semaphore.o +L_OBJS = checksum.o semaphore.o locks.o include $(TOPDIR)/Rules.make diff --git a/arch/i386/lib/locks.S b/arch/i386/lib/locks.S new file mode 100644 index 000000000000..b9d8b0a9c86e --- /dev/null +++ b/arch/i386/lib/locks.S @@ -0,0 +1,33 @@ +/* locks.S: Wheee... I'm coding Intel assembly... + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include + + /* Caller does atomic increment on current->lock_depth, + * if it was found to originally be zero then we get here, + * %eax contains callers PC and %edx holds this cpu ID. + */ +ENTRY(__lock_kernel) + pushl %eax ! return address +1: + lock + btsl $0, SYMBOL_NAME(kernel_flag) + jnc 3f +2: + btl %dl, SYMBOL_NAME(smp_invalidate_needed) + jnc 0f + lock + btrl %dl, SYMBOL_NAME(smp_invalidate_needed) + jnc 0f + movl %cr3, %eax + movl %eax, %cr3 +0: + btl $0, SYMBOL_NAME(kernel_flag) + jc 2b + jmp 1b + +3: + movb %dl, SYMBOL_NAME(active_kernel_processor) + ret diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index dafe0eb0217f..7d0628d00212 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -96,6 +98,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) unsigned long fixup; int write; + lock_kernel(); + /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); down(&mm->mmap_sem); @@ -154,7 +158,7 @@ good_area: if (bit < 32) tsk->tss.screen_bitmap |= 1 << bit; } - return; + goto out; /* * Something tried to access memory that isn't in our memory map.. @@ -167,7 +171,7 @@ bad_area: if ((fixup = search_exception_table(regs->eip)) != 0) { printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup); regs->eip = fixup; - return; + goto out; } if (error_code & 4) { @@ -175,7 +179,7 @@ bad_area: tsk->tss.error_code = error_code; tsk->tss.trap_no = 14; force_sig(SIGSEGV, tsk); - return; + goto out; } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -188,7 +192,7 @@ bad_area: pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); flush_tlb(); printk("This processor honours the WP bit even when in supervisor mode. Good.\n"); - return; + goto out; } if (address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -209,4 +213,6 @@ bad_area: } die_if_kernel("Oops", regs, error_code); do_exit(SIGKILL); +out: + unlock_kernel(); } diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index c027901ffb39..1fb61678bf94 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -289,6 +289,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) return; } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { int i; diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 4478957e4edb..6231f7c8b234 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -20,32 +20,32 @@ extern int dump_fpu(elf_fpregset_t *); /* platform dependent support */ -EXPORT_SYMBOLS(memcmp); -EXPORT_SYMBOLS(m68k_machtype); -EXPORT_SYMBOLS(m68k_cputype); -EXPORT_SYMBOLS(m68k_is040or060); -EXPORT_SYMBOLS(cache_push); -EXPORT_SYMBOLS(cache_push_v); -EXPORT_SYMBOLS(cache_clear); -EXPORT_SYMBOLS(mm_vtop); -EXPORT_SYMBOLS(mm_ptov); -EXPORT_SYMBOLS(mm_end_of_chunk); -EXPORT_SYMBOLS(m68k_debug_device); -EXPORT_SYMBOLS(request_irq); -EXPORT_SYMBOLS(free_irq); -EXPORT_SYMBOLS(dump_fpu); -EXPORT_SYMBOLS(dump_thread); -EXPORT_SYMBOLS(strnlen); -EXPORT_SYMBOLS(strrchr); -EXPORT_SYMBOLS(strstr); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(m68k_machtype); +EXPORT_SYMBOL(m68k_cputype); +EXPORT_SYMBOL(m68k_is040or060); +EXPORT_SYMBOL(cache_push); +EXPORT_SYMBOL(cache_push_v); +EXPORT_SYMBOL(cache_clear); +EXPORT_SYMBOL(mm_vtop); +EXPORT_SYMBOL(mm_ptov); +EXPORT_SYMBOL(mm_end_of_chunk); +EXPORT_SYMBOL(m68k_debug_device); +EXPORT_SYMBOL(request_irq); +EXPORT_SYMBOL(free_irq); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); /* The following are special because they're not called explicitly (the C compiler generates them). Fortunately, their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ -EXPORT_SYMBOLS_NOVERS(__ashrdi3); -EXPORT_SYMBOLS_NOVERS(memcpy); -EXPORT_SYMBOLS_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); -EXPORT_SYMBOLS_NOVERS(__down_failed); -EXPORT_SYMBOLS_NOVERS(__up_wakeup); +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__up_wakeup); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index f1393694efe5..ed0f28aa53dc 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,13 +36,20 @@ asmlinkage void ret_from_exception(void); */ asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; for (;;) schedule(); + ret = 0; +out: + unlock_kernel(); + return ret; } void hard_reset_now(void) @@ -86,20 +95,29 @@ void flush_thread(void) asmlinkage int m68k_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), regs); + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, rdusp(), regs); + unlock_kernel(); + return ret; } asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; + int ret; + lock_kernel(); /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; if (!newsp) newsp = rdusp(); - return do_fork(clone_flags, newsp, regs); + ret = do_fork(clone_flags, newsp, regs); + unlock_kernel(); + return ret; } void release_thread(struct task_struct *dead_task) @@ -224,10 +242,13 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp) char * filename; struct pt_regs *regs = (struct pt_regs *) &name; + lock_kernel(); error = getname(name, &filename); if (error) - return error; + goto out; error = do_execve(filename, argv, envp, regs); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index dc48a2ec53fe..407ebd6246d7 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -322,25 +324,29 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - struct user * dummy; - - dummy = NULL; + struct user * dummy = NULL; + int ret; + lock_kernel(); + ret = -EPERM; if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; + ret = -EPERM; if (request == PTRACE_ATTACH) { if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || @@ -348,10 +354,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->gid != child->egid) || (current->gid != child->sgid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -359,39 +365,42 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - return -ESRCH; + goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) - return -ESRCH; + goto out; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); - if (res < 0) - return res; - return put_user(tmp, (unsigned long *) data); + ret = read_long(child, addr, &tmp); + if (ret >= 0) + ret = put_user(tmp, (unsigned long *) data); + goto out; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; tmp = 0; /* Default return condition */ addr = addr >> 2; /* temporary hack. */ + ret = -EIO; if (addr < 19) { tmp = get_reg(child, addr); if (addr == PT_SR) @@ -400,23 +409,26 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else if (addr >= 21 && addr < 49) tmp = child->tss.fp[addr - 21]; else - return -EIO; - return put_user(tmp,(unsigned long *) data); + goto out; + ret = put_user(tmp,(unsigned long *) data); + goto out; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + ret = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; addr = addr >> 2; /* temporary hack. */ if (addr == PT_ORIG_D0) - return -EIO; + goto out; if (addr == PT_SR) { data &= SR_MASK; data <<= 16; @@ -424,22 +436,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } if (addr < 19) { if (put_reg(child, addr, data)) - return -EIO; - return 0; + goto out; + ret = 0; + goto out; } if (addr >= 21 && addr < 48) { child->tss.fp[addr - 21] = data; - return 0; + ret = 0; } - return -EIO; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -449,7 +463,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + ret = 0; + goto out; } /* @@ -460,21 +475,23 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_KILL: { long tmp; + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; + goto out; wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + goto out; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~PF_TRACESYS; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); put_reg(child, PT_SR, tmp); @@ -482,14 +499,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ long tmp; + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -499,19 +518,25 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); put_reg(child, PT_SR, tmp); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -524,5 +549,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; - return; +out: + unlock_kernel(); } diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 2197a7d02d53..4cbe4a9e887d 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,15 +33,18 @@ asmlinkage int sys_pipe(unsigned long * fildes) int fd[2]; int error; + lock_kernel(); error = verify_area(VERIFY_WRITE,fildes,8); if (error) - return error; + goto out; error = do_pipe(fd); if (error) - return error; + goto out; put_user(fd[0],0+fildes); put_user(fd[1],1+fildes); - return 0; +out: + unlock_kernel(); + return error; } /* @@ -64,16 +69,20 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) struct file * file = NULL; struct mmap_arg_struct a; + lock_kernel(); error = verify_area(VERIFY_READ, arg, sizeof(*arg)); if (error) - return error; + goto out; copy_from_user(&a, arg, sizeof(a)); if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) - return -EBADF; + goto out; } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); +out: + unlock_kernel(); return error; } @@ -89,10 +98,15 @@ struct sel_arg_struct { asmlinkage int old_select(struct sel_arg_struct *arg) { struct sel_arg_struct a; + int ret = -EFAULT; + lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); + goto out; + ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +out: + unlock_kernel(); + return ret; } /* @@ -102,7 +116,7 @@ asmlinkage int old_select(struct sel_arg_struct *arg) */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; @@ -110,46 +124,58 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) - return err; + goto out; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))) + goto out; get_user(fourth.__pad, (void **)ptr); - return sys_semctl (first, second, third, fourth); + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; + ret = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + ret = -EFAULT; if (copy_from_user (&tmp, ptr, sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -157,30 +183,40 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) - return err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; + if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + goto out; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; put_user (raddr, (ulong *) third); - return 0; + ret = 0; + goto out; } case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) @@ -496,60 +532,63 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) asmlinkage int sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) { - struct vm_area_struct *vma; + struct vm_area_struct *vma; + int ret = -EINVAL; - if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL - || cache & ~FLUSH_CACHE_BOTH) - return -EINVAL; + lock_kernel(); + if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || + cache & ~FLUSH_CACHE_BOTH) + goto out; - if (scope == FLUSH_SCOPE_ALL) - { - /* Only the superuser may flush the whole cache. */ - if (!suser ()) - return -EPERM; - } - else - { - /* Verify that the specified address region actually belongs to - this process. */ - vma = find_vma (current->mm, addr); - if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) - return -EINVAL; - } + if (scope == FLUSH_SCOPE_ALL) { + /* Only the superuser may flush the whole cache. */ + ret = -EPERM; + if (!suser ()) + goto out; + } else { + /* Verify that the specified address region actually belongs to + * this process. + */ + vma = find_vma (current->mm, addr); + ret = -EINVAL; + if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) + goto out; + } - if (CPU_IS_020_OR_030) { - if (scope == FLUSH_SCOPE_LINE) - { - unsigned long cacr; - __asm__ ("movec %%cacr, %0" : "=r" (cacr)); - if (cache & FLUSH_CACHE_INSN) - cacr |= 4; - if (cache & FLUSH_CACHE_DATA) - cacr |= 0x400; - len >>= 4; - while (len--) - { - __asm__ __volatile__ ("movec %1, %%caar\n\t" - "movec %0, %%cacr" - : /* no outputs */ - : "r" (cacr), "r" (addr)); - addr += 16; - } - } - else - { - /* Flush the whole cache, even if page granularity is requested. */ - unsigned long cacr; - __asm__ ("movec %%cacr, %0" : "=r" (cacr)); - if (cache & FLUSH_CACHE_INSN) - cacr |= 8; - if (cache & FLUSH_CACHE_DATA) - cacr |= 0x800; - __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); - } - return 0; - } else if (CPU_IS_040) - return cache_flush_040 (addr, scope, cache, len); - else if (CPU_IS_060) - return cache_flush_060 (addr, scope, cache, len); + if (CPU_IS_020_OR_030) { + if (scope == FLUSH_SCOPE_LINE) { + unsigned long cacr; + __asm__ ("movec %%cacr, %0" : "=r" (cacr)); + if (cache & FLUSH_CACHE_INSN) + cacr |= 4; + if (cache & FLUSH_CACHE_DATA) + cacr |= 0x400; + len >>= 4; + while (len--) { + __asm__ __volatile__ ("movec %1, %%caar\n\t" + "movec %0, %%cacr" + : /* no outputs */ + : "r" (cacr), "r" (addr)); + addr += 16; + } + } else { + /* Flush the whole cache, even if page granularity requested. */ + unsigned long cacr; + __asm__ ("movec %%cacr, %0" : "=r" (cacr)); + if (cache & FLUSH_CACHE_INSN) + cacr |= 8; + if (cache & FLUSH_CACHE_DATA) + cacr |= 0x800; + __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); + } + ret = 0; + goto out; + } else if (CPU_IS_040) { + ret = cache_flush_040 (addr, scope, cache, len); + } else if (CPU_IS_060) { + ret = cache_flush_060 (addr, scope, cache, len); + } +out: + unlock_kernel(); + return ret; } diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 5047173122a7..b5d37c0c5d5a 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -477,6 +477,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) datapages << (PAGE_SHIFT-10)); } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { unsigned long i; diff --git a/arch/mips/kernel/ipc.c b/arch/mips/kernel/ipc.c index 3c156c81c5d2..668deb8e1739 100644 --- a/arch/mips/kernel/ipc.c +++ b/arch/mips/kernel/ipc.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,57 +27,67 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { #ifdef CONFIG_SYSVIPC - int version; + int version, ret; + lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) - return err; + goto out; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))) + goto out; fourth.__pad = (void *) get_fs_long(ptr); - return sys_semctl (first, second, third, fourth); + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - int err; if (!ptr) return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) - return err; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) + goto out; memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)); - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -83,30 +95,40 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) - return err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; + if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + goto out; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; put_fs_long (raddr, (ulong *) third); - return 0; + ret = 0; + goto out; } case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; #else /* CONFIG_SYSVIPC */ return -ENOSYS; #endif /* CONFIG_SYSVIPC */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a282f4263689..7cc537294e4d 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -5,6 +5,8 @@ */ #include #include +#include +#include #include #include #include @@ -29,8 +31,11 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) { unsigned long mask; - struct pt_regs * regs = (struct pt_regs *) &restart; + struct pt_regs * regs; + int ret = -EINTR; + lock_kernel(); + regs = (struct pt_regs *) &restart; mask = current->blocked; current->blocked = set & _BLOCKABLE; regs->reg2 = -EINTR; @@ -38,8 +43,11 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(mask,regs)) - return -EINTR; + goto out; } +out: + unlock_kernel(); + return ret; } /* @@ -48,7 +56,9 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigcontext_struct *context; + int ret; + lock_kernel(); /* * We don't support fixing ADEL/ADES exceptions for signal stack frames. * No big loss - who doesn't care about the alignment of this stack @@ -99,10 +109,14 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) * disable syscall checks */ regs->orig_reg2 = -1; - return context->sc_v0; + goto out; badframe: do_exit(SIGSEGV); +out: + ret = context->sc_v0; + unlock_kernel(); + return ret; } /* @@ -239,13 +253,16 @@ static void setup_frame(struct sigaction * sa, struct sc **fp, */ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) { - unsigned long mask = ~current->blocked; + unsigned long mask; unsigned long handler_signal = 0; struct sc *frame = NULL; unsigned long pc = 0; unsigned long signr; struct sigaction * sa; + int ret; + lock_kernel(); + mask = ~current->blocked; while ((signr = current->signal & mask)) { signr = ffz(~signr); clear_bit(signr, ¤t->signal); @@ -331,8 +348,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) regs->reg2 = regs->orig_reg2; regs->cp0_epc -= 8; } + ret = 0; if (!handler_signal) /* no handler will be called - return 0 */ - return 0; + goto out; pc = regs->cp0_epc; frame = (struct sc *) regs->reg29; signr = 1; @@ -353,5 +371,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) regs->reg31 = (unsigned long) frame->code; /* Return address */ regs->cp0_epc = pc; /* "return" to the first handler */ - return 1; + ret = 1; +out: + unlock_kernel(); + return ret; } diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index e7dd048a7e8d..a8839bb1abf8 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -9,6 +9,8 @@ */ #include #include +#include +#include #include #include #include @@ -28,32 +30,43 @@ asmlinkage int sys_pipe(struct pt_regs *regs) int fd[2]; int error; + lock_kernel(); error = do_pipe(fd); if (error) - return error; + goto out; regs->reg2 = fd[0]; regs->reg3 = fd[1]; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, off_t offset) { struct file * file = NULL; + int ret = -EBADF; + lock_kernel(); if (flags & MAP_RENAME) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - return do_mmap(file, addr, len, prot, flags, offset); + ret = do_mmap(file, addr, len, prot, flags, offset); +out: + unlock_kernel(); + return ret; } asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; @@ -67,23 +80,36 @@ asmlinkage int sys_idle(void) ".set\tmips0\n\t"); schedule(); } + ret = 0; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_fork(struct pt_regs *regs) { - return do_fork(SIGCHLD, regs->reg29, regs); + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, regs->reg29, regs); + unlock_kernel(); + return ret; } asmlinkage int sys_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; + int ret; + lock_kernel(); clone_flags = regs->reg4; newsp = regs->reg5; if (!newsp) newsp = regs->reg29; - return do_fork(clone_flags, newsp, regs); + ret = do_fork(clone_flags, newsp, regs); + unlock_kernel(); + return ret; } /* @@ -94,12 +120,15 @@ asmlinkage int sys_execve(struct pt_regs *regs) int error; char * filename; + lock_kernel(); error = getname((char *) regs->reg4, &filename); if (error) - return error; + goto out; error = do_execve(filename, (char **) regs->reg5, (char **) regs->reg6, regs); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c index 07ae26ee4dd2..d5ec3390be4c 100644 --- a/arch/mips/kernel/sysmips.c +++ b/arch/mips/kernel/sysmips.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -54,44 +56,51 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3) char *name; int flags, len, retval = -EINVAL; + lock_kernel(); switch(cmd) { case SETNAME: + retval = -EPERM; if (!suser()) - return -EPERM; + goto out; name = (char *) arg1; len = get_max_hostname((unsigned long)name); - if (retval < 0) - return len; + retval = len; + if (len < 0) + goto out; len = strnlen_user(name, retval); + retval = -EINVAL; if (len == 0 || len > __NEW_UTS_LEN) - return -EINVAL; + goto out; memcpy_fromfs(system_utsname.nodename, name, len); system_utsname.nodename[len] = '\0'; - return 0; + retval = 0; + goto out; case MIPS_ATOMIC_SET: p = (int *) arg1; - retval = verify_area(VERIFY_WRITE, p, sizeof(*p)); - if(retval) - return -EINVAL; + retval = -EINVAL; + if(verify_area(VERIFY_WRITE, p, sizeof(*p))) + goto out; save_flags(flags); cli(); retval = *p; *p = arg2; restore_flags(flags); - return retval; + goto out; case MIPS_FIXADE: if (arg1) current->tss.mflags |= MF_FIXADE; else current->tss.mflags |= MF_FIXADE; retval = 0; - break; + goto out; case FLUSH_CACHE: sys_cacheflush(0, ~0, BCACHE); - break; + retval = 0; + goto out; } - +out: + unlock_kernel(); return retval; } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index cabaae009c79..6b855802a412 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -281,6 +281,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) return; } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { int i; diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 00cf40f03f4b..8dc0e61ca362 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -133,19 +135,30 @@ switch_to(struct task_struct *prev, struct task_struct *new) asmlinkage int sys_debug(unsigned long r3) { - if ( !strcmp(current->comm,"crashme")) - printk("sys_debug(): r3 (syscall) %d\n", r3); + lock_kernel(); + if (!strcmp(current->comm,"crashme")) + printk("sys_debug(): r3 (syscall) %d\n", r3); + unlock_kernel(); + return 0; } asmlinkage int sys_idle(void) { - if (current->pid != 0) - return -EPERM; - /* endless idle loop with no priority at all */ - current->counter = -100; - for (;;) { - schedule(); - } + int ret = -EPERM; + + lock_kernel(); + if (current->pid != 0) + goto out; + + /* endless idle loop with no priority at all */ + current->counter = -100; + for (;;) { + schedule(); + } + ret = 0; +out: + unlock_kernel(); + return ret; } void show_regs(struct pt_regs * regs) @@ -232,7 +245,12 @@ void dump_thread(struct pt_regs * regs, struct user * dump) asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs) { - return do_fork(SIGCHLD, regs->gpr[1], regs); + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, regs->gpr[1], regs); + unlock_kernel(); + return ret; } asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, @@ -242,6 +260,7 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, int error; char * filename; + lock_kernel(); /* getname does it's own verification of the address when it calls get_max_filename() but it will assume it's valid if get_fs() == KERNEL_DS @@ -265,9 +284,7 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, #endif error = getname((char *) a0, &filename); if (error) - { - return error; - } + goto out; flush_instruction_cache(); error = do_execve(filename, (char **) a1, (char **) a2, regs); #if 0 @@ -277,6 +294,8 @@ printk("EXECVE - file = '%s', error = %d\n", filename, error); } #endif putname(filename); +out: + unlock_kernel(); return error; } @@ -284,7 +303,10 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct { unsigned long clone_flags = p1; int res; + + lock_kernel(); res = do_fork(clone_flags, regs->gpr[1], regs); + unlock_kernel(); return res; } @@ -339,9 +361,9 @@ print_kernel_backtrace(void) inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp) { - regs->nip = eip; - regs->gpr[1] = esp; - regs->msr = MSR_USER; - set_fs(USER_DS); + regs->nip = eip; + regs->gpr[1] = esp; + regs->msr = MSR_USER; + set_fs(USER_DS); } diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 7cfad9987f4f..2d960c8cd734 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -376,34 +378,37 @@ static int write_long(struct task_struct * tsk, unsigned long addr, asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; - struct user * dummy; - - dummy = NULL; + struct user * dummy = NULL; + int ret = -EPERM; + lock_kernel(); if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->flags & PF_PTRACED) - return -EPERM; + goto out; /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; - return 0; + ret = 0; + goto out; } if (pid == 1) /* you may not mess with init */ - return -EPERM; + goto out; + ret = -ESRCH; if (!(child = get_task(pid))) - return -ESRCH; + goto out; + ret = -EPERM; if (request == PTRACE_ATTACH) { if (child == current) - return -EPERM; + goto out; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->gid)) && !suser()) - return -EPERM; + goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - return -EPERM; + goto out; child->flags |= PF_PTRACED; if (child->p_pptr != current) { REMOVE_LINKS(child); @@ -411,73 +416,75 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); } send_sig(SIGSTOP, child, 1); - return 0; + ret = 0; + goto out; } + ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - return -ESRCH; + goto out; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - return -ESRCH; + goto out; } if (child->p_pptr != current) - return -ESRCH; + goto out; switch (request) { /* If I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int res; - res = read_long(child, addr, &tmp); - if (res < 0) - return res; - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (!res) + ret = read_long(child, addr, &tmp); + if (ret < 0) + goto out; + ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); + if (!ret) put_user(tmp, (unsigned long *) data); - return res; + goto out; } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; - int res; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) return -EIO; - res = verify_area(VERIFY_WRITE, (void *) data, + ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (res) - return res; + if (ret) + goto out; tmp = 0; /* Default return condition */ addr = addr >> 2; /* temporary hack. */ - if (addr < PT_FPR0) { + if (addr < PT_FPR0) tmp = get_reg(child, addr); - } #if 0 else if (addr >= PT_FPR0 && addr < PT_FPR31) tmp = child->tss.fpr[addr - PT_FPR0]; #endif else - return -EIO; - put_user(tmp,(unsigned long *) data); - return 0; + ret = -EIO; + if(!ret) + put_user(tmp,(unsigned long *) data); + goto out; } /* If I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - return write_long(child,addr,data); + ret = write_long(child,addr,data); + goto out; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - return -EIO; + goto out; addr = addr >> 2; /* temporary hack. */ if (addr == PT_ORIG_R3) - return -EIO; + goto out; #if 0 /* Let this check be in 'put_reg' */ if (addr == PT_SR) { data &= SR_MASK; @@ -487,22 +494,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) #endif if (addr < PT_FPR0) { if (put_reg(child, addr, data)) - return -EIO; - return 0; + goto out; + ret = 0; + goto out; } #if 0 - if (addr >= 21 && addr < 48) - { + if (addr >= 21 && addr < 48) { child->tss.fp[addr - 21] = data; - return 0; + ret = 0; + goto out; } #endif - return -EIO; + goto out; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else @@ -511,7 +520,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + ret = 0; + goto out; } /* @@ -520,29 +530,33 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) * exit. */ case PTRACE_KILL: { + ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; + goto out; wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + goto out; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~PF_TRACESYS; set_single_step(child); wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ - return 0; + ret = 0; + goto out; } case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; if ((unsigned long) data >= NSIG) - return -EIO; + goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; @@ -551,19 +565,25 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) SET_LINKS(child); /* make sure the single step bit is not set. */ clear_single_step(child); - return 0; + ret = 0; + goto out; } default: - return -EIO; + ret = -EIO; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage void syscall_trace(void) { + lock_kernel(); if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current); @@ -576,5 +596,6 @@ asmlinkage void syscall_trace(void) if (current->exit_code) current->signal |= (1 << (current->exit_code - 1)); current->exit_code = 0; - return; +out: + unlock_kernel(); } diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index ca07edc7ca1b..ba8864251f7a 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -28,7 +30,9 @@ asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs) { unsigned long mask; + int ret = -EINTR; + lock_kernel(); mask = current->blocked; current->blocked = set & _BLOCKABLE; regs->gpr[3] = -EINTR; @@ -39,15 +43,20 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(mask,regs)) - return -EINTR; + goto out; } +out: + unlock_kernel(); + return ret; } asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigcontext_struct *sc; struct pt_regs *int_regs; - int signo; + int signo, ret; + + lock_kernel(); #if 1 if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc)) || (regs->gpr[1] >=KERNELBASE)) @@ -58,8 +67,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) int_regs = sc->regs; signo = sc->signal; sc++; /* Pop signal 'context' */ - if (sc == (struct sigcontext_struct *)(int_regs)) - { /* Last stacked signal */ + if (sc == (struct sigcontext_struct *)(int_regs)) { + /* Last stacked signal */ #if 0 /* This doesn't work - it blows away the return address! */ memcpy(regs, int_regs, sizeof(*regs)); @@ -76,20 +85,24 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) regs->nip -= 4; /* Back up & retry system call */ regs->result = 0; } - return (regs->result); - } else - { /* More signals to go */ + ret = (regs->result); + } else { /* More signals to go */ regs->gpr[1] = (unsigned long)sc; regs->gpr[3] = sc->signal; regs->gpr[4] = sc->regs; regs->link = (unsigned long)((sc->regs)+1); regs->nip = sc->handler; - return (sc->signal); + ret = sc->signal; } + goto out; + badframe: /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n", regs,current->comm,current->pid);*/ - do_exit(SIGSEGV); + do_exit(SIGSEGV); +out: + unlock_kernel(); + return ret; } @@ -104,159 +117,167 @@ badframe: */ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) { - unsigned long mask = ~current->blocked; - unsigned long handler_signal = 0; - unsigned long *frame = NULL; - unsigned long *trampoline; - unsigned long *regs_ptr; - unsigned long nip = 0; - unsigned long signr; - int bitno; - struct sigcontext_struct *sc; - struct sigaction * sa; - int s; + unsigned long mask; + unsigned long handler_signal = 0; + unsigned long *frame = NULL; + unsigned long *trampoline, *regs_ptr; + unsigned long nip = 0; + unsigned long signr; + struct sigcontext_struct *sc; + struct sigaction * sa; + int bitno, s, ret; - while ((signr = current->signal & mask)) { - for (bitno = 0; bitno < 32; bitno++) - { - if (signr & (1<blocked; + while ((signr = current->signal & mask)) { + for (bitno = 0; bitno < 32; bitno++) + if (signr & (1<signal &= ~(1<sig->action + signr; - signr++; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { - current->exit_code = signr; - current->state = TASK_STOPPED; - notify_parent(current); - schedule(); - if (!(signr = current->exit_code)) - continue; - current->exit_code = 0; - if (signr == SIGSTOP) - continue; - if (_S(signr) & current->blocked) { - current->signal |= _S(signr); - continue; - } - sa = current->sig->action + signr - 1; - } - if (sa->sa_handler == SIG_IGN) { - if (signr != SIGCHLD) - continue; - /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) - /* nothing */; - continue; - } - if (sa->sa_handler == SIG_DFL) { - if (current->pid == 1) - continue; - switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: - continue; + current->signal &= ~(1<sig->action + signr; + signr++; + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + if (signr == SIGSTOP) + continue; + if (_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sig->action + signr - 1; + } + if (sa->sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* check for SIGCHLD: it's special */ + while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* nothing */; + continue; + } + if (sa->sa_handler == SIG_DFL) { + if (current->pid == 1) + continue; + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: - if (current->flags & PF_PTRACED) - continue; - current->state = TASK_STOPPED; - current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) - notify_parent(current); - schedule(); - continue; + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGIOT: case SIGFPE: case SIGSEGV: + if (current->binfmt && current->binfmt->core_dump) { + if (current->binfmt->core_dump(signr, regs)) + signr |= 0x80; + } + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + do_exit(signr); + } + } - case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; + /* handle signal */ + if ((int)regs->orig_gpr3 >= 0) { + if ((int)regs->result == -ERESTARTNOHAND || + ((int)regs->result == -ERESTARTSYS && + !(sa->sa_flags & SA_RESTART))) + (int)regs->result = -EINTR; + } + handler_signal |= 1 << (signr-1); + mask &= ~sa->sa_mask; } - /* fall through */ - default: - current->signal |= _S(signr & 0x7f); - do_exit(signr); - } - } - /* handle signal */ - - if ((int)regs->orig_gpr3 >= 0) { - if ((int)regs->result == -ERESTARTNOHAND || - ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) - (int)regs->result = -EINTR; - } - handler_signal |= 1 << (signr-1); - mask &= ~sa->sa_mask; - } - if (!handler_signal) /* no handler will be called - return 0 */ - { - return 0; - } + ret = 0; + if (!handler_signal) /* no handler will be called - return 0 */ + goto out; + nip = regs->nip; + frame = (unsigned long *) regs->gpr[1]; - nip = regs->nip; - frame = (unsigned long *) regs->gpr[1]; - /* Build trampoline code on stack */ - frame -= 2; - trampoline = frame; + /* Build trampoline code on stack */ + frame -= 2; + trampoline = frame; #if 1 - /* verify stack is valid for writing regs struct */ - if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs)) - || (frame >= KERNELBASE )) - goto badframe; + /* verify stack is valid for writing regs struct */ + if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs)) + || (frame >= KERNELBASE )) + goto badframe; #endif - trampoline[0] = 0x38007777; /* li r0,0x7777 */ - trampoline[1] = 0x44000002; /* sc */ - frame -= sizeof(*regs) / sizeof(long); - regs_ptr = frame; - memcpy(regs_ptr, regs, sizeof(*regs)); - signr = 1; - sa = current->sig->action; - + trampoline[0] = 0x38007777; /* li r0,0x7777 */ + trampoline[1] = 0x44000002; /* sc */ + frame -= sizeof(*regs) / sizeof(long); + regs_ptr = frame; + memcpy(regs_ptr, regs, sizeof(*regs)); + signr = 1; + sa = current->sig->action; - for (mask = 1 ; mask ; sa++,signr++,mask += mask) { - if (mask > handler_signal) - break; - if (!(mask & handler_signal)) - continue; + for (mask = 1 ; mask ; sa++,signr++,mask += mask) { + if (mask > handler_signal) + break; + if (!(mask & handler_signal)) + continue; - frame -= sizeof(struct sigcontext_struct) / sizeof(long); + frame -= sizeof(struct sigcontext_struct) / sizeof(long); #if 1 - if (verify_area(VERIFY_WRITE,(void *)frame, - sizeof(struct sigcontext_struct)/sizeof(long))) - goto badframe; + if (verify_area(VERIFY_WRITE,(void *)frame, + sizeof(struct sigcontext_struct)/sizeof(long))) + goto badframe; #endif - sc = (struct sigcontext_struct *)frame; - nip = (unsigned long) sa->sa_handler; + sc = (struct sigcontext_struct *)frame; + nip = (unsigned long) sa->sa_handler; #if 0 /* Old compiler */ - nip = *(unsigned long *)nip; + nip = *(unsigned long *)nip; #endif - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - sc->handler = nip; - sc->oldmask = current->blocked; - sc->regs = (unsigned long)regs_ptr; - sc->signal = signr; - current->blocked |= sa->sa_mask; - regs->gpr[3] = signr; - regs->gpr[4] = (unsigned long)regs_ptr; - } - regs->link = (unsigned long)trampoline; - regs->nip = nip; - regs->gpr[1] = (unsigned long)sc; - /* The DATA cache must be flushed here to insure coherency */ - /* between the DATA & INSTRUCTION caches. Since we just */ - /* created an instruction stream using the DATA [cache] space */ - /* and since the instruction cache will not look in the DATA */ - /* cache for new data, we have to force the data to go on to */ - /* memory and flush the instruction cache to force it to look */ - /* there. The following function performs this magic */ - flush_instruction_cache(); - return 1; + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + sc->handler = nip; + sc->oldmask = current->blocked; + sc->regs = (unsigned long)regs_ptr; + sc->signal = signr; + current->blocked |= sa->sa_mask; + regs->gpr[3] = signr; + regs->gpr[4] = (unsigned long)regs_ptr; + } + regs->link = (unsigned long)trampoline; + regs->nip = nip; + regs->gpr[1] = (unsigned long)sc; + + /* The DATA cache must be flushed here to insure coherency + * between the DATA & INSTRUCTION caches. Since we just + * created an instruction stream using the DATA [cache] space + * and since the instruction cache will not look in the DATA + * cache for new data, we have to force the data to go on to + * memory and flush the instruction cache to force it to look + * there. The following function performs this magic + */ + flush_instruction_cache(); + ret = 1; + goto out; + badframe: - /* printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n", - signr,frame,regs,current->comm,current->pid);*/ - do_exit(SIGSEGV); +#if 0 + printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n", + signr, frame, regs, current->comm, current->pid); +#endif + do_exit(SIGSEGV); + +out: + unlock_kernel(); + return ret; } diff --git a/arch/ppc/kernel/stubs.c b/arch/ppc/kernel/stubs.c index 78069d11c04f..30f02827995b 100644 --- a/arch/ppc/kernel/stubs.c +++ b/arch/ppc/kernel/stubs.c @@ -1,24 +1,56 @@ /*#include */ #include +#include +#include -void sys_iopl(void) { panic("sys_iopl"); } -void sys_vm86(void) { panic("sys_vm86"); } -void sys_modify_ldt(void) { panic("sys_modify_ldt"); } +void sys_iopl(void) +{ + lock_kernel(); + panic("sys_iopl"); + unlock_kernel(); +} +void sys_vm86(void) +{ + lock_kernel(); + panic("sys_vm86"); + unlock_kernel(); +} +void sys_modify_ldt(void) +{ + lock_kernel(); + panic("sys_modify_ldt"); + unlock_kernel(); +} -void sys_ipc(void) {panic("sys_ipc"); } -void sys_newselect(void) {panic("sys_newselect"); } +void sys_ipc(void) +{ + lock_kernel(); + panic("sys_ipc"); + unlock_kernel(); +} + +void sys_newselect(void) +{ + lock_kernel(); + panic("sys_newselect"); + unlock_kernel(); +} #ifndef CONFIG_MODULES void scsi_register_module(void) { + lock_kernel(); panic("scsi_register_module"); + unlock_kernel(); } void scsi_unregister_module(void) { + lock_kernel(); panic("scsi_unregister_module"); + unlock_kernel(); } #endif diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index dc7fc413423a..9d18c45ab2cf 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,27 +28,33 @@ asmlinkage int sys_pipe(unsigned long * fildes) { int error; + + lock_kernel(); error = verify_area(VERIFY_WRITE,fildes,8); if (error) - return error; + goto out; error = do_pipe(fildes); - if (error) - return error; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, off_t offset) { struct file * file = NULL; + int ret = -EBADF; + lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - return do_mmap(file, addr, len, prot, flags, offset); + ret = do_mmap(file, addr, len, prot, flags, offset); +out: + unlock_kernel(); + return ret; } /* @@ -62,21 +70,27 @@ asmlinkage int old_mmap(unsigned long *buffer) long a,b,c,d,e; struct file * file = NULL; + lock_kernel(); error = verify_area(VERIFY_READ, buffer, 6*sizeof(long)); if (error) - return error; + goto out; get_user(flags,buffer+3); if (!(flags & MAP_ANONYMOUS)) { unsigned long fd; get_user(fd,buffer+4); + error = -EBADF; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + error = -EFAULT; if ( get_user(a,buffer) || get_user(b,buffer+1) || get_user(c,buffer+2)||get_user(d,buffer+5) ) - return -EFAULT; - return do_mmap(file,a,b,c, flags, d); + goto out; + error = do_mmap(file,a,b,c, flags, d); +out: + unlock_kernel(); + return error; } extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); @@ -89,15 +103,19 @@ asmlinkage int old_select(unsigned long *buffer) fd_set *exp; struct timeval *tvp; + lock_kernel(); n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long)); if (n) - return n; + goto out; get_user(n,buffer); get_user(inp,buffer+1); get_user(outp,buffer+2); get_user(exp,buffer+3); get_user(tvp,buffer+4); - return sys_select(n, inp, outp, exp, tvp); + n = sys_select(n, inp, outp, exp, tvp); +out: + unlock_kernel(); + return n; } #if 0 @@ -108,57 +126,68 @@ asmlinkage int old_select(unsigned long *buffer) */ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, ret; + lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + ret = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) - return err; + goto out; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))) + goto out; fourth.__pad = (void *) get_fs_long(ptr); - return sys_semctl (first, second, third, fourth); + ret = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - int err; + ret = -EINVAL; if (!ptr) - return -EINVAL; - if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) - return err; + goto out; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) + goto out; memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)); - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + ret = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -166,29 +195,39 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) - return err; - err = sys_shmat (first, (char *) ptr, second, &raddr); - if (err) - return err; + if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + goto out; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; put_fs_long (raddr, (ulong *) third); - return 0; + ret = 0; + goto out; } case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; if (get_fs() != get_ds()) - return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + ret = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + ret = -EINVAL; + goto out; } - return -EINVAL; + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; } #endif diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index e1015aeb57be..fa8274c3130b 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -174,6 +174,11 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) return; } +void free_initmem(void) +{ + /* To be written */ +} + void si_meminfo(struct sysinfo *val) { int i; diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 3e372482510b..b62c95f7681b 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 1996/12/18 06:17:39 tridge Exp $ +# $Id: Makefile,v 1.23 1997/01/02 14:14:17 jj Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -18,7 +18,8 @@ SHELL =/bin/bash #CFLAGS := $(CFLAGS) -g -pipe CFLAGS := $(CFLAGS) -pipe -LINKFLAGS = -N -Ttext 0xf0004000 +#LINKFLAGS = -N -Ttext 0xf0004000 +LINKFLAGS = -T arch/sparc/vmlinux.lds HEAD := arch/sparc/kernel/head.o @@ -30,9 +31,6 @@ ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES) LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a -INITOBJ = $(TOPDIR)/arch/sparc/kernel/initobj.o -FINITOBJ = $(TOPDIR)/arch/sparc/kernel/finitobj.o - ifdef CONFIG_AP1000 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp ARCHIVES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o $(TOPDIR)/mpp/mpplib.o $(ARCHIVES) @@ -41,6 +39,5 @@ CFLAGS := $(CFLAGS) -D__MPP__=1 endif archclean: - rm -f $(TOPDIR)/arch/sparc/boot/boot archdep: diff --git a/arch/sparc/ap1000/Makefile b/arch/sparc/ap1000/Makefile new file mode 100644 index 000000000000..83df0ef8ea44 --- /dev/null +++ b/arch/sparc/ap1000/Makefile @@ -0,0 +1,20 @@ +# Makefile for the AP1000 files in the Linux kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s +.S.o: + $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + +all: ap1000lib.o + +O_TARGET := ap1000lib.o +O_OBJS := bnet.o timer.o util.o dma.o kgdb.o irq.o \ + msc.o hw.o tnet.o sync.o mpp.o \ + apmmu.o aplib.o approm.o + +include $(TOPDIR)/Rules.make diff --git a/arch/sparc/ap1000/apinline.h b/arch/sparc/ap1000/apinline.h new file mode 100644 index 000000000000..d8170b59ef19 --- /dev/null +++ b/arch/sparc/ap1000/apinline.h @@ -0,0 +1,86 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* inline utilities to support the AP1000 code */ + +#if 0 +/* MMU bypass access */ + +static inline unsigned long phys_9_in(unsigned long paddr) +{ + unsigned long word; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (word) : + "r" (paddr), "i" (0x29) : + "memory"); + return word; +} + +static inline void phys_9_out(unsigned long paddr, unsigned long word) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (word), "r" (paddr), "i" (0x29) : + "memory"); +} + +static inline unsigned long phys_b_in(unsigned long paddr) +{ + unsigned long word; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (word) : + "r" (paddr), "i" (0x2b) : + "memory"); + return word; +} + +static inline void phys_b_out(unsigned long paddr, unsigned long word) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (word), "r" (paddr), "i" (0x2b) : + "memory"); +} + +static inline unsigned long phys_c_in(unsigned long paddr) +{ + unsigned long word; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (word) : + "r" (paddr), "i" (0x2b) : + "memory"); + return word; +} + +static inline void phys_c_out(unsigned long paddr, unsigned long word) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (word), "r" (paddr), "i" (0x2b) : + "memory"); +} + +#undef BIF_IN +#undef BIF_OUT +#undef DMA_IN +#undef DMA_OUT +#undef MSC_IN +#undef MSC_OUT +#undef MC_IN +#undef MC_OUT + +#define BIF_IN(reg) phys_9_in(reg) +#define BIF_OUT(reg,v) phys_9_out(reg,v) +#define DMA_IN(reg) phys_9_in(reg) +#define DMA_OUT(reg,v) phys_9_out(reg,v) +#define MC_IN(reg) phys_b_in((reg) - MC_BASE0) +#define MC_OUT(reg,v) phys_b_out((reg) - MC_BASE0,v) +#define MSC_IN(reg) phys_c_in((reg) - MSC_BASE0) +#define MSC_OUT(reg,v) phys_c_out((reg) - MSC_BASE0,v) +#endif + + diff --git a/arch/sparc/ap1000/aplib.c b/arch/sparc/ap1000/aplib.c new file mode 100644 index 000000000000..55a778ed792a --- /dev/null +++ b/arch/sparc/ap1000/aplib.c @@ -0,0 +1,496 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ + +/* kernel based aplib. + + This was initially implemented in user space, but we eventually + relented when we discovered some really nasty MSC hardware bugs and + decided to disallow access to the device registers by users. Pity :-( + + Andrew Tridgell, November 1996 +*/ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + #include +#include +#include +#include + + +extern int *tnet_rel_cid_table; +extern unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy; + + +/* this is used to stop the task hogging the MSC while paging in data */ +static inline void page_in(char *addr,long size) +{ + unsigned sum = 0; + while (size > 0) { + sum += *(volatile char *)addr; + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } +} + + +/* this sets up the aplib structures using info passed in from user space + it should only be called once, and should be the first aplib call + it should be followed by APLIB_SYNC + */ +static inline int aplib_init(struct aplib_init *init) +{ + struct aplib_struct *aplib; + int error,i; + int old_uid; + + error = verify_area(VERIFY_READ,init,sizeof(*init)); + if (error) return error; + error = verify_area(VERIFY_READ,init->phys_cells, + sizeof(int)*init->numcells); + if (error) return error; + error = verify_area(VERIFY_WRITE, + init->ringbuffer, + init->ringbuf_size * sizeof(int)); + if (error) return error; + error = verify_area(VERIFY_WRITE, + (char *)APLIB_PAGE_BASE, + APLIB_PAGE_LEN); + if (error) return error; + + if (!MPP_IS_PAR_TASK(current->taskid)) + return -EINVAL; + + if (current->aplib) + return -EINVAL; + + aplib = current->aplib = (struct aplib_struct *)APLIB_PAGE_BASE; + + /* lock the aplib structure in memory */ + old_uid = current->euid; + current->euid = 0; + memset(aplib,0,APLIB_PAGE_LEN); + error = sys_mlock(aplib,APLIB_PAGE_LEN); + current->euid = old_uid; + if (error) { + printk("mlock1 failed\n"); + return error; + } + + /* lock the ringbuffer in memory */ + old_uid = current->euid; + current->euid = 0; + memset(init->ringbuffer,0,init->ringbuf_size*4); + error = sys_mlock(init->ringbuffer,init->ringbuf_size*4); + current->euid = old_uid; + if (error) { + printk("mlock2 failed\n"); + return error; + } + + aplib->ringbuf = init->ringbuffer; + aplib->ringbuf_size = init->ringbuf_size; + aplib->numcells = init->numcells; + aplib->cid = init->cid; + aplib->tid = current->taskid; + aplib->numcells_x = init->numcells_x; + aplib->numcells_y = init->numcells_y; + aplib->cidx = init->cid % init->numcells_x; + aplib->cidy = init->cid / init->numcells_x; + + aplib->physical_cid = (unsigned *)(aplib+1); + aplib->rel_cid = aplib->physical_cid + init->numcells; + + if ((char *)(aplib->rel_cid + init->numcells) > + (char *)(APLIB_PAGE_BASE + APLIB_PAGE_LEN)) { + return -ENOMEM; + } + + memcpy(aplib->physical_cid,init->phys_cells, + sizeof(int)*init->numcells); + + /* initialise the relative cid table */ + for (i=0;inumcells;i++) + aplib->rel_cid[i] = + tnet_rel_cid_table[aplib->physical_cid[i]]; + + return 0; +} + + +/* n == which sync line (ignored) + returns logical or of the stat values across the cells (1 bit resolution) + + This has to be done very carefully as the tasks can startup on the cells + in any order, so we don't know which tasks have started up when this + is called +*/ +static inline int aplib_sync(int n,int stat) +{ + struct aplib_struct *aplib = current->aplib; + static int sync_flags[MPP_NUM_TASKS]; + int i,err; + int tsk = current->taskid; + + stat &= 1; + + if (aplib->numcells < 2) + return stat; + + tsk -= MPP_TASK_BASE; + + if (aplib->cid == 0) { + if ((err=wait_on_int(&sync_flags[tsk], + aplib->numcells-1,5))) + return err; + sync_flags[tsk] = 0; + if (aplib->numcells == _ncel) { + ap_bput(0,0,0,(u_long)&sync_flags[tsk],0); + } else { + for (i=1;inumcells;i++) + ap_put(aplib->physical_cid[i], + 0,0,0,(u_long)&sync_flags[tsk],0); + } + } else { + ap_put(aplib->physical_cid[0], + 0,0,0,(u_long)&sync_flags[tsk],0); + if ((err=wait_on_int(&sync_flags[tsk],1,5))) + return err; + sync_flags[tsk] = 0; + } + + /* I haven't written the xy_ calls yet ... */ + /* aplib_xy_ior(stat,&stat); */ + + return stat; +} + + + +static inline void _putget(unsigned q, + unsigned rcell, + unsigned *src_addr, + unsigned size,unsigned *dest_addr, + unsigned *dest_flag,unsigned *src_flag) +{ + unsigned flags; + volatile unsigned *entry = (volatile unsigned *)q; + + save_flags(flags); cli(); + + *entry = rcell; + *entry = size; + *entry = (unsigned)dest_addr; + *entry = 0; + *entry = (unsigned)dest_flag; + *entry = (unsigned)src_flag; + *entry = (unsigned)src_addr; + *entry = 0; + + restore_flags(flags); +} + + +/* a basic put() operation. Note the avoidance of odd word boundaries + and transfers sizes beyond what the hardware can deal with */ +static inline int aplib_put(struct aplib_putget *put) +{ + int error; + struct aplib_struct *aplib = current->aplib; + + error = verify_area(VERIFY_WRITE,put,sizeof(*put)); + if (error) return error; + + if (put->cid >= aplib->numcells) + return -EINVAL; + + do { + int n; + + if (put->size && (((unsigned)put->src_addr) & 4)) { + n = 1; + } else if (put->size > MAX_PUT_SIZE) { + n = MAX_PUT_SIZE; + } else { + n = put->size; + } + + put->size -= n; + + page_in((char *)put->src_addr,n<<2); + + _putget(MSC_PUT_QUEUE, + aplib->rel_cid[put->cid], + put->src_addr, + n, + put->dest_addr, + put->size?0:put->dest_flag, + put->size?0:put->src_flag); + + put->dest_addr += n; + put->src_addr += n; + } while (put->size); + + if (put->ack) { + aplib->ack_request++; + _putget(MSC_GET_QUEUE, + aplib->rel_cid[put->cid], + 0, 0, 0, + &aplib->ack_flag, 0); + } + + return 0; +} + + +/* a basic get() operation */ +static inline int aplib_get(struct aplib_putget *get) +{ + struct aplib_struct *aplib = current->aplib; + int error = verify_area(VERIFY_WRITE,get,sizeof(*get)); + if (error) return error; + + if (get->cid >= aplib->numcells) + return -EINVAL; + + do { + int n; + + if (get->size && (((unsigned)get->src_addr) & 4)) { + n = 1; + } else if (get->size > MAX_PUT_SIZE) { + n = MAX_PUT_SIZE; + } else { + n = get->size; + } + + get->size -= n; + + page_in((char *)get->dest_addr,n<<2); + + _putget(MSC_GET_QUEUE, + aplib->rel_cid[get->cid], + get->src_addr, + n, + get->dest_addr, + get->size?0:get->dest_flag, + get->size?0:get->src_flag); + + get->dest_addr += n; + get->src_addr += n; + } while (get->size); + + return 0; +} + + +/* we have received a protocol message - now do the get + This function is called from interrupt level with interrupts + disabled + + note that send->size is now in words +*/ +void aplib_bigrecv(unsigned *msgp) +{ + struct aplib_struct *aplib; + struct aplib_send *send = (struct aplib_send *)(msgp+2); + unsigned tid = (msgp[1]&0x3FF); + unsigned cid = (msgp[0]>>22)&0x1FF; + unsigned octx, ctx; + struct task_struct *tsk; + unsigned room; + + tsk = task[tid]; + if (!tsk || !tsk->aplib) + return; + + octx = apmmu_get_context(); + ctx = MPP_TASK_TO_CTX(tid); + if (octx != ctx) + apmmu_set_context(ctx); + aplib = tsk->aplib; + + if (aplib->write_pointer < aplib->read_pointer) + room = aplib->read_pointer - (aplib->write_pointer+1); + else + room = aplib->ringbuf_size - + ((aplib->write_pointer+1)-aplib->read_pointer); + + if (room < (send->size+2)) { + send_sig(SIGLOST,tsk,1); + goto finished; + } + + aplib->ringbuf[aplib->write_pointer++] = send->info1; + aplib->ringbuf[aplib->write_pointer++] = send->info2; + + /* now finally do the get() */ + _putget(MSC_GET_QUEUE, + aplib->rel_cid[cid], + send->src_addr, + send->size, + &aplib->ringbuf[aplib->write_pointer], + &aplib->rbuf_flag2, + send->flag_addr); + + aplib->write_pointer += send->size; + if (aplib->write_pointer >= aplib->ringbuf_size) + aplib->write_pointer -= aplib->ringbuf_size; + +finished: + if (octx != ctx) + apmmu_set_context(octx); +} + + +/* note the 8 byte alignment fix for the MSC bug */ +static inline int aplib_send(struct aplib_send *send) +{ + struct aplib_struct *aplib = current->aplib; + int wordSize; + int byteAlign, byteFix; + u_long src; + u_long info1, info2; + volatile unsigned *q = (volatile unsigned *)MSC_SEND_QUEUE_S; + extern long system_recv_flag; + int error; + unsigned flags, rcell; + unsigned flag_ptr; + + error = verify_area(VERIFY_WRITE,send,sizeof(*send)); + if (error) return error; + + if (send->cid >= aplib->numcells) + return -EINVAL; + + if (send->tag == RBUF_SYSTEM || send->tag == RBUF_BIGSEND) + return -EINVAL; + + error = verify_area(VERIFY_READ,(char *)send->src_addr,send->size); + if (error) return error; + + page_in((char *)send->src_addr,send->size); + + rcell = aplib->rel_cid[send->cid]; + + byteAlign = send->src_addr & 0x3; + byteFix = send->size & 0x3; + + wordSize = (send->size + byteAlign + 3) >> 2; + + src = send->src_addr & ~3; + + /* this handles the MSC alignment bug */ + if (wordSize > 1 && + (src & 4)) { + info1 |= 0x80000000; + src -= 4; + wordSize++; + } + + info1 = (aplib->cid<<22) | (byteFix<<20) | wordSize; + info2 = (send->tag<<28) | (byteAlign<<26) | + (send->type<<10) | aplib->tid; + flag_ptr = (unsigned)&send->flag; + + if (send->size > SMALL_SEND_THRESHOLD) { + send->info1 = info1; + send->info2 = info2; + send->size = wordSize; + send->src_addr = src; + send->flag_addr = (unsigned)&send->flag; + flag_ptr = 0; + + wordSize = sizeof(*send)>>2; + src = (unsigned)send; + + info1 = (aplib->cid<<22) | wordSize; + info2 = (RBUF_BIGSEND<<28) | aplib->tid; + } + + save_flags(flags); cli(); + + *q = rcell; + *q = wordSize; + *q = (u_long)&system_recv_flag; + *q = flag_ptr; + *q = (u_long)src; + *q = 0; + *q = info1; + *q = info2; + + restore_flags(flags); + + return 0; +} + + +static inline int aplib_probe(void) +{ + tnet_check_completion(); + return 0; +} + +static inline int aplib_poll(unsigned counter) +{ + struct aplib_struct *aplib = current->aplib; + + while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) { + tnet_check_completion(); + if (need_resched) break; + if (current->signal & ~current->blocked) break; + } + return 0; +} + +int sys_aplib(unsigned call,int a1,int a2,int a3,int a4) +{ + + if (!current->aplib && call != APLIB_INIT) + return -EINVAL; + + switch (call) { + case APLIB_INIT: + return aplib_init((struct aplib_init *)a1); + + case APLIB_SYNC: + return aplib_sync(a1,a2); + + case APLIB_PUT: + return aplib_put((struct aplib_putget *)a1); + + case APLIB_GET: + return aplib_get((struct aplib_putget *)a1); + + case APLIB_SEND: + return aplib_send((struct aplib_send *)a1); + + case APLIB_PROBE: + return aplib_probe(); + + case APLIB_POLL: + return aplib_poll((unsigned)a1); + } + + return -EINVAL; +} + + diff --git a/arch/sparc/ap1000/apmmu.c b/arch/sparc/ap1000/apmmu.c new file mode 100644 index 000000000000..b0251d908d61 --- /dev/null +++ b/arch/sparc/ap1000/apmmu.c @@ -0,0 +1,1190 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * apmmu.c: mmu routines for the AP1000 + * + * based on srmmu.c + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static unsigned long (*mmu_getpage)(void); +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); +static void (*flush_cache_page_to_uncache)(unsigned long page); +static void (*flush_tlb_page_for_cbit)(unsigned long page); + +extern void mc_tlb_flush_all(void); + + +static struct apmmu_stats { + int invall; + int invpg; + int invrnge; + int invmm; +} module_stats; + +static char *apmmu_name; + +static ctxd_t *apmmu_ctx_table_phys; +static ctxd_t *apmmu_context_table; + +static unsigned long ap_mem_size; +static unsigned long mempool; + + +static inline unsigned long apmmu_v2p(unsigned long vaddr) +{ + if (KERNBASE <= vaddr && + (KERNBASE + ap_mem_size > vaddr)) { + return (vaddr - KERNBASE); + } + return 0xffffffffUL; +} + +static inline unsigned long apmmu_p2v(unsigned long paddr) +{ + if (ap_mem_size > paddr) + return (paddr + KERNBASE); + return 0xffffffffUL; +} + +/* 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. + */ +static inline unsigned long apmmu_swap(unsigned long *addr, unsigned long value) +{ + /* the AP1000 has its memory on bus 8, not 0 like suns do */ + if ((value&0xF0000000) == 0) + value |= MEM_BUS_SPACE<<28; + __asm__ __volatile__("swap [%2], %0\n\t" : + "=&r" (value) : + "0" (value), "r" (addr)); + return value; +} + +/* Functions really use this, not apmmu_swap directly. */ +#define apmmu_set_entry(ptr, newentry) \ + apmmu_swap((unsigned long *) (ptr), (newentry)) + + +/* The very generic APMMU page table operations. */ +static unsigned int apmmu_pmd_align(unsigned int addr) { return APMMU_PMD_ALIGN(addr); } +static unsigned int apmmu_pgdir_align(unsigned int addr) { return APMMU_PGDIR_ALIGN(addr); } + +static unsigned long apmmu_vmalloc_start(void) +{ + return APMMU_VMALLOC_START; +} + +static inline int apmmu_device_memory(unsigned long x) +{ + return ((x & 0xF0000000) != 0); +} + +static unsigned long apmmu_pgd_page(pgd_t pgd) +{ return apmmu_device_memory(pgd_val(pgd))?~0:apmmu_p2v((pgd_val(pgd) & APMMU_PTD_PMASK) << 4); } + +static unsigned long apmmu_pmd_page(pmd_t pmd) +{ return apmmu_device_memory(pmd_val(pmd))?~0:apmmu_p2v((pmd_val(pmd) & APMMU_PTD_PMASK) << 4); } + +static unsigned long apmmu_pte_page(pte_t pte) +{ return apmmu_device_memory(pte_val(pte))?~0:apmmu_p2v((pte_val(pte) & APMMU_PTE_PMASK) << 4); } + +static int apmmu_pte_none(pte_t pte) +{ return !(pte_val(pte) & 0xFFFFFFF); } + +static int apmmu_pte_present(pte_t pte) +{ return ((pte_val(pte) & APMMU_ET_MASK) == APMMU_ET_PTE); } + +static void apmmu_pte_clear(pte_t *ptep) { set_pte(ptep, __pte(0)); } + +static int apmmu_pmd_none(pmd_t pmd) +{ return !(pmd_val(pmd) & 0xFFFFFFF); } + +static int apmmu_pmd_bad(pmd_t pmd) +{ return (pmd_val(pmd) & APMMU_ET_MASK) != APMMU_ET_PTD; } + +static int apmmu_pmd_present(pmd_t pmd) +{ return ((pmd_val(pmd) & APMMU_ET_MASK) == APMMU_ET_PTD); } + +static void apmmu_pmd_clear(pmd_t *pmdp) { set_pte((pte_t *)pmdp, __pte(0)); } + +static int apmmu_pgd_none(pgd_t pgd) +{ return !(pgd_val(pgd) & 0xFFFFFFF); } + +static int apmmu_pgd_bad(pgd_t pgd) +{ return (pgd_val(pgd) & APMMU_ET_MASK) != APMMU_ET_PTD; } + +static int apmmu_pgd_present(pgd_t pgd) +{ return ((pgd_val(pgd) & APMMU_ET_MASK) == APMMU_ET_PTD); } + +static void apmmu_pgd_clear(pgd_t * pgdp) { set_pte((pte_t *)pgdp, __pte(0)); } + +static int apmmu_pte_write(pte_t pte) { return pte_val(pte) & APMMU_WRITE; } +static int apmmu_pte_dirty(pte_t pte) { return pte_val(pte) & APMMU_DIRTY; } +static int apmmu_pte_young(pte_t pte) { return pte_val(pte) & APMMU_REF; } + +static pte_t apmmu_pte_wrprotect(pte_t pte) { return __pte(pte_val(pte) & ~APMMU_WRITE);} +static pte_t apmmu_pte_mkclean(pte_t pte) { return __pte(pte_val(pte) & ~APMMU_DIRTY);} +static pte_t apmmu_pte_mkold(pte_t pte) { return __pte(pte_val(pte) & ~APMMU_REF);} +static pte_t apmmu_pte_mkwrite(pte_t pte) { return __pte(pte_val(pte) | APMMU_WRITE);} +static pte_t apmmu_pte_mkdirty(pte_t pte) { return __pte(pte_val(pte) | APMMU_DIRTY);} +static pte_t apmmu_pte_mkyoung(pte_t pte) { return __pte(pte_val(pte) | APMMU_REF);} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +static pte_t apmmu_mk_pte(unsigned long page, pgprot_t pgprot) +{ return __pte(((apmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); } + +static pte_t apmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot) +{ return __pte(((page) >> 4) | pgprot_val(pgprot)); } + +static pte_t apmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) +{ + return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); +} + +static void apmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) +{ + set_pte((pte_t *)ctxp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pgdp) >> 4))); +} + +static void apmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) +{ + set_pte((pte_t *)pgdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pmdp) >> 4))); +} + +static void apmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) +{ + set_pte((pte_t *)pmdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) ptep) >> 4))); +} + +static pte_t apmmu_pte_modify(pte_t pte, pgprot_t newprot) +{ + return __pte((pte_val(pte) & APMMU_CHG_MASK) | pgprot_val(newprot)); +} + +/* to find an entry in a top-level page table... */ +static pgd_t *apmmu_pgd_offset(struct mm_struct * mm, unsigned long address) +{ + return mm->pgd + ((address >> APMMU_PGDIR_SHIFT) & (APMMU_PTRS_PER_PGD - 1)); +} + +/* Find an entry in the second-level page table.. */ +static pmd_t *apmmu_pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) apmmu_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1)); +} + +/* Find an entry in the third-level page table.. */ +static pte_t *apmmu_pte_offset(pmd_t * dir, unsigned long address) +{ + return (pte_t *) apmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1)); +} + +/* This must update the context table entry for this process. */ +static void apmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) +{ + if(tsk->mm->context != NO_CONTEXT) { + flush_cache_mm(current->mm); + ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp); + flush_tlb_mm(current->mm); + } +} + + +/* Accessing the MMU control register. */ +static inline unsigned int apmmu_get_mmureg(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %1, %0\n\t" : + "=r" (retval) : + "i" (ASI_M_MMUREGS)); + return retval; +} + +static inline void apmmu_set_mmureg(unsigned long regval) +{ + __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : : + "r" (regval), "i" (ASI_M_MMUREGS) : "memory"); + +} + +static inline void apmmu_set_ctable_ptr(unsigned long paddr) +{ + paddr = ((paddr >> 4) & APMMU_CTX_PMASK); + paddr |= (MEM_BUS_SPACE<<28); + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (paddr), "r" (APMMU_CTXTBL_PTR), + "i" (ASI_M_MMUREGS) : + "memory"); +} + +static inline void apmmu_flush_whole_tlb(void) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : + "r" (0x400), /* Flush entire TLB!! */ + "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +/* These flush types are not available on all chips... */ +static inline void apmmu_flush_tlb_ctx(void) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : + "r" (0x300), /* Flush TLB ctx.. */ + "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static inline void apmmu_flush_tlb_region(unsigned long addr) +{ + addr &= APMMU_PGDIR_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : + "r" (addr | 0x200), /* Flush TLB region.. */ + "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + + +static inline void apmmu_flush_tlb_segment(unsigned long addr) +{ + addr &= APMMU_PMD_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : + "r" (addr | 0x100), /* Flush TLB segment.. */ + "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static inline void apmmu_flush_tlb_page(unsigned long page) +{ + page &= PAGE_MASK; + __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : + "r" (page), /* Flush TLB page.. */ + "i" (ASI_M_FLUSH_PROBE) : "memory"); + +} + +static inline unsigned long apmmu_hwprobe(unsigned long vaddr) +{ + unsigned long retval; + + vaddr &= PAGE_MASK; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); + + return retval; +} + + + +static inline void apmmu_uncache_page(unsigned long addr) +{ + pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr); + pmd_t *pmdp; + pte_t *ptep; + + if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { + ptep = (pte_t *) pgdp; + } else { + pmdp = apmmu_pmd_offset(pgdp, addr); + if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { + ptep = (pte_t *) pmdp; + } else { + ptep = apmmu_pte_offset(pmdp, addr); + } + } + + flush_cache_page_to_uncache(addr); + set_pte(ptep, __pte((pte_val(*ptep) & ~APMMU_CACHE))); + flush_tlb_page_for_cbit(addr); +} + +static inline void apmmu_recache_page(unsigned long addr) +{ + pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr); + pmd_t *pmdp; + pte_t *ptep; + + if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { + ptep = (pte_t *) pgdp; + } else { + pmdp = apmmu_pmd_offset(pgdp, addr); + if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) { + ptep = (pte_t *) pmdp; + } else { + ptep = apmmu_pte_offset(pmdp, addr); + } + } + set_pte(ptep, __pte((pte_val(*ptep) | APMMU_CACHE))); + flush_tlb_page_for_cbit(addr); +} + +static unsigned long apmmu_getpage(void) +{ + unsigned long page = get_free_page(GFP_KERNEL); + + return page; +} + +static inline void apmmu_putpage(unsigned long page) +{ + free_page(page); +} + +/* The easy versions. */ +#define NEW_PGD() (pgd_t *) mmu_getpage() +#define NEW_PMD() (pmd_t *) mmu_getpage() +#define NEW_PTE() (pte_t *) mmu_getpage() +#define FREE_PGD(chunk) apmmu_putpage((unsigned long)(chunk)) +#define FREE_PMD(chunk) apmmu_putpage((unsigned long)(chunk)) +#define FREE_PTE(chunk) apmmu_putpage((unsigned long)(chunk)) + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any, and marks the page tables reserved. + */ +static void apmmu_pte_free_kernel(pte_t *pte) +{ + FREE_PTE(pte); +} + +static pte_t *apmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1); + if(apmmu_pmd_none(*pmd)) { + pte_t *page = NEW_PTE(); + if(apmmu_pmd_none(*pmd)) { + if(page) { + pmd_set(pmd, page); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + FREE_PTE(page); + } + if(apmmu_pmd_bad(*pmd)) { + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return (pte_t *) apmmu_pmd_page(*pmd) + address; +} + +static void apmmu_pmd_free_kernel(pmd_t *pmd) +{ + FREE_PMD(pmd); +} + +static pmd_t *apmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) +{ + address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1); + if(apmmu_pgd_none(*pgd)) { + pmd_t *page; + page = NEW_PMD(); + if(apmmu_pgd_none(*pgd)) { + if(page) { + pgd_set(pgd, page); + return page + address; + } + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + return NULL; + } + FREE_PMD(page); + } + if(apmmu_pgd_bad(*pgd)) { + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + return NULL; + } + return (pmd_t *) pgd_page(*pgd) + address; +} + +static void apmmu_pte_free(pte_t *pte) +{ + FREE_PTE(pte); +} + +static pte_t *apmmu_pte_alloc(pmd_t * pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1); + if(apmmu_pmd_none(*pmd)) { + pte_t *page = NEW_PTE(); + if(apmmu_pmd_none(*pmd)) { + if(page) { + pmd_set(pmd, page); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + FREE_PTE(page); + } + if(apmmu_pmd_bad(*pmd)) { + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return ((pte_t *) apmmu_pmd_page(*pmd)) + address; +} + +/* Real three-level page tables on APMMU. */ +static void apmmu_pmd_free(pmd_t * pmd) +{ + FREE_PMD(pmd); +} + +static pmd_t *apmmu_pmd_alloc(pgd_t * pgd, unsigned long address) +{ + address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1); + if(apmmu_pgd_none(*pgd)) { + pmd_t *page = NEW_PMD(); + if(apmmu_pgd_none(*pgd)) { + if(page) { + pgd_set(pgd, page); + return page + address; + } + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + return NULL; + } + FREE_PMD(page); + } + if(apmmu_pgd_bad(*pgd)) { + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + return NULL; + } + return (pmd_t *) apmmu_pgd_page(*pgd) + address; +} + +static void apmmu_pgd_free(pgd_t *pgd) +{ + FREE_PGD(pgd); +} + +static pgd_t *apmmu_pgd_alloc(void) +{ + return NEW_PGD(); +} + +static void apmmu_pgd_flush(pgd_t *pgdp) +{ +} + +static void apmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval) +{ + apmmu_set_entry(ptep, pte_val(pteval)); +} + +static void apmmu_quick_kernel_fault(unsigned long address) +{ + printk("Kernel faults at addr=0x%08lx\n", address); + printk("PTE=%08lx\n", apmmu_hwprobe((address & PAGE_MASK))); + die_if_kernel("APMMU bolixed...", current->tss.kregs); +} + +static inline void alloc_context(struct task_struct *tsk) +{ + struct mm_struct *mm = tsk->mm; + struct ctx_list *ctxp; + + if (tsk->taskid >= MPP_TASK_BASE) { + mm->context = MPP_CONTEXT_BASE + (tsk->taskid - MPP_TASK_BASE); + return; + } + + ctxp = ctx_free.next; + if(ctxp != &ctx_free) { + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + mm->context = ctxp->ctx_number; + ctxp->ctx_mm = mm; + return; + } + ctxp = ctx_used.next; + if(ctxp->ctx_mm == current->mm) + ctxp = ctxp->next; + if(ctxp == &ctx_used) + panic("out of mmu contexts"); + flush_cache_mm(ctxp->ctx_mm); + flush_tlb_mm(ctxp->ctx_mm); + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + ctxp->ctx_mm->context = NO_CONTEXT; + ctxp->ctx_mm = mm; + mm->context = ctxp->ctx_number; +} + +static inline void free_context(int context) +{ + struct ctx_list *ctx_old; + + if (context >= MPP_CONTEXT_BASE) + return; /* nothing to do! */ + + ctx_old = ctx_list_pool + context; + remove_from_ctx_list(ctx_old); + add_to_free_ctxlist(ctx_old); +} + + +static void apmmu_switch_to_context(struct task_struct *tsk) +{ + if(tsk->mm->context == NO_CONTEXT) { + alloc_context(tsk); + flush_cache_mm(current->mm); + ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd); + flush_tlb_mm(current->mm); + } + apmmu_set_context(tsk->mm->context); +} + +static char *apmmu_lockarea(char *vaddr, unsigned long len) +{ + return vaddr; +} + +static void apmmu_unlockarea(char *vaddr, unsigned long len) +{ +} + +struct task_struct *apmmu_alloc_task_struct(void) +{ + return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL); +} + +static unsigned long apmmu_alloc_kernel_stack(struct task_struct *tsk) +{ + unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0); + + if(!kstk) + kstk = (unsigned long) vmalloc(PAGE_SIZE << 1); + + return kstk; +} + +static void apmmu_free_task_struct(struct task_struct *tsk) +{ + kfree(tsk); +} + +static void apmmu_free_kernel_stack(unsigned long stack) +{ + if(stack < VMALLOC_START) + free_pages(stack, 1); + else + vfree((char *)stack); +} + +static void apmmu_null_func(void) +{ +} + +static inline void mc_tlb_flush_all(void) +{ + unsigned long long *tlb4k; + int i; + + tlb4k = (unsigned long long *)MC_MMU_TLB4K; + for (i = MC_MMU_TLB4K_SIZE/4; i > 0; --i) { + tlb4k[0] = 0; + tlb4k[1] = 0; + tlb4k[2] = 0; + tlb4k[3] = 0; + tlb4k += 4; + } +} + +static inline void mc_tlb_flush_page(unsigned vaddr,int ctx) +{ + if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) { + *(((unsigned long long *)MC_MMU_TLB4K) + ((vaddr>>12)&0xFF)) = 0; + } +} + +static inline void mc_tlb_flush_ctx(int ctx) +{ + unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K; + if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) { + int i; + for (i=0; i> 5) & 0xFFF) == ctx) tlb4k[i] = 0; + } +} + +static inline void mc_tlb_flush_region(unsigned start,int ctx) +{ + mc_tlb_flush_ctx(ctx); +} + +static inline void mc_tlb_flush_segment(unsigned start,int ctx) +{ + mc_tlb_flush_ctx(ctx); +} + +static void viking_flush_tlb_all(void) +{ + module_stats.invall++; + flush_user_windows(); + apmmu_flush_whole_tlb(); + mc_tlb_flush_all(); +} + +static void viking_flush_tlb_mm(struct mm_struct *mm) +{ + int octx; + + module_stats.invmm++; + + if(mm->context != NO_CONTEXT) { + flush_user_windows(); + octx = apmmu_get_context(); + if (octx != mm->context) + apmmu_set_context(mm->context); + apmmu_flush_tlb_ctx(); + mc_tlb_flush_ctx(mm->context); + if (octx != mm->context) + apmmu_set_context(octx); + } +} + +static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + int octx; + + module_stats.invrnge++; + + if(mm->context != NO_CONTEXT) { + flush_user_windows(); + octx = apmmu_get_context(); + if (octx != mm->context) + apmmu_set_context(mm->context); + if((end - start) < APMMU_PMD_SIZE) { + start &= PAGE_MASK; + while(start < end) { + apmmu_flush_tlb_page(start); + mc_tlb_flush_page(start,mm->context); + start += PAGE_SIZE; + } + } else if((end - start) < APMMU_PGDIR_SIZE) { + start &= APMMU_PMD_MASK; + while(start < end) { + apmmu_flush_tlb_segment(start); + mc_tlb_flush_segment(start,mm->context); + start += APMMU_PMD_SIZE; + } + } else { + start &= APMMU_PGDIR_MASK; + while(start < end) { + apmmu_flush_tlb_region(start); + mc_tlb_flush_region(start,mm->context); + start += APMMU_PGDIR_SIZE; + } + } + if (octx != mm->context) + apmmu_set_context(octx); + } +} + +static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + int octx; + struct mm_struct *mm = vma->vm_mm; + + module_stats.invpg++; + if(mm->context != NO_CONTEXT) { + flush_user_windows(); + octx = apmmu_get_context(); + if (octx != mm->context) + apmmu_set_context(mm->context); + apmmu_flush_tlb_page(page); + mc_tlb_flush_page(page,mm->context); + if (octx != mm->context) + apmmu_set_context(octx); + } +} + +static void viking_flush_tlb_page_for_cbit(unsigned long page) +{ + apmmu_flush_tlb_page(page); + mc_tlb_flush_page(page,apmmu_get_context()); +} + +/* Some dirty hacks to abstract away the painful boot up init. */ +static inline unsigned long apmmu_early_paddr(unsigned long vaddr) +{ + return (vaddr - KERNBASE); +} + +static inline void apmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp) +{ + set_pte((pte_t *)pgdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) pmdp) >> 4)))); +} + +static inline void apmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep) +{ + set_pte((pte_t *)pmdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) ptep) >> 4)))); +} + +static inline unsigned long apmmu_early_pgd_page(pgd_t pgd) +{ + return ((pgd_val(pgd) & APMMU_PTD_PMASK) << 4) + KERNBASE; +} + +static inline unsigned long apmmu_early_pmd_page(pmd_t pmd) +{ + return ((pmd_val(pmd) & APMMU_PTD_PMASK) << 4) + KERNBASE; +} + +static inline pmd_t *apmmu_early_pmd_offset(pgd_t *dir, unsigned long address) +{ + return (pmd_t *) apmmu_early_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1)); +} + +static inline pte_t *apmmu_early_pte_offset(pmd_t *dir, unsigned long address) +{ + return (pte_t *) apmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1)); +} + +__initfunc(static inline void apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + while(start < end) { + pgdp = apmmu_pgd_offset(init_task.mm, start); + if(apmmu_pgd_none(*pgdp)) { + pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); + apmmu_early_pgd_set(pgdp, pmdp); + } + pmdp = apmmu_early_pmd_offset(pgdp, start); + if(apmmu_pmd_none(*pmdp)) { + ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE); + apmmu_early_pmd_set(pmdp, ptep); + } + start = (start + APMMU_PMD_SIZE) & APMMU_PMD_MASK; + } +} + + +__initfunc(static void make_page(unsigned virt_page, unsigned phys_page, unsigned prot)) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + unsigned start = virt_page<<12; + + pgdp = apmmu_pgd_offset(init_task.mm, start); + if(apmmu_pgd_none(*pgdp)) { + pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE); + apmmu_early_pgd_set(pgdp, pmdp); + } + pmdp = apmmu_early_pmd_offset(pgdp, start); + if(apmmu_pmd_none(*pmdp)) { + ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE); + apmmu_early_pmd_set(pmdp, ptep); + } + ptep = apmmu_early_pte_offset(pmdp, start); + *ptep = __pte((phys_page<<8) | prot); +} + + +__initfunc(static void make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot)) +{ + pgd_t *pgdp; + unsigned start = virt_page<<12; + + pgdp = apmmu_pgd_offset(init_task.mm, start); + *pgdp = __pgd((phys_page<<8) | prot); +} + + +__initfunc(static void ap_setup_mappings(void)) +{ + unsigned Srwe = APMMU_PRIV | APMMU_VALID; + unsigned SrweUr = 0x14 | APMMU_VALID; /* weird! */ + + /* LBus */ + make_large_page(0xfb000,0x9fb000,Srwe); + make_large_page(0xff000,0x9ff000,SrweUr); + make_large_page(0xfc000,0x911000,Srwe); + + /* MC Register */ + make_page(0xfa000,0xb00000,SrweUr); + make_page(0xfa001,0xb00001,Srwe); + make_page(0xfa002,0xb00002,Srwe); + make_page(0xfa003,0xb00003,Srwe); + make_page(0xfa004,0xb00004,Srwe); + make_page(0xfa005,0xb00005,Srwe); + make_page(0xfa006,0xb00006,Srwe); + make_page(0xfa007,0xb00007,Srwe); + + /* MSC+ Register */ + make_page(0xfa008,0xc00000,SrweUr); + make_page(0xfa009,0xc00001,Srwe); + make_page(0xfa00a,0xc00002,Srwe); + make_page(0xfa00b,0xc00003,Srwe); + make_page(0xfa00c,0xc00004,Srwe); + make_page(0xfa00d,0xc00005,Srwe); /* RBMPR 0 */ + make_page(0xfa00e,0xc00006,Srwe); /* RBMPR 1 */ + make_page(0xfa00f,0xc00007,Srwe); /* RBMPR 2 */ + + /* user queues */ + make_page(MSC_PUT_QUEUE>>PAGE_SHIFT, 0xa00000,Srwe); + make_page(MSC_GET_QUEUE>>PAGE_SHIFT, 0xa00001,Srwe); + make_page(MSC_SEND_QUEUE>>PAGE_SHIFT, 0xa00040,Srwe); + make_page(MSC_XY_QUEUE>>PAGE_SHIFT, 0xa00640,Srwe); + make_page(MSC_X_QUEUE>>PAGE_SHIFT, 0xa00240,Srwe); + make_page(MSC_Y_QUEUE>>PAGE_SHIFT, 0xa00440,Srwe); + make_page(MSC_XYG_QUEUE>>PAGE_SHIFT, 0xa00600,Srwe); + make_page(MSC_XG_QUEUE>>PAGE_SHIFT, 0xa00200,Srwe); + make_page(MSC_YG_QUEUE>>PAGE_SHIFT, 0xa00400,Srwe); + make_page(MSC_CSI_QUEUE>>PAGE_SHIFT, 0xa02004,Srwe); + make_page(MSC_FOP_QUEUE>>PAGE_SHIFT, 0xa02005,Srwe); + + /* system queues */ + make_page(MSC_PUT_QUEUE_S>>PAGE_SHIFT, 0xa02000,Srwe); /* system put */ + make_page(MSC_CPUT_QUEUE_S>>PAGE_SHIFT, 0xa02020,Srwe); /* system creg put */ + make_page(MSC_GET_QUEUE_S>>PAGE_SHIFT, 0xa02001,Srwe); /* system get */ + make_page(MSC_CGET_QUEUE_S>>PAGE_SHIFT, 0xa02021,Srwe); /* system creg get */ + make_page(MSC_SEND_QUEUE_S>>PAGE_SHIFT, 0xa02040,Srwe); /* system send */ + make_page(MSC_BSEND_QUEUE_S>>PAGE_SHIFT,0xa02640,Srwe); /* system send broad */ + make_page(MSC_XYG_QUEUE_S>>PAGE_SHIFT, 0xa02600,Srwe); /* system put broad */ + make_page(MSC_CXYG_QUEUE_S>>PAGE_SHIFT, 0xa02620,Srwe); /* system put broad */ + + /* Direct queue access entries for refilling the MSC send queue */ + make_page(MSC_SYSTEM_DIRECT>>PAGE_SHIFT, 0xa08000,Srwe); + make_page(MSC_USER_DIRECT>>PAGE_SHIFT, 0xa08001,Srwe); + make_page(MSC_REMOTE_DIRECT>>PAGE_SHIFT, 0xa08002,Srwe); + make_page(MSC_REPLY_DIRECT>>PAGE_SHIFT, 0xa08003,Srwe); + make_page(MSC_REMREPLY_DIRECT>>PAGE_SHIFT, 0xa08004,Srwe); + + /* As above with end-bit set */ + make_page(MSC_SYSTEM_DIRECT_END>>PAGE_SHIFT, 0xa0c000,Srwe); + make_page(MSC_USER_DIRECT_END>>PAGE_SHIFT, 0xa0c001,Srwe); + make_page(MSC_REMOTE_DIRECT_END>>PAGE_SHIFT, 0xa0c002,Srwe); + make_page(MSC_REPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c003,Srwe); + make_page(MSC_REMREPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c004,Srwe); +} + +__initfunc(static void map_kernel(void)) +{ + int phys; + + /* the AP+ only ever has one bank of memory starting at address 0 */ + ap_mem_size = sp_banks[0].num_bytes; + for (phys=0; phys < sp_banks[0].num_bytes; phys += APMMU_PGDIR_SIZE) + make_large_page((KERNBASE+phys)>>12, + (phys>>12), + APMMU_CACHE|APMMU_PRIV|APMMU_VALID); + init_task.mm->mmap->vm_start = page_offset = KERNBASE; + stack_top = page_offset - PAGE_SIZE; +} + +extern unsigned long free_area_init(unsigned long, unsigned long); +extern unsigned long sparc_context_init(unsigned long, int); + +extern int physmem_mapped_contig; +extern int linux_num_cpus; + +void (*poke_apmmu)(void); + +__initfunc(unsigned long apmmu_paging_init(unsigned long start_mem, unsigned long end_mem)) +{ + int i; + + physmem_mapped_contig = 1; /* for init.c:taint_real_pages() */ + + num_contexts = AP_NUM_CONTEXTS; + mempool = PAGE_ALIGN(start_mem); + memset(swapper_pg_dir, 0, PAGE_SIZE); + + apmmu_allocate_ptable_skeleton(KERNBASE, end_mem); + mempool = PAGE_ALIGN(mempool); + map_kernel(); + ap_setup_mappings(); + + /* the MSC wants this aligned on a 16k boundary */ + apmmu_context_table = + sparc_init_alloc(&mempool, + num_contexts*sizeof(ctxd_t)<0x4000? + 0x4000: + num_contexts*sizeof(ctxd_t)); + apmmu_ctx_table_phys = (ctxd_t *) apmmu_v2p((unsigned long) apmmu_context_table); + for(i = 0; i < num_contexts; i++) + ctxd_set(&apmmu_context_table[i], swapper_pg_dir); + + start_mem = PAGE_ALIGN(mempool); + + flush_cache_all(); + apmmu_set_ctable_ptr((unsigned long) apmmu_ctx_table_phys); + flush_tlb_all(); + poke_apmmu(); + + /* on the AP we don't put the top few contexts into the free + context list as these are reserved for parallel tasks */ + start_mem = sparc_context_init(start_mem, MPP_CONTEXT_BASE); + start_mem = free_area_init(start_mem, end_mem); + + return PAGE_ALIGN(start_mem); +} + +static char apmmuinfo[512]; + +static char *apmmu_mmu_info(void) +{ + sprintf(apmmuinfo, "MMU type\t: %s\n" + "invall\t\t: %d\n" + "invmm\t\t: %d\n" + "invrnge\t\t: %d\n" + "invpg\t\t: %d\n" + "contexts\t: %d\n" + , apmmu_name, + module_stats.invall, + module_stats.invmm, + module_stats.invrnge, + module_stats.invpg, + num_contexts + ); + return apmmuinfo; +} + +static void apmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) +{ +} + +static void apmmu_exit_hook(void) +{ + struct mm_struct *mm = current->mm; + + if(mm->context != NO_CONTEXT && mm->count == 1) { + ctxd_set(&apmmu_context_table[mm->context], swapper_pg_dir); + viking_flush_tlb_mm(mm); + free_context(mm->context); + mm->context = NO_CONTEXT; + } +} + +static void apmmu_flush_hook(void) +{ + if(current->tss.flags & SPARC_FLAG_KTHREAD) { + alloc_context(current); + ctxd_set(&apmmu_context_table[current->mm->context], current->mm->pgd); + viking_flush_tlb_mm(current->mm); + apmmu_set_context(current->mm->context); + } +} + +__initfunc(static void poke_viking(void)) +{ + unsigned long mreg = apmmu_get_mmureg(); + + mreg |= VIKING_SPENABLE; + mreg |= (VIKING_ICENABLE | VIKING_DCENABLE); + mreg &= ~VIKING_ACENABLE; + mreg &= ~VIKING_SBENABLE; + mreg |= VIKING_TCENABLE; + apmmu_set_mmureg(mreg); +} + +__initfunc(static void init_viking(void)) +{ + apmmu_name = "TI Viking/AP1000"; + + flush_cache_page_to_uncache = apmmu_null_func; + flush_page_for_dma = apmmu_null_func; + + flush_cache_all = apmmu_null_func; + flush_cache_mm = apmmu_null_func; + flush_cache_page = apmmu_null_func; + flush_cache_range = apmmu_null_func; + + flush_tlb_all = viking_flush_tlb_all; + flush_tlb_mm = viking_flush_tlb_mm; + flush_tlb_page = viking_flush_tlb_page; + flush_tlb_range = viking_flush_tlb_range; + + flush_page_to_ram = apmmu_null_func; + flush_sig_insns = apmmu_null_func; + flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit; + + poke_apmmu = poke_viking; +} + + +extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, + tsetup_mmu_patchme, rtrap_mmu_patchme; + +extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk, + tsetup_srmmu_stackchk, srmmu_rett_stackchk; + +extern unsigned long srmmu_fault; + +#define PATCH_BRANCH(insn, dest) do { \ + iaddr = &(insn); \ + daddr = &(dest); \ + *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ + } while(0); + +__initfunc(static void patch_window_trap_handlers(void)) +{ + unsigned long *iaddr, *daddr; + + PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk); + PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk); + PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk); + PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk); + PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault); + PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault); + PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault); +} + +/* Load up routines and constants for sun4m mmu */ +__initfunc(void ld_mmu_apmmu(void)) +{ + /* First the constants */ + pmd_shift = APMMU_PMD_SHIFT; + pmd_size = APMMU_PMD_SIZE; + pmd_mask = APMMU_PMD_MASK; + pgdir_shift = APMMU_PGDIR_SHIFT; + pgdir_size = APMMU_PGDIR_SIZE; + pgdir_mask = APMMU_PGDIR_MASK; + + ptrs_per_pte = APMMU_PTRS_PER_PTE; + ptrs_per_pmd = APMMU_PTRS_PER_PMD; + ptrs_per_pgd = APMMU_PTRS_PER_PGD; + + page_none = APMMU_PAGE_NONE; + page_shared = APMMU_PAGE_SHARED; + page_copy = APMMU_PAGE_COPY; + page_readonly = APMMU_PAGE_RDONLY; + page_kernel = APMMU_PAGE_KERNEL; + pg_iobits = APMMU_VALID | APMMU_WRITE | APMMU_REF; + + /* Functions */ + mmu_getpage = apmmu_getpage; + set_pte = apmmu_set_pte_cacheable; + switch_to_context = apmmu_switch_to_context; + pmd_align = apmmu_pmd_align; + pgdir_align = apmmu_pgdir_align; + vmalloc_start = apmmu_vmalloc_start; + + pte_page = apmmu_pte_page; + pmd_page = apmmu_pmd_page; + pgd_page = apmmu_pgd_page; + + sparc_update_rootmmu_dir = apmmu_update_rootmmu_dir; + + pte_none = apmmu_pte_none; + pte_present = apmmu_pte_present; + pte_clear = apmmu_pte_clear; + + pmd_none = apmmu_pmd_none; + pmd_bad = apmmu_pmd_bad; + pmd_present = apmmu_pmd_present; + pmd_clear = apmmu_pmd_clear; + + pgd_none = apmmu_pgd_none; + pgd_bad = apmmu_pgd_bad; + pgd_present = apmmu_pgd_present; + pgd_clear = apmmu_pgd_clear; + + mk_pte = apmmu_mk_pte; + mk_pte_phys = apmmu_mk_pte_phys; + pgd_set = apmmu_pgd_set; + mk_pte_io = apmmu_mk_pte_io; + pte_modify = apmmu_pte_modify; + pgd_offset = apmmu_pgd_offset; + pmd_offset = apmmu_pmd_offset; + pte_offset = apmmu_pte_offset; + pte_free_kernel = apmmu_pte_free_kernel; + pmd_free_kernel = apmmu_pmd_free_kernel; + pte_alloc_kernel = apmmu_pte_alloc_kernel; + pmd_alloc_kernel = apmmu_pmd_alloc_kernel; + pte_free = apmmu_pte_free; + pte_alloc = apmmu_pte_alloc; + pmd_free = apmmu_pmd_free; + pmd_alloc = apmmu_pmd_alloc; + pgd_free = apmmu_pgd_free; + pgd_alloc = apmmu_pgd_alloc; + pgd_flush = apmmu_pgd_flush; + + pte_write = apmmu_pte_write; + pte_dirty = apmmu_pte_dirty; + pte_young = apmmu_pte_young; + pte_wrprotect = apmmu_pte_wrprotect; + pte_mkclean = apmmu_pte_mkclean; + pte_mkold = apmmu_pte_mkold; + pte_mkwrite = apmmu_pte_mkwrite; + pte_mkdirty = apmmu_pte_mkdirty; + pte_mkyoung = apmmu_pte_mkyoung; + update_mmu_cache = apmmu_update_mmu_cache; + mmu_exit_hook = apmmu_exit_hook; + mmu_flush_hook = apmmu_flush_hook; + mmu_lockarea = apmmu_lockarea; + mmu_unlockarea = apmmu_unlockarea; + + mmu_get_scsi_one = NULL; + mmu_get_scsi_sgl = NULL; + mmu_release_scsi_one = NULL; + mmu_release_scsi_sgl = NULL; + + mmu_info = apmmu_mmu_info; + mmu_v2p = apmmu_v2p; + mmu_p2v = apmmu_p2v; + + /* Task struct and kernel stack allocating/freeing. */ + alloc_kernel_stack = apmmu_alloc_kernel_stack; + alloc_task_struct = apmmu_alloc_task_struct; + free_kernel_stack = apmmu_free_kernel_stack; + free_task_struct = apmmu_free_task_struct; + + quick_kernel_fault = apmmu_quick_kernel_fault; + + ctxd_set = apmmu_ctxd_set; + pmd_set = apmmu_pmd_set; + + init_viking(); + patch_window_trap_handlers(); +} + + diff --git a/arch/sparc/ap1000/approm.c b/arch/sparc/ap1000/approm.c new file mode 100644 index 000000000000..4fe956bcbace --- /dev/null +++ b/arch/sparc/ap1000/approm.c @@ -0,0 +1,148 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * fake a really simple Sun prom for the AP+ + * + */ + +#include +#include +#include +#include +#include +#include + +static struct linux_romvec ap_romvec; +static struct idprom ap_idprom; + +struct property { + char *name; + char *value; + int length; +}; + +struct node { + int level; + struct property *properties; +}; + +struct property null_properties = { NULL, NULL, -1 }; + +struct property root_properties[] = { + {"device_type", "cpu", 4}, + {"idprom", (char *)&ap_idprom, sizeof(ap_idprom)}, + {"banner-name", "Fujitsu AP1000+", 16}, + {NULL, NULL, -1} +}; + +struct node nodes[] = { + { 0, &null_properties }, + { 0, root_properties }, + { -1,&null_properties } +}; + + +static int no_nextnode(int node) +{ + if (nodes[node].level == nodes[node+1].level) + return node+1; + return -1; +} + +static int no_child(int node) +{ + if (nodes[node].level == nodes[node+1].level-1) + return node+1; + return -1; +} + +static struct property *find_property(int node,char *name) +{ + struct property *prop = &nodes[node].properties[0]; + while (prop && prop->name) { + if (strcmp(prop->name,name) == 0) return prop; + prop++; + } + return NULL; +} + +static int no_proplen(int node,char *name) +{ + struct property *prop = find_property(node,name); + if (prop) return prop->length; + return -1; +} + +static int no_getprop(int node,char *name,char *value) +{ + struct property *prop = find_property(node,name); + if (prop) { + memcpy(value,prop->value,prop->length); + return 1; + } + return -1; +} + +static int no_setprop(int node,char *name,char *value,int len) +{ + return -1; +} + +static char *no_nextprop(int node,char *name) +{ + struct property *prop = find_property(node,name); + if (prop) return prop[1].name; + return NULL; +} + + +static struct linux_nodeops ap_nodeops = { + no_nextnode, + no_child, + no_proplen, + no_getprop, + no_setprop, + no_nextprop +}; + + + +static unsigned char calc_idprom_cksum(struct idprom *idprom) +{ + unsigned char cksum, i, *ptr = (unsigned char *)idprom; + + for (i = cksum = 0; i <= 0x0E; i++) + cksum ^= *ptr++; + + return cksum; +} + +static int synch_hook; + + +struct linux_romvec *ap_prom_init(void) +{ + memset(&ap_romvec,0,sizeof(ap_romvec)); + + ap_romvec.pv_romvers = 42; + ap_romvec.pv_nodeops = &ap_nodeops; + ap_romvec.pv_reboot = ap_reboot; + ap_romvec.pv_synchook = &synch_hook; + + ap_idprom.id_format = 1; + ap_idprom.id_sernum = mpp_cid(); + ap_idprom.id_machtype = SM_SUN4M_OBP; + ap_idprom.id_cksum = calc_idprom_cksum(&ap_idprom); + + return &ap_romvec; +} + + + + + diff --git a/arch/sparc/ap1000/bnet.c b/arch/sparc/ap1000/bnet.c new file mode 100644 index 000000000000..9305b0a55fde --- /dev/null +++ b/arch/sparc/ap1000/bnet.c @@ -0,0 +1,1204 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* routines to control the AP1000 bif interface. This is the interface + used to talk to the front end processor */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NET_DEBUG 0 + +#define DUMMY_MSG_LEN 100 +#define DUMMY_MSG_WAIT 30 + +#define MAX_CELLS 128 + +#define HAVE_BIF() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG) +#define BIF_BUSY() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BB) + +#define SNET_ARBITRATION 0 +#define TOKEN_ARBITRATION 1 + +#define DEBUG(x) + +#if TOKEN_ARBITRATION +static int have_token = 0; +#endif + +extern struct cap_init cap_init; + +static int interrupt_driven = 0; +static int use_dma = 0; +struct pt_regs *bif_pt_regs = NULL; +enum dma_state {DMA_IDLE,DMA_INCOMING,DMA_OUTGOING}; +static enum dma_state dma_state = DMA_IDLE; + +static int net_started = 0; +static int waiting_for_bif = 0; +static int queue_length = 0; + +static int drop_ip_packets = 0; + +#define DMA_THRESHOLD 64 + +static struct cap_request bread_req; + +int tnet_ip_enabled = 1; + +#define BIF_DATA_WAITING() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) + +#define ROUND4(x) (((x) + 3) & -4) + +static void bif_intr_receive(struct cap_request *req1); + + +/* read some data from the bif */ +void read_bif(char *buf,int size) +{ + unsigned *ibuf = (unsigned *)buf; + unsigned avail; + + DEBUG(("|read_bif %d\n",size)); + + if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); + + size = (size+3) >> 2; + + while (size > 4) { + while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_RB_SHIFT) & 7)) + ; + if (avail & 4) { + ibuf[0] = BIF_IN(BIF_DATA); + ibuf[1] = BIF_IN(BIF_DATA); + ibuf[2] = BIF_IN(BIF_DATA); + ibuf[3] = BIF_IN(BIF_DATA); + size -= 4; ibuf += 4; + continue; + } + + if (avail & 2) { + ibuf[0] = BIF_IN(BIF_DATA); + ibuf[1] = BIF_IN(BIF_DATA); + size -= 2; ibuf += 2; + continue; + } + *ibuf++ = BIF_IN(BIF_DATA); + size--; + } + + while (size--) { + while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)) ; + *ibuf++ = BIF_IN(BIF_DATA); + } + + DEBUG(("|read bif done\n")); +} + +/* throw out some data from the bif. This is usually called when we + don't have the resources to handle it immediately */ +void bif_toss(int size) +{ + unsigned flags; + save_flags(flags); cli(); + + DEBUG(("|bif toss %d\n",size)); + + while (size>0) { + while (!BIF_DATA_WAITING()); + BIF_IN(BIF_DATA); + size -= 4; + } + + DEBUG(("|bif toss done\n")); + + restore_flags(flags); +} + + +static void bif_reset_interrupts(void) +{ + BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_GET_SH); + BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_HEADER_SH); +} + +static void bif_mask_interrupts(void) +{ + BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_GET_SH); + BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_HEADER_SH); +} + +static void attn_enable(void) +{ + BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_ATTN_SH); +} + +static void attn_mask(void) +{ + BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_ATTN_SH); +} + + +void ap_bif_status(void) +{ + static int bif_sdcsr; + static int bif_intr; + static int bif_mhocr; + static int bif_x0sk; + static int bif_xsk; + static int bif_xsz; + static int bif_y0sk; + static int bif_ysk; + static int bif_ysz; + static int bif_cx0sk; + static int bif_cxsk; + static int bif_cxsz; + static int bif_cy0sk; + static int bif_cysk; + static int bif_cysz; + static int bif_ttl; + static int bif_cttl; + static int bif_header; + + bif_sdcsr = BIF_IN(BIF_SDCSR); + bif_intr = BIF_IN(BIF_INTR); + bif_mhocr = BIF_IN(BIF_MHOCR); + + bif_x0sk = BIF_IN(BIF_X0SK); + bif_xsk = BIF_IN(BIF_XSK); + bif_xsz = BIF_IN(BIF_XSZ); + bif_y0sk = BIF_IN(BIF_Y0SK); + bif_ysk = BIF_IN(BIF_YSK); + bif_ysz = BIF_IN(BIF_YSZ); + + bif_cx0sk = BIF_IN(BIF_CX0SK); + bif_cxsk = BIF_IN(BIF_CXSK); + bif_cxsz = BIF_IN(BIF_CXSZ); + bif_cy0sk = BIF_IN(BIF_CY0SK); + bif_cysk = BIF_IN(BIF_CYSK); + bif_cysz = BIF_IN(BIF_CYSZ); + + bif_ttl = BIF_IN(BIF_TTL); + bif_cttl = BIF_IN(BIF_CTTL); + bif_header = BIF_IN(BIF_HEADER); + + printk("|\t***** BIF REG. *****\n"); + printk("|\tBIF_SDCSR = %08x ", bif_sdcsr); + if(bif_sdcsr & BIF_SDCSR_CN) printk("|"); + if(bif_sdcsr & BIF_SDCSR_FN) printk("|"); + if(bif_sdcsr & BIF_SDCSR_DE) printk("|"); + if(bif_sdcsr & BIF_SDCSR_DR) printk("|"); + if(bif_sdcsr & BIF_SDCSR_BB) printk("|"); + if(bif_sdcsr & BIF_SDCSR_BR) printk("|"); + if(bif_sdcsr & BIF_SDCSR_BG) printk("|"); + if(bif_sdcsr & BIF_SDCSR_ER) printk("|"); + if(bif_sdcsr & BIF_SDCSR_PE) printk("|"); + printk("|\n"); + printk("|\tBIF_INTR = %08x\n", bif_intr); + printk("|\tBIF_MHOCR = %08x\n", bif_mhocr); + + printk("|\tBIF_X0SK = %08x\n", bif_x0sk); + printk("|\tBIF_XSK = %08x\n", bif_xsk); + printk("|\tBIF_XSZ = %08x\n", bif_xsz); + printk("|\tBIF_Y0SK = %08x\n", bif_y0sk); + printk("|\tBIF_YSK = %08x\n", bif_ysk); + printk("|\tBIF_YSZ = %08x\n", bif_ysz); + printk("|\tBIF_CX0SK = %08x\n", bif_cx0sk); + printk("|\tBIF_CXSK = %08x\n", bif_cxsk); + printk("|\tBIF_CXSZ = %08x\n", bif_cxsz); + printk("|\tBIF_CY0SK = %08x\n", bif_cy0sk); + printk("|\tBIF_CYSK = %08x\n", bif_cysk); + printk("|\tBIF_CYSZ = %08x\n", bif_cysz); + + printk("|\tBIF_TTL = %08x\n", bif_ttl); + printk("|\tBIF_CTTL = %08x\n", bif_cttl); + printk("|\tBIF_HEADER = %08x\n", bif_header); +} + + +void bif_led_status(void) +{ +#if 1 + static int i = 0; + unsigned char res = 0; + + switch (i) { + case 0: + case 2: + res = 0xff; + break; + case 1: + case 3: + res = 0; + break; + default: + res = 0xFF & (BIF_IN(BIF_SDCSR) >> (((i-4)/4)*8)); + } + i = (i+1) % 20; + + ap_led(res); +#endif +} + +static void get_bif(void) +{ + if (HAVE_BIF()) + return; + + drop_ip_packets = 1; + + DEBUG(("|get_bif started\n")); + + if (dma_state != DMA_IDLE) + ap_dma_wait(DMA_CH2); + +#if SNET_ARBITRATION + /* wait till the host doesn't want the BIF anymore, tossing + any data that arrives */ + while (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) + if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) + bif_intr_receive(NULL); + waiting_for_bif = 0; +#endif + +#if TOKEN_ARBITRATION + BIF_OUT(FSTT_CLR,HOST_STATUS_BIT); +#endif + + /* request the BIF */ + BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); + + /* loop waiting for us to get the BIF, tossing any data */ + while (!HAVE_BIF()) + if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB) + bif_intr_receive(NULL); + + bif_reset_interrupts(); + if (!interrupt_driven) + bif_mask_interrupts(); + + drop_ip_packets = 0; + +#if TOKEN_ARBITRATION + BIF_OUT(FSTT_SET,HOST_STATUS_BIT); +#endif + + DEBUG(("|get_bif done\n")); +} + + +/* write a message to the front end over the Bnet. This can be in + multiple parts, as long as the first part sets "start" and the last + part sets "end". The bus will be grabbed while this is going on + */ +static void write_bif(char *buf,int size,int start,int end) +{ + unsigned *ibuf; + unsigned avail; + + DEBUG(("|write_bif %d %d %d\n",size,start,end)); + + if (start) { + /* a dma op may be in progress */ + if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); + } + + size = (size+3) >> 2; + ibuf = (unsigned *)buf; + if (end) size--; + + while (size > 4) { + while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_TB_SHIFT) & 7)) + ; + if (avail & 4) { + BIF_OUT(BIF_DATA,ibuf[0]); + BIF_OUT(BIF_DATA,ibuf[1]); + BIF_OUT(BIF_DATA,ibuf[2]); + BIF_OUT(BIF_DATA,ibuf[3]); + size -= 4; ibuf += 4; + continue; + } + + if (avail & 2) { + BIF_OUT(BIF_DATA,ibuf[0]); + BIF_OUT(BIF_DATA,ibuf[1]); + size -= 2; ibuf += 2; + continue; + } + BIF_OUT(BIF_DATA,ibuf[0]); + ibuf++; size--; + } + + while (size--) { + while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ; + BIF_OUT(BIF_DATA,ibuf[0]); + ibuf++; + } + + if (end) { + while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ; + BIF_OUT(BIF_EDATA,*ibuf); + } + + DEBUG(("|write bif done\n")); +} + +#if TOKEN_ARBITRATION +static void forward_token(void) +{ + struct cap_request req; + req.cid = mpp_cid(); + req.type = REQ_BIF_TOKEN; + req.size = sizeof(req); + if (req.cid == cap_init.numcells - 1) + req.header = MAKE_HEADER(HOST_CID); + else + req.header = MAKE_HEADER(req.cid + 1); + + write_bif((char *)&req,sizeof(req),1,1); + have_token = 0; +} +#endif + +static void release_bif(void) +{ + static int dummy[DUMMY_MSG_LEN]; + + waiting_for_bif = 0; + +#if SNET_ARBITRATION + /* mask the attention interrupt */ + attn_mask(); +#endif + + /* maybe we don't have it?? */ + if (!HAVE_BIF()) + return; + + DEBUG(("|release bif started\n")); + + if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2); + +#if TOKEN_ARBITRATION + if (have_token) + forward_token(); +#endif + +#if 1 + /* send a dummy message to ensure FIFO flushing + (suggestion from woods to overcome bif release + hardware bug) */ + dummy[0] = 0xEEEE4000; + write_bif((char *)dummy,DUMMY_MSG_LEN,1,1); +#endif + /* wait till the send FIFO is completely empty */ + while (!((BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB) == BIF_SDCSR_TB)) ; + + /* wait another few us */ + udelay(DUMMY_MSG_WAIT); + + /* send release-data */ + BIF_OUT(BIF_DATA,BIF_HEADER_RS); + + /* wait until we don't have the bus */ + while (HAVE_BIF()) ; + + DEBUG(("|release bif done\n")); +} + + +/* wait for a particular request type - throwing away anything else! */ +void ap_wait_request(struct cap_request *req,int type) +{ + drop_ip_packets = 1; + do { + while (!BIF_DATA_WAITING()) + if (HAVE_BIF()) release_bif(); + read_bif((char *)req,sizeof(*req)); + if (req->type != type) { + bif_intr_receive(req); + } + } while (req->type != type); + drop_ip_packets = 0; +} + + +void write_bif_polled(char *buf1,int len1,char *buf2,int len2) +{ + unsigned flags; + save_flags(flags); cli(); + + get_bif(); + write_bif(buf1,len1,1,(buf2&&len2)?0:1); + if (buf2 && len2) + write_bif(buf2,len2,0,1); + release_bif(); + restore_flags(flags); +} + +static void want_bif(void) +{ + unsigned flags; + + save_flags(flags); cli(); + + /* maybe we've already got it */ + if (HAVE_BIF()) { + waiting_for_bif = 0; + restore_flags(flags); + return; + } + +#if SNET_ARBITRATION + if (interrupt_driven) + attn_enable(); + + /* check if the host wants it */ + if (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) { + /* the host wants it - don't get it yet */ + waiting_for_bif = 1; + } else { + /* the host doesn't want it - just set bus request */ + waiting_for_bif = 0; + BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); + while (!HAVE_BIF() && !BIF_BUSY()) ; + DEBUG(("|set bif request\n")); + } + restore_flags(flags); + return; +#endif + +#if TOKEN_ARBITRATION + if (net_started && !have_token) { + BIF_OUT(FSTT_CLR,HOST_STATUS_BIT); + restore_flags(flags); + return; + } + BIF_OUT(FSTT_SET,HOST_STATUS_BIT); +#endif + + BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR); + restore_flags(flags); +} + +#define BIF_NOCOPY (1<<0) + +/* a queue of requests that need to be sent over the bif. Needs to be +modified sometime to allow the direct queueing of skb's */ +struct bif_queue { + volatile struct bif_queue *next; + struct cap_request req; + char *data; + int data_size; + int flags; +}; + +static volatile struct bif_queue *bif_queue_top = NULL; +static volatile struct bif_queue *bif_queue_end = NULL; + +static struct sk_buff *skb_out = NULL; +static struct sk_buff *skb_in = NULL; +static char *bif_dma_data = NULL; +static int bif_dma_out_size = 0; + + +/* send waiting elements. Called mainly when we get a bif "bus get" + interrupt to say we now have the bus */ +static void bif_intr_runqueue(void) +{ + unsigned flags; + + /* if I don't have the bus then return */ + if (!HAVE_BIF()) + return; + + if (dma_state != DMA_IDLE) return; + + save_flags(flags); cli(); + + while (bif_queue_top) { + volatile struct bif_queue *q = bif_queue_top; + bif_queue_top = q->next; + + /* printk("|queue run (length=%d)\n",queue_length); */ + queue_length--; + + if (!q->data) { + /* use programmed IO for small requests */ + write_bif((char *)&q->req,sizeof(q->req),1,1); + kfree_s((char *)q,sizeof(*q)); + continue; + } + + if (q->flags & BIF_NOCOPY) { + write_bif((char *)&q->req,sizeof(q->req),1,0); + } + + if (use_dma && q->data_size > DMA_THRESHOLD) { + dma_state = DMA_OUTGOING; + if (q->req.type == REQ_IP) { + skb_out = (struct sk_buff *)q->data; + ap_dma_go(DMA_CH2,(unsigned)skb_out->data, + q->data_size,DMA_DCMD_TD_MD); + } else { + if (!(q->flags & BIF_NOCOPY)) { + bif_dma_data = q->data; + bif_dma_out_size = q->data_size; + } + ap_dma_go(DMA_CH2,(unsigned)q->data, + q->data_size,DMA_DCMD_TD_MD); + } + kfree_s((char *)q,sizeof(*q)); + restore_flags(flags); + return; /* wait for DMA to complete */ + } + + 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); + } else { + write_bif(q->data,q->data_size,1,1); + if (!(q->flags & BIF_NOCOPY)) + kfree_s(q->data,q->data_size); + } + kfree_s((char *)q,sizeof(*q)); + } + + /* I don't want the bus now */ + release_bif(); + restore_flags(flags); +} + + +static void queue_attach(struct bif_queue *q) +{ + unsigned flags; + save_flags(flags); cli(); + + /* attach it to the end of the queue */ + if (!bif_queue_top) { + bif_queue_top = q; + } else { + bif_queue_end->next = q; + } + bif_queue_end = q; + + queue_length++; + + /* printk("|queue add (length=%d)\n",queue_length); */ + + /* tell the bus we want access */ + want_bif(); + + restore_flags(flags); +} + + +/* queue an element for sending over the bif. */ +int bif_queue(struct cap_request *req,char *buf,int bufsize) +{ + struct bif_queue *q; + + if (req->header == 0) + req->header = MAKE_HEADER(HOST_CID); + + /* if we aren't running interrupt driven then just send it + immediately */ + if (!interrupt_driven) { + write_bif_polled((char *)req,sizeof(*req),buf,bufsize); + return(0); + } + + /* allocate a queue element */ + q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); + if (!q) { + /* yikes! */ + return(-ENOMEM); + } + + q->flags = 0; + q->data = NULL; + q->data_size = 0; + + if (buf && bufsize>0) { + q->data_size = bufsize+sizeof(*req); + q->data = (char *)kmalloc(q->data_size,GFP_ATOMIC); + if (!q->data) { + kfree_s(q,sizeof(*q)); + return(-ENOMEM); + } + } + + q->req = *req; + if (buf&&bufsize) { + memcpy(q->data,(char *)req,sizeof(*req)); + memcpy(q->data+sizeof(*req),buf,bufsize); + } + q->next = NULL; + + queue_attach(q); + + return(0); +} + + +/* queue an element for sending over the bif. */ +int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize) +{ + struct bif_queue *q; + + if (req->header == 0) + req->header = MAKE_HEADER(HOST_CID); + + /* allocate a queue element */ + q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); + if (!q) { + return(-ENOMEM); + } + + q->data = buf; + q->data_size = bufsize; + q->flags = BIF_NOCOPY; + q->req = *req; + q->next = NULL; + + queue_attach(q); + + return(0); +} + + +/* put an IP packet into the bif queue */ +int bif_send_ip(int cid, struct sk_buff *skb) +{ + struct cap_request *req = (struct cap_request *)skb->data; + struct bif_queue *q; + u_long destip; + + destip = *(u_long *)(skb->data+sizeof(*req)+16); + + if (cid != -1) { + req->header = MAKE_HEADER(cid); + } else if (destip == (cap_init.baseIP | ~cap_init.netmask)) { + req->header = BIF_HEADER_IN | BIF_HEADER_BR; + } else { + req->header = MAKE_HEADER(HOST_CID); + } + + /* allocate a queue element */ + q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); + if (!q) { + /* yikes! */ + dev_kfree_skb(skb, FREE_WRITE); + return(-ENOMEM); + } + + req->size = ROUND4(skb->len); + req->cid = mpp_cid(); + req->type = REQ_IP; + + q->data = (char *)skb; + q->data_size = req->size; + q->next = NULL; + q->req = *req; + q->flags = 0; + + queue_attach(q); + + return(0); +} + + +/* send an OPENNET request to tell the front end to open the apnet + network interface */ +void start_apnet(void) +{ + struct cap_request req; + req.cid = mpp_cid(); + req.type = REQ_OPENNET; + req.size = sizeof(req); + req.header = MAKE_HEADER(HOST_CID); + + bif_queue(&req,NULL,0); + printk("sent start_apnet request\n"); +} + +/* we have received an IP packet - pass it to the bif network + interface code */ +static void reply_ip(struct cap_request *req) +{ + if (drop_ip_packets || + !(skb_in = dev_alloc_skb(req->size - sizeof(*req)))) { + bif_toss(req->size - sizeof(*req)); + return; + } + + if (use_dma && req->size > DMA_THRESHOLD) { + dma_state = DMA_INCOMING; + ap_dma_go(DMA_CH2, + (unsigned)skb_put(skb_in,req->size - sizeof(*req)), + req->size - sizeof(*req),DMA_DCMD_TD_DM); + } else { + read_bif(skb_put(skb_in,req->size - sizeof(*req)), + req->size - sizeof(*req)); + bif_rx(skb_in); + skb_in = NULL; + } +} + + +/* we have received a bread block - DMA it in */ +static void reply_bread(struct cap_request *req) +{ + extern char *ap_buffer(struct cap_request *creq); + char *buffer; + + buffer = ap_buffer(req); + bread_req = *req; + + if (use_dma) { + dma_state = DMA_INCOMING; + ap_dma_go(DMA_CH2, + (unsigned)buffer,req->size - sizeof(*req), + DMA_DCMD_TD_DM); + } else { + read_bif(buffer,req->size - sizeof(*req)); + ap_complete(&bread_req); + bread_req.type = -1; + } +} + + +static struct debug_key { + struct debug_key *next; + char key; + void (*fn)(void); + char *description; +} *debug_keys = NULL; + + +void show_debug_keys(void) +{ + struct debug_key *r; + for (r=debug_keys;r;r=r->next) + printk("%c: %s\n",r->key,r->description); +} + + +void bif_add_debug_key(char key,void (*fn)(void),char *description) +{ + struct debug_key *r,*r2; + r = (struct debug_key *)kmalloc(sizeof(*r),GFP_ATOMIC); + if (r) { + r->next = NULL; + r->key = key; + r->fn = fn; + r->description = description; + if (!debug_keys) { + debug_keys = r; + } else { + for (r2=debug_keys; + r2->next && r2->key != key;r2=r2->next) ; + + if (r2->key == key) { + r2->fn = fn; + r2->description = description; + kfree_s(r,sizeof(*r)); + } else { + r2->next = r; + } + } + } +} + +/* these are very useful for debugging ! */ +static void reply_putchar(struct cap_request *req) +{ + struct debug_key *r; + + char c = req->data[0]; + + ap_set_user(req->data[1]); + + for (r=debug_keys;r;r=r->next) + if (r->key == c) { + r->fn(); + break; + } + if (!r) + printk("cell %d got character %d [%c]\n",mpp_cid(),(int)c,c); + + ap_set_user(-1); +} + + +/* send a signal to a task by name or pid */ +static void reply_kill(struct cap_request *req) +{ + int sig = req->data[0]; + struct task_struct *p; + int len; + char name[32]; + + len = req->size - sizeof(*req); + if (len == 0) { + int pid = req->data[1]; + for_each_task(p) + if (p->pid == pid) { + send_sig(sig,p,1); + return; + } + printk("cell %d: no task with pid %d\n",mpp_cid(),pid); + return; + } + + if (len > sizeof(name)-1) { + bif_toss(len); + return; + } + + read_bif(name,len); + name[len] = 0; + + for_each_task(p) + if (strcmp(name,p->comm) == 0) + send_sig(sig,p,1); +} + + +static struct req_list { + struct req_list *next; + int type; + void (*fn)(struct cap_request *); +} *reg_req_list = NULL; + + +void bif_register_request(int type,void (*fn)(struct cap_request *)) +{ + struct req_list *r,*r2; + r = (struct req_list *)kmalloc(sizeof(*r),GFP_ATOMIC); + if (r) { + r->next = NULL; + r->type = type; + r->fn = fn; + if (!reg_req_list) { + reg_req_list = r; + } else { + for (r2=reg_req_list; + r2->next && r2->type != type;r2=r2->next) ; + + if (r2->type == type) { + r2->fn = fn; + kfree_s(r,sizeof(*r)); + } else { + r2->next = r; + } + } + } +} + + + +/* a request has come in on the bif - process it */ +static void bif_intr_receive(struct cap_request *req1) +{ + struct req_list *r; + extern void ap_open_reply(struct cap_request *creq); + struct cap_request req; + + if (req1) { + req = *req1; + } else { + /* read the main cap request header */ + read_bif((char *)&req,sizeof(req)); + } + + /* service it */ + switch (req.type) + { + case REQ_PUTCHAR: + reply_putchar(&req); + break; + case REQ_KILL: + reply_kill(&req); + break; + case REQ_BREAK: + breakpoint(); + break; + case REQ_IP: + reply_ip(&req); + break; +#if TOKEN_ARBITRATION + case REQ_BIF_TOKEN: + have_token = 1; + want_bif(); + break; +#endif + case REQ_OPENNET: + net_started = 1; + break; + case REQ_BREAD: + reply_bread(&req); + break; + case REQ_BOPEN: + ap_open_reply(&req); + break; + case REQ_BWRITE: + ap_complete(&req); + break; + case REQ_SCHEDULE: + mpp_schedule(&req); + break; + + default: + for (r=reg_req_list;r;r=r->next) + if (r->type == req.type) { + r->fn(&req); + return; + } + printk("Unknown request %d\n",req.type); + break; + } +} + + +static void bif_dma_complete(void) +{ + extern int bif_rx(struct sk_buff *skb); + enum dma_state old_state = dma_state; + unsigned a; + + a = DMA_IN(DMA2_DMST); + + if (a & DMA_DMST_AC) return; + + DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ< +#include +#include +#include +#include +#include + +#define DMA_MAX_TRANS_SIZE2 (0xfffffc) + +int ap_dma_wait(int ch) +{ + int i = 0; + while (DMA_IN(ch+DMA_DMST) & DMA_DMST_AC) i++; + return i; +} + +/* send some data out a dma channel */ +int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd) +{ + int rest; + + p = mmu_v2p(p); + + cmd |= DMA_DCMD_ST | DMA_DCMD_TYP_AUTO; + +#if 0 + if (ap_dma_wait(ch)) { + printk("WARNING: dma started when not complete\n"); + } + + if (cmd == DMA_DCMD_TD_MD && !(BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)) { + ap_led(0xAA); + printk("attempt to dma without holding the bus\n"); + return -1; + } +#endif + + /* reset the dma system */ + DMA_OUT(ch + DMA_DMST,DMA_DMST_RST); + + if (size <= DMA_MAX_TRANS_SIZE) { + DMA_OUT(ch + DMA_MADDR,(unsigned long)p); + DMA_OUT(ch + DMA_HSKIP,1); + DMA_OUT(ch + DMA_VSKIP,1); + DMA_OUT(ch + DMA_DCMD,cmd | B2W(size)); + return 0; + } + + if (size <= DMA_MAX_TRANS_SIZE2) { + if(size & 0x3) size += 4; + rest = (size & (DMA_TRANS_BLOCK_SIZE - 1)) >> 2; + if (rest) { + DMA_OUT(ch + DMA_HDRP,(unsigned)p); + p += rest << 2; + } + DMA_OUT(ch + DMA_MADDR,(unsigned)p); + DMA_OUT(ch + DMA_HSKIP,size >> (2 + 6)); + DMA_OUT(ch + DMA_VSKIP,1); + DMA_OUT(ch + DMA_DCMD,cmd | (rest << 16) | 64); + return 0; + } + + printk("AP1000 DMA operation too big (%d bytes) - aborting\n",size); + return(-1); +} + diff --git a/arch/sparc/ap1000/hw.c b/arch/sparc/ap1000/hw.c new file mode 100644 index 000000000000..c36150c4e960 --- /dev/null +++ b/arch/sparc/ap1000/hw.c @@ -0,0 +1,185 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Initialize the AP1000 hardware: BIF, MSC+, MC+, etc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define APLOG 0 + +/* these make using CellOS code easier */ +int cap_nopt0; +int cap_cid0; +int cap_ncel0; + +unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy; + +/* yuck - needed for sun4c! */ +static unsigned char dummy; +unsigned char *auxio_register = &dummy; + + +extern struct cap_init cap_init; + +static void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + ap_panic("** unexpected interrupt %d **\n",irq); +} + +static void ap_other_irqs(void) +{ + request_irq(3, unexpected_irq, SA_INTERRUPT, "unused", 0); + request_irq(5, unexpected_irq, SA_INTERRUPT, "unused", 0); + request_irq(12, unexpected_irq, SA_INTERRUPT, "unused", 0); + request_irq(15, unexpected_irq, SA_INTERRUPT, "unused", 0); +} + +int ap_memory_size(void) +{ + if ((MSC_IN(MSC_SIMMCHK) & MSC_SIMMCHK_MASK) == 0) { + return 16*1024*1024; + } + return 64*1024*1024; +} + +static void show_registers(void) +{ + extern struct pt_regs *bif_pt_regs; + if (bif_pt_regs) + show_regs(bif_pt_regs); + else + printk("unable to show registers\n"); +} + + +static void check_alive(void) +{ + printk("Cell %d is alive\n",mpp_cid()); +} + + + +static void show_task(struct task_struct *t) +{ + printk("cell=%3d uid=%5d pid=%5d utime=%3d stime=%3d etime=%3d name=%s\n", + mpp_cid(), + t->uid, + (int)t->pid, + (int)t->utime, + (int)t->stime, + (jiffies - (int)t->start_time) / 100, + t->comm); +} + +static void show_ptasks(void) +{ + extern struct task_struct *task[]; + int i; + int count=0; + + for (i=MPP_TASK_BASE;iuid > 1) { + show_task(task[i]); + count++; + } + + if (count == 0) + printk("no user tasks on cell %d\n",mpp_cid()); +} + + +static void show_otasks(void) +{ + extern struct task_struct *task[]; + int i; + int count=0; + extern int ap_current_uid; + + for (i=0;iuid == ap_current_uid) { + show_task(task[i]); + count++; + } + + if (count == 0) + printk("no tasks on cell %d\n",mpp_cid()); +} + + +void do_panic(void) +{ + int *x = 0; + *x = 1; /* uggh */ +} + + +void mpp_hw_init(void) +{ + extern void show_state(void); + extern void breakpoint(void); + extern void ctrl_alt_del(void); + extern void mac_print_state(void); + extern void show_debug_keys(void); + + bif_add_debug_key('c',check_alive,"check if a cell is alive"); + bif_add_debug_key('k',show_debug_keys,"show the kernel debug keys"); + bif_add_debug_key('p',show_registers,"show register info"); + bif_add_debug_key('p',show_registers,"show register info"); + bif_add_debug_key('m',show_mem,"detailed memory stats"); + bif_add_debug_key('s',show_state,"detailed process stats"); + bif_add_debug_key('D',ap_start_debugger,"launch the kernel debugger"); + bif_add_debug_key('i',breakpoint,"send a breakpoint"); + bif_add_debug_key('r',ctrl_alt_del,"run shutdown (doesn't work)"); + bif_add_debug_key('P',show_ptasks,"show running parallel tasks"); + bif_add_debug_key('U',show_utasks,"show all user tasks"); + bif_add_debug_key('O',show_otasks,"show own user tasks"); + bif_add_debug_key('^',do_panic,"panic :-)"); + + + cap_cid0 = BIF_IN(BIF_CIDR1); + cap_ncel0 = cap_init.numcells; + + _cid = cap_cid0; + _ncel = cap_ncel0; + _ncelx = _ncel<8?_ncel:8; + _ncely = ((_ncel-1) / _ncelx) + 1; + _cidx = _cid % _ncelx; + _cidy = _cid / _ncelx; + + ap_bif_init(); + ap_msc_init(); + ap_tnet_init(); + ap_profile_init(); + ap_other_irqs(); + ap_ringbuf_init(); +#if APLOG + ap_log(NULL,-1); +#endif +} diff --git a/arch/sparc/ap1000/irq.c b/arch/sparc/ap1000/irq.c new file mode 100644 index 000000000000..d329faf3ace9 --- /dev/null +++ b/arch/sparc/ap1000/irq.c @@ -0,0 +1,64 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void ap_clear_clock_irq(void); +extern void ap_init_timers(void); + +static void ap_enable_irq(unsigned int irq_nr) +{ + /* printk("ENABLE IRQ %d IGNORED\n",irq_nr); */ +} + +static void ap_disable_irq(unsigned int irq_nr) +{ + printk("DISABLE IRQ %d IGNORED\n",irq_nr); +} + +static void ap_clear_profile_irq(void) +{ + MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); +} + +static void ap_load_profile_irq(unsigned limit) +{ + MC_OUT(MC_ITIMER0,limit); +} + +void ap_init_IRQ(void) +{ + enable_irq = ap_enable_irq; + disable_irq = ap_disable_irq; + clear_clock_irq = ap_clear_clock_irq; + clear_profile_irq = ap_clear_profile_irq; + load_profile_irq = ap_load_profile_irq; + init_timers = ap_init_timers; + + sti(); /* the sun4m code does this, so we do too */ +} diff --git a/arch/sparc/ap1000/kgdb.c b/arch/sparc/ap1000/kgdb.c new file mode 100644 index 000000000000..fa6c65ecd7af --- /dev/null +++ b/arch/sparc/ap1000/kgdb.c @@ -0,0 +1,78 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* routines to support remote kgdb to Linux/AP+ cells */ + +#include +#include +#include +#include +#include + +static char out_buf[0x100]; +static int out_buf_pos = 0; + +static char in_buf[0x100]; +static int in_buf_pos = 0; +static int in_buf_count = 0; + +static int hash_pos = -1; + +void ap_dbg_flush(void) +{ + struct cap_request req; + + if (out_buf_pos == 0) return; + + req.cid = mpp_cid(); + req.type = REQ_PUTDEBUGSTRING; + req.size = sizeof(req) + out_buf_pos; + req.header = MAKE_HEADER(HOST_CID); + + write_bif_polled((char *)&req,sizeof(req),(char *)out_buf,out_buf_pos); + + out_buf_pos = 0; + hash_pos = -1; +} + +/* called by the gdb stuff */ +void putDebugChar(char c) +{ + if (c == '#') hash_pos = out_buf_pos; + + out_buf[out_buf_pos++] = c; + if (out_buf_pos == sizeof(out_buf)) { + ap_dbg_flush(); + } +} + +/* used by gdb to get input */ +char getDebugChar(void) +{ + unsigned flags; + struct cap_request req; + + ap_dbg_flush(); + + if (in_buf_count == 0) { + req.cid = mpp_cid(); + req.type = REQ_GETDEBUGCHAR; + req.size = sizeof(req); + req.header = MAKE_HEADER(HOST_CID); + + save_flags(flags); cli(); + write_bif_polled((char *)&req,sizeof(req),NULL,0); + ap_wait_request(&req,REQ_GETDEBUGCHAR); + read_bif(in_buf,req.size - sizeof(req)); + in_buf_pos = 0; + in_buf_count = req.size - sizeof(req); + restore_flags(flags); + } + + in_buf_count--; + return(in_buf[in_buf_pos++]); +} diff --git a/arch/sparc/ap1000/mpp.c b/arch/sparc/ap1000/mpp.c new file mode 100644 index 000000000000..021c1a2e5fcf --- /dev/null +++ b/arch/sparc/ap1000/mpp.c @@ -0,0 +1,82 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * simple mpp functions for the AP+ + */ + +#include +#include +#include +#include +#include +#include + +extern int cap_cid0; +extern int cap_ncel0; +extern struct cap_init cap_init; + +static volatile int mpp_current_task = 0; +static int gang_factor = DEF_GANG_FACTOR; +static int last_task = 0; + + +void mpp_schedule(struct cap_request *req) +{ + mpp_current_task = req->data[0]; + need_resched = 1; + mark_bh(TQUEUE_BH); +} + + +void mpp_notify_schedule(struct task_struct *tsk) +{ + last_task = tsk->taskid; + + msc_switch_check(tsk); + + if (gang_factor == 0) return; + + if (cap_cid0 == cap_init.bootcid && + mpp_current_task != tsk->taskid) { + struct cap_request req; + + mpp_current_task = tsk->taskid; + + req.cid = mpp_cid(); + req.type = REQ_SCHEDULE; + req.size = sizeof(req); + req.header = MAKE_HEADER(-1); + req.data[0] = mpp_current_task; + + bif_queue(&req,NULL,0); + } +} + + +int mpp_weight(struct task_struct *tsk) +{ + extern int block_parallel_tasks; + + if (!MPP_IS_PAR_TASK(tsk->taskid)) return 0; + + if (block_parallel_tasks) return -1000; + + if (last_task && last_task != tsk->taskid && task[last_task] && + !msc_switch_ok()) return -1000; + + if (cap_cid0 != cap_init.bootcid && + tsk->taskid != mpp_current_task) { + return -gang_factor; + } + return 0; +} + +void mpp_set_gang_factor(int factor) +{ + gang_factor = factor; +} diff --git a/arch/sparc/ap1000/msc.c b/arch/sparc/ap1000/msc.c new file mode 100644 index 000000000000..242df954c5e2 --- /dev/null +++ b/arch/sparc/ap1000/msc.c @@ -0,0 +1,1263 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Routines to control the AP1000+ Message Controller (MSC+) + * and Memory Controller (MC+). + * + */ +#include +#define _APLIB_ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs); +static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs); +static void msc_set_ringbuf(int context); +static void msc_update_read_ptr(int context,int overflow); +static void fail_write(int context,int intr,unsigned vaddr); +static void fail_read(int context,int intr,unsigned vaddr); +static void msc_switch_from_check(struct task_struct *tsk); +static void msc_status(void); + +#define DEBUG 0 + +/* + * This describes how the 5 queues for outgoing requests + * are mapped into the 256 words of send queue RAM in the MSC+. + */ +#define NSENDQUEUES 5 + +static struct send_queues { + int base; /* must be a multiple of size */ + int size; /* must be 32 or 64 */ +} send_queues[NSENDQUEUES] = { + {0, 64}, /* System put/send requests */ + {192, 32}, /* Remote read/write requests */ + {64, 64}, /* User put/send requests */ + {224, 32}, /* Remote read replies */ + {128, 64}, /* Get replies */ +}; + +#define NR_RBUFS MSC_NR_RBUFS + +static struct { + unsigned rbmbwp; + unsigned rbmmode; + unsigned rbmrp; +} ringbufs[MSC_NR_RBUFS] = { + {MSC_RBMBWP0, MSC_RBMMODE0, MSC_RBMRP0}, + {MSC_RBMBWP1, MSC_RBMMODE1, MSC_RBMRP1}, + {MSC_RBMBWP2, MSC_RBMMODE2, MSC_RBMRP2}, +}; + +#define CTX_MASK 0xfff +#define NULL_CONTEXT CTX_MASK + +#define QOF_ORDER 3 /* 32kB queue overflow buffer */ +#define QOF_SIZE ((1<> 19, MSC_QBMP_BP) \ + + MKFIELD((qof) >> 3, MSC_QBMP_WP) \ + + MKFIELD(((qof) + (size) - 1) >> 13, MSC_QBMP_LIM)) + +#define QBM_UPDATE_WP(wp) \ + MSC_OUT(MSC_QBMPTR, INSFIELD(MSC_IN(MSC_QBMPTR), (unsigned)(wp) >> 3, \ + MSC_QBMP_WP)) + +/* Send queue overflow buffer structure */ +struct qof_elt { + unsigned info; + unsigned data; +}; + +/* Fields in qof_elt.info */ +#define QOF_QUEUE_SH 24 /* queue bits start at bit 24 */ +#define QOF_QUEUE_M 0x1f /* 5 bits wide */ +#define QOF_ENDBIT 1 /* end bit in bit 0 */ + +static struct qof_elt *qof_base=NULL; /* start of overflow buffer */ +static unsigned long qof_phys; /* physical start adrs of overflow buffer */ +static struct qof_elt *qof_rp; /* read pointer for refills */ +static struct qof_elt *qof_new; /* first element we haven't yet looked at */ +static int qof_present[NSENDQUEUES];/* # elts for each q in [qof_rp,qof_new) */ + +/* this is used to flag when the msc is blocked, so we can't send + messages on it without the possability of deadlock */ +int msc_blocked = 0; +int block_parallel_tasks = 0; + +static int qbm_full_counter = 0; + +#define INTR_LIMIT 10000 +static int intr_counter = 0; +static unsigned intr_mask; + +#define DUMMY_RINGBUF_ORDER 5 +#define DUMMY_RINGBUF_SIZE ((1<>5)-1; +unsigned dummy_read_ptr = (DUMMY_RINGBUF_SIZE>>5)-1; + +#define SQ_NEW_MODE(mode) do { \ + MSC_OUT(MSC_SQCTRL, ((MSC_IN(MSC_SQCTRL) & ~MSC_SQC_RMODE) \ + | MSC_SQC_RMODE_ ## mode)); \ + while ((MSC_IN(MSC_SQCTRL) & MSC_SQC_MODE) != MSC_SQC_MODE_ ## mode) \ + /* hang */ ; \ +} while (0) + +/* Repack the queue overflow buffer if >= this many already-used entries */ +#define REPACK_THRESH 64 + + +static void refill_sq(void); +static void repack_qof(void); +static void shuffle_qof(void); +static void async_callback(int, unsigned long, int, int); + + +static void mask_all_interrupts(void) +{ + /* disable all MSC+ interrupts */ + MSC_OUT(MSC_INTR, + (AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH) | + (AP_SET_INTR_MASK << MSC_INTR_SQFILL_SH) | + (AP_SET_INTR_MASK << MSC_INTR_RBMISS_SH) | + (AP_SET_INTR_MASK << MSC_INTR_RBFULL_SH) | + (AP_SET_INTR_MASK << MSC_INTR_RMASF_SH) | + (AP_SET_INTR_MASK << MSC_INTR_RMASE_SH) | + (AP_SET_INTR_MASK << MSC_INTR_SMASF_SH) | + (AP_SET_INTR_MASK << MSC_INTR_SMASE_SH)); +} + +static inline int valid_task(struct task_struct *tsk) +{ + return(tsk && + !((tsk)->flags & PF_EXITING) && + tsk->mm && + tsk->mm->context != NO_CONTEXT); +} + +static inline unsigned long apmmu_get_raw_ctable_ptr(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (APMMU_CTXTBL_PTR), + "i" (ASI_M_MMUREGS)); + return (retval); +} + +static void mc_tlb_map(unsigned phys_page,unsigned vpage,int context) +{ + unsigned long long *tlb4k; + unsigned long long new_entry; + unsigned long *new_entryp = (unsigned long *)&new_entry; + tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF); + new_entryp[0] = (phys_page&~7) >> 3; + new_entryp[1] = ((phys_page & 7) << 29) | (((vpage>>8)&0xFFF) << 17) | + (context << 5) | 0x13; + tlb4k[0] = new_entry; +#if DEBUG + printk("mc_tlb_map(%x,%x,%x) %x %x at %x\n", + phys_page,vpage,context,new_entryp[0],new_entryp[1],tlb4k); +#endif +} + +static void mc_tlb_unmap(unsigned vpage) +{ + unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K; + tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF); + tlb4k[0] = 0; +} + +void mc_tlb_init(void) +{ + unsigned long long *tlb256k, *tlb4k; + int i; + + tlb4k = (unsigned long long *)MC_MMU_TLB4K; + for (i = MC_MMU_TLB4K_SIZE; i > 0; --i) + *tlb4k++ = 0; + tlb256k = (unsigned long long *)MC_MMU_TLB256K; + for (i = MC_MMU_TLB256K_SIZE; i > 0; --i) + *tlb256k++ = 0; +} + +void ap_msc_init(void) +{ + int i, flags, res; + unsigned int qp; + + bif_add_debug_key('M',msc_status,"MSC+ status"); + +#if DEBUG + printk("MSC+ version %x\n", MSC_IN(MSC_VERSION)); + printk("MC+ version %x\n", MC_IN(MC_VERSION)); +#endif + + mc_tlb_init(); + + /* Set the MC's copy of the context table pointer */ + MC_OUT(MC_CTP, apmmu_get_raw_ctable_ptr()); + + /* Initialize the send queue pointers */ + qp = MSC_SQPTR0; + for (i = 0; i < 5; ++i) { + MSC_OUT(qp, ((send_queues[i].size == 64? MSC_SQP_MODE: 0) + + ((send_queues[i].base >> 5) << MSC_SQP_BP_SH))); + qp += (MSC_SQPTR1 - MSC_SQPTR0); + } + + /* Initialize the send queue RAM */ + for (i = 0; i < 256; ++i) + MSC_OUT(MSC_SQRAM + i * 8, -1); + + if (!qof_base) { + qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER, 0); + for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i) + set_bit(PG_reserved, &mem_map[i].flags); + } + + qof_phys = mmu_v2p((unsigned long) qof_base); + MSC_OUT(MSC_QBMPTR, MAKE_QBMPTR((unsigned long)qof_base, QOF_SIZE)); + qof_rp = qof_base; + qof_new = qof_base; + for (i = 0; i < NSENDQUEUES; ++i) + qof_present[i] = 0; + + SQ_NEW_MODE(NORMAL); /* Set the send queue to normal mode */ + + /* Register interrupt handler for MSC+ */ + save_flags(flags); cli(); + res = request_irq(APMSC_IRQ, msc_interrupt_11, SA_INTERRUPT, + "apmsc", NULL); + if (res != 0) + printk("couldn't register MSC interrupt 11: error=%d\n", res); + res = request_irq(APMAS_IRQ, msc_interrupt_9, SA_INTERRUPT, + "apmas", NULL); + if (res != 0) + printk("couldn't register MSC interrupt 9: error=%d\n", res); + restore_flags(flags); + + MSC_OUT(MSC_MASCTRL, 0); + + /* Enable all MSC+ interrupts (for now) */ + MSC_OUT(MSC_INTR, + (AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_SQFILL_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_RBMISS_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_RBFULL_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_RMASE_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH) | + (AP_CLR_INTR_MASK << MSC_INTR_SMASE_SH)); + + /* setup invalid contexts */ + for (i=0; i= QOF_GREEN_NELT) { +#if DEBUG + printk("send queue overflow buffer overflow\n"); +#endif + MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH); + intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH); + need_resched = 1; + block_parallel_tasks = 1; + mark_bh(TQUEUE_BH); + } + ntot = qof_new - qof_rp; /* total # words of qof buf used */ + if (ntot - nvalid >= REPACK_THRESH || ntot >= QOF_GREEN_NELT + || (ntot > nvalid && nvalid >= QOF_GREEN_NELT - REPACK_THRESH)) { + repack_qof(); + if (qof_new - qof_rp != nvalid) { + printk("MSC: qof_present wrong\n"); + } + } else if (nvalid > 0) { + shuffle_qof(); + } + /* N.B. if nvalid == 0, msc_refill_sq has already reset the QBM's WP */ + SQ_NEW_MODE(NORMAL); + + /* dismiss the interrupt */ + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_QBMFUL_SH); +} + + +static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned intr; + unsigned long flags; + + save_flags(flags); cli(); + + if (intr_counter++ == INTR_LIMIT) { + mask_all_interrupts(); + printk("too many MSC interrupts\n"); + restore_flags(flags); + return; + } + + intr = MSC_IN(MSC_INTR); + +#if DEBUG + printk("CID(%d) msc_interrupt_11: intr = %x\n", mpp_cid(), intr); +#endif + + if (intr & (AP_INTR_REQ << MSC_INTR_RBMISS_SH)) { + int context; + context = MSC_IN(MSC_RMASREG) >> 20; + + msc_set_ringbuf(context); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBMISS_SH); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_RBFULL_SH)) { + int context = MSC_IN(MSC_RMASREG) >> 20; + msc_update_read_ptr(context,1); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBFULL_SH); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_SQFILL_SH)) { + qbmfill_interrupt(); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_QBMFUL_SH)) { + qbmful_interrupt(); + } + + restore_flags(flags); +} + + +void msc_timer(void) +{ + /* unmask all the interrupts that are supposed to be unmasked */ + intr_counter = 0; +} + +/* assumes NSENDQUEUES == 5 */ +static int log2tbl[32] = { + -1, 0, 1, -1, 2, -1, -1, -1, + 3, -1, -1, -1, -1, -1, -1, -1, + 4, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static unsigned long direct_queues[NSENDQUEUES][2] = { + { MSC_SYSTEM_DIRECT, MSC_SYSTEM_DIRECT_END }, + { MSC_REMOTE_DIRECT, MSC_REMOTE_DIRECT_END }, + { MSC_USER_DIRECT, MSC_USER_DIRECT_END }, + { MSC_REMREPLY_DIRECT, MSC_REMREPLY_DIRECT_END }, + { MSC_REPLY_DIRECT, MSC_REPLY_DIRECT_END } +}; + +/* + * Copy entries from the queue overflow buffer back to the send queue. + * This must be called with the send queue controller in THRU mode. + */ +static void refill_sq(void) +{ + int notfull, use_old; + int q, kept_some; + int sqp, sqc; + struct qof_elt *rp, *qof_wp; + int freew[NSENDQUEUES]; /* # free words in each queue */ + + /* give parallel tasks another chance */ + block_parallel_tasks = 0; + + /* get the qbm's write pointer */ + qof_wp = qof_base + (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) + & ((QOF_SIZE - 1) >> 3)); +#if 0 + printk("refill_sq: rp=%p new=%p wp=%p pres=[", + qof_rp, qof_new, qof_wp); + for (q = 0; q < NSENDQUEUES; ++q) + printk("%d ", qof_present[q]); + printk("]\n"); +#endif + + /* work out which send queues and aren't full */ + notfull = 0; + use_old = 0; + for (q = 0; q < NSENDQUEUES; ++q) { + sqp = MSC_IN(MSC_SQPTR0 + q * 8); + freew[q] = (EXTFIELD(sqp, MSC_SQP_RP) - EXTFIELD(sqp, MSC_SQP_WP) - 1) + & ((sqp & MSC_SQP_MODE)? 0x3f: 0x1f); + if (freew[q] > 0) + notfull |= 1 << (q + QOF_QUEUE_SH); + use_old += (freew[q] < qof_present[q])? freew[q]: qof_present[q]; + } + + /* + * If there are useful entries in the old part of the overflow + * queue, process them. + */ + kept_some = 0; + for (rp = qof_rp; rp < qof_new && use_old > 0; ++rp) { + if (rp->info & notfull) { + /* Here's one we can stuff back into the send queue */ + q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)]; + if (q < 0) { + printk("bad queue bits in qof info (%x) at %p\n", + rp->info, rp); + /* XXX just ignore this entry - should never happen */ + rp->info = 0; + continue; + } + MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data); + if (--freew[q] == 0) + notfull &= ~(1 << (q + QOF_QUEUE_SH)); + --qof_present[q]; + --use_old; + rp->info = 0; + } else if (!kept_some && rp->info != 0) { + qof_rp = rp; + kept_some = 1; + } + } + + /* Trim off any further already-used items. */ + if (!kept_some) { + for (; rp < qof_new; ++rp) { + if (rp->info) { + qof_rp = rp; + kept_some = 1; + break; + } + } + } + + /* + * Now process everything that's arrived since we last updated qof_new. + */ + for (rp = qof_new; rp < qof_wp; ++rp) { + if (rp->info == 0) + continue; + q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)]; + if (q < 0) { + printk("bad queue bits in qof info (%x) at %p\n", rp->info, rp); + /* XXX just ignore this entry - should never happen */ + rp->info = 0; + continue; + } + if (rp->info & notfull) { + /* Another one to stuff back into the send queue. */ + MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data); + if (--freew[q] == 0) + notfull &= ~(1 << (q + QOF_QUEUE_SH)); + rp->info = 0; + } else { + ++qof_present[q]; + if (!kept_some) { + qof_rp = rp; + kept_some = 1; + } + } + } + + /* Update state and the MSC queue-spill flags. */ + if (!kept_some) { + /* queue is empty; avoid unnecessary overflow interrupt later */ + qof_rp = qof_new = qof_base; + QBM_UPDATE_WP(mmu_v2p((unsigned long)qof_base)); + } else { + qof_new = qof_wp; + } + + sqc = MSC_IN(MSC_SQCTRL); + for (q = 0; q < NSENDQUEUES; ++q) + if (qof_present[q] == 0 && freew[q] > 0) + sqc &= ~(1 << (q + MSC_SQC_SPLF_SH)); + MSC_OUT(MSC_SQCTRL, sqc); +} + +/* + * Copy the valid entries from their current position + * in the queue overflow buffer to the beginning. + * This must be called with the send queue controller in THRU or BLOCKING mode. + */ +static void repack_qof(void) +{ + struct qof_elt *rp, *wp; + + wp = qof_base; + for (rp = qof_rp; rp < qof_new; ++rp) { + if (rp->info) { + if (rp > wp) + *wp = *rp; + ++wp; + } + } + qof_rp = qof_base; + qof_new = wp; + QBM_UPDATE_WP(wp); +} + +/* + * Copy all entries from their current position + * in the queue overflow buffer to the beginning. + * This must be called with the send queue controller in THRU or BLOCKING mode. + */ +static void shuffle_qof(void) +{ + int n; + + n = qof_new - qof_rp; + memmove(qof_base, qof_rp, n * sizeof(struct qof_elt)); + qof_rp = qof_base; + qof_new = qof_base + n; + QBM_UPDATE_WP(qof_new); +} + +static inline void handle_signal(int context,unsigned vaddr) +{ + int signum = (vaddr - MSC_REM_SIGNAL) >> PAGE_SHIFT; + int taskid = MPP_CTX_TO_TASK(context); + if (MPP_IS_PAR_TASK(taskid) && valid_task(task[taskid])) { + send_sig(signum,task[taskid],1); +#if DEBUG + printk("CID(%d) sent signal %d to task %d\n",mpp_cid(),signum,taskid); +#endif + } +} + + +/* + * fail a msc write operation. We use Pauls dirty tlb trick to avoide + * the msc hardware bugs + */ +static void fail_write(int context,int intr,unsigned vaddr) +{ + int tsk = MPP_CTX_TO_TASK(context); + int vpage = vaddr >> 12; +#if DEBUG + printk("fail write tsk=%d intr=%x vaddr=%x RMASREG=%x errproc=%x\n", + tsk,intr,vaddr,MSC_IN(MSC_RMASREG),MSC_IN(MSC_RHDERRPROC)); +#endif + + mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12), + vpage,context); + MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr); + + mc_tlb_unmap(vpage); + + if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) { + if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { + handle_signal(context,vaddr); + } else { + task[tsk]->tss.sig_address = vaddr; + task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING; + send_sig(SIGSEGV, task[tsk], 1); + } + } +} + +/* + * fail a msc read operation using the tlb trick */ +static void fail_read(int context,int intr,unsigned vaddr) +{ + int tsk = MPP_CTX_TO_TASK(context); +#if DEBUG + printk("fail read tsk=%d intr=%x\n",tsk,intr); +#endif + + mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12), + vaddr>>12,context); + MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr); + + mc_tlb_unmap(vaddr>>12); + + if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) { + if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { + handle_signal(context,vaddr); + } else { + task[tsk]->tss.sig_address = vaddr; + task[tsk]->tss.sig_desc = SUBSIG_NOMAPPING; + send_sig(SIGSEGV, task[tsk], 1); + } + } +} + +static void async_callback(int tsk,unsigned long vaddr,int write,int ret) +{ + unsigned flags; + save_flags(flags); cli(); + + msc_blocked--; + if (write) { + intr_mask &= ~(AP_INTR_REQ << MSC_INTR_RMASF_SH); + if (ret) { + fail_write(MPP_TASK_TO_CTX(tsk),MSC_INTR_RMASF_SH,vaddr); + MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH); + restore_flags(flags); + return; + } + MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASF_SH); + MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH); + } else { + intr_mask &= ~(AP_INTR_REQ << MSC_INTR_SMASF_SH); + if (ret) { + fail_read(MPP_TASK_TO_CTX(tsk),MSC_INTR_SMASF_SH,vaddr); + MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH); + restore_flags(flags); + return; + } + MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT); + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH); + MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH); + } + restore_flags(flags); +} + + + +static inline void msc_write_fault(void) +{ + unsigned context = MSC_IN(MSC_RMASREG) >> 20; + unsigned vaddr = MSC_IN(MSC_RMASTWP)<<12; + + if (context == SYSTEM_CONTEXT) { + fail_write(context,MSC_INTR_RMASF_SH,vaddr); + show_mapping_ctx(0,context,vaddr); + printk("ERROR: system write fault at %x\n",vaddr); + return; + } + + if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { + fail_write(context,MSC_INTR_RMASF_SH,vaddr); + return; + } + + if (MPP_IS_PAR_CTX(context)) { + int tsk = MPP_CTX_TO_TASK(context); + if (valid_task(task[tsk]) && task[tsk]->ringbuf) { + MSC_OUT(MSC_INTR, + AP_SET_INTR_MASK << MSC_INTR_RMASF_SH); + intr_mask |= (AP_INTR_REQ << MSC_INTR_RMASF_SH); +#if DEBUG + show_mapping_ctx(0,context,vaddr); +#endif + msc_blocked++; + async_fault(vaddr,1,tsk,async_callback); + return; + } + } + +#if DEBUG + printk("CID(%d) mas write fault context=%x vaddr=%x\n", + mpp_cid(),context,vaddr); +#endif + + fail_write(context,MSC_INTR_RMASF_SH,vaddr); +} + + +static inline void msc_read_fault(void) +{ + unsigned context = MSC_IN(MSC_SMASREG) >> 20; + unsigned vaddr = MSC_IN(MSC_SMASTWP)<<12; + + if (context == SYSTEM_CONTEXT) { + fail_read(context,MSC_INTR_SMASF_SH,vaddr); + show_mapping_ctx(0,context,vaddr); + printk("ERROR: system read fault at %x\n",vaddr); + return; + } + + if (MPP_IS_PAR_CTX(context)) { + int tsk = MPP_CTX_TO_TASK(context); + + if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) { + fail_read(context,MSC_INTR_SMASF_SH,vaddr); + return; + } + + if (valid_task(task[tsk]) && task[tsk]->ringbuf) { + MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_SMASF_SH); + intr_mask |= (AP_INTR_REQ << MSC_INTR_SMASF_SH); + msc_blocked++; + async_fault(vaddr,0,tsk,async_callback); + return; + } + } + +#if DEBUG + printk("CID(%d) mas read fault context=%x vaddr=%x\n", + mpp_cid(),context,vaddr); +#endif + + fail_read(context,MSC_INTR_SMASF_SH,vaddr); +} + + + +static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned intr, cnt, r; + + save_flags(flags); cli(); + + if (intr_counter++ == INTR_LIMIT) { + mask_all_interrupts(); + printk("too many MSC interrupts\n"); + restore_flags(flags); + return; + } + + intr = MSC_IN(MSC_INTR) & ~intr_mask; + +#if DEBUG + printk("CID(%d) msc_interrupt_9: intr = %x\n", mpp_cid(), intr); +#endif + + if (intr & (AP_INTR_REQ << MSC_INTR_RMASF_SH)) { + msc_write_fault(); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_SMASF_SH)) { + msc_read_fault(); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_RMASE_SH)) { + printk("recv mas error interrupt (write)\n"); + printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL)); + printk("rmasadr = %x %x\n", MSC_IN(MSC_RMASADR), + MSC_IN(MSC_RMASADR + 4)); + printk("rmastwp = %x\n", MSC_IN(MSC_RMASTWP)); + printk("rmasreg = %x\n", MSC_IN(MSC_RMASREG)); + r = MSC_IN(MSC_RMASREG); + if ((r & MSC_MASR_AVIO) || (r & MSC_MASR_CMD) != MSC_MASR_CMD_XFER) + /* throw away the rest of the incoming data */ + MSC_OUT(MSC_RHDERRPROC, 0); + /* clear the interrupt */ + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASE_SH); + } + + if (intr & (AP_INTR_REQ << MSC_INTR_SMASE_SH)) { + printk("send mas error interrupt (read)\n"); + printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL)); + printk("smasadr = %x %x\n", MSC_IN(MSC_SMASADR), + MSC_IN(MSC_SMASADR + 4)); + printk("smascnt = %x\n", MSC_IN(MSC_SMASCNT)); + printk("smastwp = %x\n", MSC_IN(MSC_SMASTWP)); + printk("smasreg = %x\n", MSC_IN(MSC_SMASREG)); + /* supply dummy data */ + cnt = MSC_IN(MSC_SMASCNT); + switch (MSC_IN(MSC_SMASREG) & MSC_MASR_CMD) { + case MSC_MASR_CMD_XFER: + MSC_OUT(MSC_HDGERRPROC, (EXTFIELD(cnt, MSC_SMCT_MCNT) + + EXTFIELD(cnt, MSC_SMCT_ICNT))); + break; + /* case remote read: */ + case MSC_MASR_CMD_FOP: + case MSC_MASR_CMD_CSI: + MSC_OUT(MSC_HDGERRPROC, 1); + break; + } + /* clear interrupt */ + MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH); + } + + restore_flags(flags); +} + +/* + * remove access to a tasks ring buffer + */ +void msc_unset_ringbuf(int i) +{ + int ctx = MSC_IN(ringbufs[i].rbmmode) & CTX_MASK; + int tsk = MPP_CTX_TO_TASK(ctx); + struct ringbuf_struct *rbuf; + +#if DEBUG + printk("msc_unset_ringbuf(%d) %x\n",i,ctx); +#endif + + MSC_OUT(ringbufs[i].rbmmode,NULL_CONTEXT); + if (ctx == SYSTEM_CONTEXT) { + rbuf = &system_ringbuf; + } else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && + valid_task(task[tsk]) && task[tsk]->ringbuf) { + rbuf = task[tsk]->ringbuf; + } else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && + valid_task(task[tsk]) && task[tsk]->aplib) { + rbuf = &system_ringbuf; + } else { + rbuf = &dummy_ringbuf; + } + + rbuf->write_ptr = MSC_IN(ringbufs[i].rbmbwp); +} + +static void msc_update_read_ptr(int context,int overflow) +{ + int i; + unsigned new_read_ptr; + + for (i=0;iringbuf) { + struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)]; + struct _kernel_cap_shared *_kernel; + unsigned soft_read_ptr; + unsigned octx; + + octx = apmmu_get_context(); + if (octx != context) + apmmu_set_context(context); + _kernel = (struct _kernel_cap_shared *)(RBUF_VBASE + RBUF_SHARED_PAGE_OFF); + soft_read_ptr = _kernel->rbuf_read_ptr; + if (octx != context) + apmmu_set_context(octx); + + if (overflow && MSC_IN(ringbufs[i].rbmrp) == soft_read_ptr) { + /* send them a SIGLOST and wipe their ring buffer */ + printk("ring buffer overflow for %s ctx=%x\n", + tsk->comm,context); + send_sig(SIGLOST,tsk,1); + soft_read_ptr--; + } + new_read_ptr = soft_read_ptr; + } else if (MPP_IS_PAR_CTX(context) && + valid_task(task[MPP_CTX_TO_TASK(context)]) && + task[MPP_CTX_TO_TASK(context)]->aplib) { + tnet_check_completion(); + if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr) + printk("system ringbuffer overflow\n"); + new_read_ptr = system_read_ptr; + } else { + dummy_read_ptr = MSC_IN(ringbufs[i].rbmrp) - 1; + new_read_ptr = dummy_read_ptr - 1; +#if DEBUG + if (overflow) + printk("reset dummy ring buffer for context %x\n", + context); +#endif + } + + + MSC_OUT(ringbufs[i].rbmrp,new_read_ptr); +} + +/* + * give a task one of the system ring buffers + * this is called on a context miss interrupt, so we can assume that + * the tasks context is not currently set in one of the ringbufs + */ +static void msc_set_ringbuf(int context) +{ + int i; + int ctx; + int mode; + unsigned write_ptr; + static unsigned next_ctx = 0; + struct ringbuf_struct *rbuf; + + if (context == SYSTEM_CONTEXT) { + rbuf = &system_ringbuf; + } else if (MPP_IS_PAR_CTX(context) && + valid_task(task[MPP_CTX_TO_TASK(context)]) && + task[MPP_CTX_TO_TASK(context)]->ringbuf) { + struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)]; + rbuf = tsk->ringbuf; + } else if (MPP_IS_PAR_CTX(context) && + valid_task(task[MPP_CTX_TO_TASK(context)]) && + task[MPP_CTX_TO_TASK(context)]->aplib) { + rbuf = &system_ringbuf; + } else { + /* use the dummy ring buffer */ + rbuf = &dummy_ringbuf; + } + + for (i=0;iwrite_ptr; + mode = (rbuf->order - 5) >> 1; + + MSC_OUT(ringbufs[i].rbmmode,context | (mode << 12)); + MSC_OUT(ringbufs[i].rbmbwp,write_ptr); + + if (rbuf == &system_ringbuf) { + MSC_OUT(ringbufs[i].rbmrp,system_read_ptr); + } else { + msc_update_read_ptr(context,0); + } + +#if DEBUG + printk("CID(%d) mapped ringbuf for context %d in slot %d\n", + mpp_cid(),context,i); +#endif +} + + +/* + * this is called when a task exits +*/ +void exit_msc(struct task_struct *tsk) +{ + int i; + + if (!MPP_IS_PAR_TASK(tsk->taskid)) + return; + +#if DEBUG + printk("exit_msc(%d) ctx=%d\n",tsk->taskid,tsk->mm->context); +#endif + + for (i=0;itaskid)) + msc_unset_ringbuf(i); + } + msc_switch_from_check(tsk); + + /* stop it receiving new-style messages */ + tsk->aplib = NULL; + + exit_ringbuf(tsk); +} + + +static void msc_sq_pause(void) +{ + MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) | MSC_SQC_PAUSE); + while (!(MSC_IN(MSC_SQCTRL) & MSC_SQC_STABLE)) /* wait for stable bit */ ; +} + +static void msc_sq_resume(void) +{ + MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) & ~MSC_SQC_PAUSE); +} + +static void msc_switch_from_check(struct task_struct *tsk) +{ + int user_count; + unsigned flags; + struct ringbuf_struct *rbuf = NULL; + int octx, ctx; + + if (valid_task(tsk) && tsk->ringbuf) + rbuf = tsk->ringbuf; + + /* it doesn't seem obvious why this field should contain count+1, + but it does */ + user_count = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1; + + /* check if the user queue count is != 0 */ + if (user_count == 0) return; + + if (!rbuf) + printk("switching from dead task\n"); + +#if 1 + printk("saving %d words MSC_QWORDCNT=%x\n", + user_count,MSC_IN(MSC_QWORDCNT)); +#endif + + /* bugger - we have to do some messy work */ + save_flags(flags); cli(); + + ctx = MPP_TASK_TO_CTX(tsk->taskid); + octx = apmmu_get_context(); + if (octx != ctx) + apmmu_set_context(ctx); + + msc_sq_pause(); + + /* remember the expected length of the command - usually (always?) 8 */ + if (rbuf) + rbuf->frag_len = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRLEN); + + /* pull words from the overflow first */ + if (MSC_IN(MSC_SQCTRL) & MSC_SQC_USERF) { + /* we have overflowed */ + struct qof_elt *qof_wp = qof_base + + (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) & ((QOF_SIZE - 1) >> 3)); + while (qof_wp != qof_rp && user_count) { + qof_wp--; + /* only grab elements in the user queue */ + if (qof_wp->info && log2tbl[EXTFIELD(qof_wp->info, QOF_QUEUE)] == 2) { + if (qof_wp->info & 1) { + printk("MSC: end bit set - yikes!\n"); + } + qof_wp->info = 0; + if (rbuf) { + rbuf->sq_fragment[--user_count] = qof_wp->data; + rbuf->frag_count++; + } + if (qof_wp < qof_new) + qof_present[2]--; + } + } +#if DEBUG + if (rbuf) + printk("pulled %d elements from overflow (%d left)\n", + rbuf->frag_count,user_count); +#endif + } + + /* then pull words direct from the msc ram */ + if (user_count) { + int wp = EXTFIELD(MSC_IN(MSC_SQPTR2),MSC_SQP_WP); + int i; + wp -= user_count; + if (wp < 0) wp += send_queues[2].size; + + for (i=0;isq_fragment[i + rbuf->frag_count] = + MSC_IN(MSC_SQRAM + (send_queues[2].base + wp2)*8); + } + + if (rbuf) + rbuf->frag_count += user_count; + + MSC_OUT(MSC_SQPTR2,INSFIELD(MSC_IN(MSC_SQPTR2),wp,MSC_SQP_WP)); +#if DEBUG + printk("saved %d words from msc ram\n",rbuf->frag_count); +#endif + } + + /* reset the user count to 1 */ + MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),1,MSC_QWDC_USRCNT)); + + msc_sq_resume(); + + if (octx != ctx) + apmmu_set_context(octx); + + restore_flags(flags); +} + +static void msc_switch_to_check(struct task_struct *tsk) +{ + int i; + unsigned flags; + int octx, ctx; + + if (!valid_task(tsk) || !tsk->ringbuf) + return; + + save_flags(flags); cli(); + + + ctx = MPP_TASK_TO_CTX(tsk->taskid); + octx = apmmu_get_context(); + if (octx != ctx) + apmmu_set_context(ctx); + + /* if the task we are switching to has no saved words then + we're finished */ + if (tsk->ringbuf->frag_count == 0) { + if (octx != ctx) + apmmu_set_context(octx); + restore_flags(flags); + return; + } + + +#if 1 + printk("frag fill MSC_QWORDCNT=%x frag_count=%d\n", + MSC_IN(MSC_QWORDCNT),tsk->ringbuf->frag_count); +#endif + + /* reset the user length */ + MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT), + tsk->ringbuf->frag_len, + MSC_QWDC_USRLEN)); + + /* push the words into the direct queue */ + for (i=0;iringbuf->frag_count;i++) + MSC_OUT(MSC_USER_DIRECT,tsk->ringbuf->sq_fragment[i]); + + /* reset the user count */ + MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT), + 1+tsk->ringbuf->frag_count, + MSC_QWDC_USRCNT)); + +#if DEBUG + printk("frag fill done MSC_QWORDCNT=%x\n", + MSC_IN(MSC_QWORDCNT)); +#endif + + tsk->ringbuf->frag_count = 0; + tsk->ringbuf->frag_len = 0; + if (octx != ctx) + apmmu_set_context(octx); + restore_flags(flags); +} + + + +void msc_switch_check(struct task_struct *tsk) +{ + static int last_task = 0; + + if (last_task == tsk->taskid) return; + + if (MPP_IS_PAR_TASK(last_task)) + msc_switch_from_check(task[last_task]); + + msc_switch_to_check(tsk); + + last_task = tsk->taskid; +} + +/* we want to try to avoid task switching while there are partial commands + in the send queues */ +int msc_switch_ok(void) +{ + if ((EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1)) + return 0; + + return 1; +} + +/* + * print out the state of the msc +*/ +static void msc_status(void) +{ + int i; + + printk("MSC_SQCTRL=%x\n",MSC_IN(MSC_SQCTRL)); + + for (i=0;i<5;i++) + printk("MSC_SQPTR%d=%x\n",i,MSC_IN(MSC_SQPTR0 + 8*i)); + printk("MSC_OPTADR=%x\n",MSC_IN(MSC_OPTADR)); + printk("MSC_MASCTRL=%x\n", MSC_IN(MSC_MASCTRL)); + printk("MSC_SMASADR=%x_%x\n", MSC_IN(MSC_SMASADR),MSC_IN(MSC_SMASADR + 4)); + printk("MSC_RMASADR=%x_%x\n", MSC_IN(MSC_RMASADR),MSC_IN(MSC_RMASADR + 4)); + printk("MSC_PID=%x\n",MSC_IN(MSC_PID)); + + printk("MSC_QWORDCNT=%x\n",MSC_IN(MSC_QWORDCNT)); + + printk("MSC_INTR=%x\n",MSC_IN(MSC_INTR)); + printk("MSC_CIDRANGE=%x\n",MSC_IN(MSC_CIDRANGE)); + printk("MSC_QBMPTR=%x\n",MSC_IN(MSC_QBMPTR)); + printk("MSC_SMASTWP=%x\n", MSC_IN(MSC_SMASTWP)); + printk("MSC_RMASTWP=%x\n", MSC_IN(MSC_RMASTWP)); + printk("MSC_SMASREG=%x\n", MSC_IN(MSC_SMASREG)); + printk("MSC_RMASREG=%x\n", MSC_IN(MSC_RMASREG)); + printk("MSC_SMASCNT=%x\n", MSC_IN(MSC_SMASCNT)); + printk("MSC_IRL=%x\n", MSC_IN(MSC_IRL)); + printk("MSC_SIMMCHK=%x\n", MSC_IN(MSC_SIMMCHK)); + + for (i=0;i<3;i++) { + printk("RBMBWP%d=%x\n",i,MSC_IN(ringbufs[i].rbmbwp)); + printk("RBMMODE%d=%x\n",i,MSC_IN(ringbufs[i].rbmmode)); + printk("RBMRP%d=%x\n",i,MSC_IN(ringbufs[i].rbmrp)); + } + + printk("DMA_GEN=%x\n",MSC_IN(DMA_GEN)); + + printk("qbm_full_counter=%d\n",qbm_full_counter); +} diff --git a/arch/sparc/ap1000/sync.c b/arch/sparc/ap1000/sync.c new file mode 100644 index 000000000000..455a67173ce4 --- /dev/null +++ b/arch/sparc/ap1000/sync.c @@ -0,0 +1,55 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* sync functions using the Tnet */ + +#include +#include +#include +#include + +extern int cap_cid0; +extern unsigned _ncel, _ncelx, _ncely, _cid; + +static volatile int sync_flags[MPP_NUM_TASKS]; + + +int ap_sync(int numcells, int *phys_map) +{ + int basecell; + int i,err; + int tsk = current->taskid; + + if (numcells < 2) return 0; + + if (!MPP_IS_PAR_TASK(tsk)) { + printk("nonparallel task %d called ap_sync\n",tsk); + return 0; + } + tsk -= MPP_TASK_BASE; + + basecell = phys_map[0]; + if (cap_cid0 == basecell) { + if ((err=wait_on_int(&sync_flags[tsk],numcells-1,5))) + return err; + sync_flags[tsk] = 0; + if (numcells == _ncel) { + ap_bput(0,0,0,&sync_flags[tsk],0); + } else { + for (i=1;i +#include +#include +#include +#include +#include +#include +#include + +#define INIT_TIM1 (781250/HZ) +#define INIT_TIM0 (781250/(10*HZ)) + +static unsigned long last_freerun; + +unsigned ap_freerun(void) +{ + return *((volatile unsigned long *)(MC_FREERUN + 4)); +} + +void ap_clear_clock_irq(void) +{ + MC_OUT(MC_INTR, AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH); + last_freerun = *((unsigned long *)(MC_FREERUN + 4)); + tnet_check_completion(); +#if 1 + if ((((unsigned)jiffies) % (HZ/4)) == 0) { + msc_timer(); + ap_xor_led(1); + bif_timer(); + ap_dbg_flush(); +#if 0 + bif_led_status(); +#endif + } +#endif +} + + +void ap_gettimeofday(struct timeval *xt) +{ + unsigned long d; + unsigned v; + unsigned long new_freerun; + + /* this is in 80ns units - we only use the low 32 bits + as 5mins is plenty for this stuff */ + d = new_freerun = *((unsigned long *)(MC_FREERUN + 4)); + + if (d < last_freerun) { + /* wraparound */ + d += ((~0) - last_freerun); + } else { + d -= last_freerun; + } + + /* convert to microseconds */ + v = ((d&0xffffff)*10)/125; + + /* only want microseconds/HZ */ + v = v%(1000000/HZ); + + xt->tv_usec += v; + + last_freerun = new_freerun; +} + + +static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long ip = instruction_pointer(regs); + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + if (ip < prof_len) + prof_buffer[ip]++; + } + MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); +} + +void ap_profile_init(void) +{ + if (prof_shift) { + printk("Initialising profiling with prof_shift=%d\n",(int)prof_shift); + MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH); + MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM0_SH); + } +} + +void ap_init_timers(void) +{ + extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs); + unsigned flags; + + printk("Initialising ap1000 timer\n"); + + save_flags(flags); cli(); + + request_irq(APTIM1_IRQ, + timer_interrupt, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", NULL); + + request_irq(APTIM0_IRQ, + profile_interrupt, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "profile", NULL); + + ap_clear_clock_irq(); + + MC_OUT(MC_ITIMER0,INIT_TIM0); + MC_OUT(MC_ITIMER1,INIT_TIM1); + MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH); + MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM1_SH); + MC_OUT(MC_INTR,AP_SET_INTR_MASK << MC_INTR_ITIM0_SH); + restore_flags(flags); +} diff --git a/arch/sparc/ap1000/tnet.c b/arch/sparc/ap1000/tnet.c new file mode 100644 index 000000000000..14a29ae7a0c1 --- /dev/null +++ b/arch/sparc/ap1000/tnet.c @@ -0,0 +1,709 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* routines to control the AP1000 Tnet interface */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* message types for system messages */ +#define TNET_IP 0 +#define TNET_IP_SMALL 1 +#define TNET_RPC 2 + +static struct { + int errors; + int alloc_errors; + int bytes_received; + int bytes_sent; + int packets_received; + int packets_sent; + int small_packets_received; + int small_packets_sent; +} tnet_stats; + +extern int cap_cid0; +extern int cap_ncel0; +static u_long xy_global_head; + +extern unsigned _ncel, _ncelx, _ncely, _cid, _cidx, _cidy; + +extern struct ringbuf_struct system_ringbuf; +extern u_long system_read_ptr; + +u_long system_recv_flag = 0; +static u_long system_recv_count = 0; + +int *tnet_rel_cid_table; + +static int dummy=1; + +#define TNET_IP_THRESHOLD 100 + +void tnet_check_completion(void); +static void reschedule(void); +static u_long tnet_add_completion(void (*fn)(int a1,...), + int a1,int a2); +static void tnet_info(void); + +static struct { + int shift; + void (*fn)(void); +} iports[4] = { + {MC_INTP_0_SH,tnet_check_completion}, + {MC_INTP_1_SH,reschedule}, + {MC_INTP_2_SH,NULL}, + {MC_INTP_3_SH,NULL}}; + +static inline int rel_cid(unsigned dst) +{ + unsigned dstx, dsty; + unsigned dx,dy; + + if (dst == _cid) return 0; + + dstx = dst % _ncelx; + dsty = dst / _ncelx; + if (dstx >= _cidx) + dx = dstx - _cidx; + else + dx = (_ncelx - _cidx) + dstx; + + if (dsty >= _cidy) + dy = dsty - _cidy; + else + dy = (_ncely - _cidy) + dsty; + + return (dx<<8) | dy; +} + +#define SAVE_PID() \ + unsigned long flags; \ + int saved_pid; \ + save_flags(flags); cli(); \ + saved_pid = MSC_IN(MSC_PID); \ + MSC_OUT(MSC_PID,SYSTEM_CONTEXT); + +#define RESTORE_PID() \ + MSC_OUT(MSC_PID,saved_pid); \ + restore_flags(flags); + + +void ap_put(int dest_cell,u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag) +{ + volatile u_long *entry; + SAVE_PID(); + + entry = (volatile u_long *)MSC_PUT_QUEUE_S; + + *entry = tnet_rel_cid_table[dest_cell]; + *entry = ((size+3) >> 2); + *entry = (u_long)remote_addr; + *entry = 0; + *entry = (u_long)dest_flag; + *entry = (u_long)local_flag; + *entry = (u_long)local_addr; + *entry = 0; + RESTORE_PID(); +} + +/* remote_addr is physical + local address is virtual + both flags are virtual */ +void ap_phys_put(int dest_cell,u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag) +{ + volatile u_long *entry; + SAVE_PID(); + + entry = (volatile u_long *)MSC_CPUT_QUEUE_S; + + *entry = tnet_rel_cid_table[dest_cell]; + *entry = ((size+3) >> 2); + *entry = (u_long)remote_addr; + *entry = 0; + *entry = (u_long)dest_flag; + *entry = (u_long)local_flag; + *entry = (u_long)local_addr; + *entry = 0; + RESTORE_PID(); +} + + +/* broadcast put - yeah! */ +void ap_bput(u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag) +{ + volatile u_long *entry = (volatile u_long *)MSC_XYG_QUEUE_S; + SAVE_PID(); + + *entry = xy_global_head; + *entry = ((size+3) >> 2); + *entry = (u_long)remote_addr; + *entry = 0; + *entry = (u_long)dest_flag; + *entry = (u_long)local_flag; + *entry = (u_long)local_addr; + *entry = 0; + RESTORE_PID(); +} + + +/* remote_addr is physical */ +void ap_phys_bput(u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag) +{ + volatile u_long *entry = (volatile u_long *)MSC_CXYG_QUEUE_S; + SAVE_PID(); + + *entry = xy_global_head; + *entry = ((size+3) >> 2); + *entry = (u_long)remote_addr; + *entry = 0; + *entry = (u_long)dest_flag; + *entry = (u_long)local_flag; + *entry = (u_long)local_addr; + *entry = 0; + RESTORE_PID(); +} + + + +void ap_get(int dest_cell,u_long local_addr,int size, + u_long remote_addr,u_long local_flag,u_long dest_flag) +{ + volatile u_long *entry; + SAVE_PID(); + + entry = (u_long *)MSC_GET_QUEUE_S; + + *entry = tnet_rel_cid_table[dest_cell]; + *entry = (size+3) >> 2; /* byte --> word */ + *entry = (u_long)local_addr; + *entry = 0; + *entry = (u_long)local_flag; + *entry = (u_long)dest_flag; + *entry = (u_long)remote_addr; + *entry = 0; + RESTORE_PID(); +} + + +/* local_addr is physical + remote_addr is virtual + both flags are virtual +*/ +void ap_phys_get(int dest_cell,u_long local_addr,int size, + u_long remote_addr,u_long local_flag,u_long dest_flag) +{ + volatile u_long *entry; + SAVE_PID(); + + entry = (u_long *)MSC_CGET_QUEUE_S; + + *entry = tnet_rel_cid_table[dest_cell]; + *entry = (size+3) >> 2; /* byte --> word */ + *entry = (u_long)local_addr; + *entry = 0; + *entry = (u_long)local_flag; + *entry = (u_long)dest_flag; + *entry = (u_long)remote_addr; + *entry = 0; + RESTORE_PID(); +} + + +/* + * copy a message from the ringbuffer - being careful of wraparound +*/ +static inline void tnet_copyin(unsigned *dest,unsigned *src,int size) +{ + unsigned *limit = (unsigned *)system_ringbuf.ringbuf + + (SYSTEM_RINGBUF_SIZE>>2); + int size1 = limit - src; + + if (size < size1) + size1 = size; + + size -= size1; + while (size1--) { + *dest++ = *src++; + } + src = system_ringbuf.ringbuf; + while (size--) { + *dest++ = *src++; + } +} + + +/* + put some data into a tasks ringbuffer. size is in words. + */ +static inline void memcpy_to_rbuf(unsigned tid,unsigned *msgp,unsigned size) +{ + struct aplib_struct *aplib; + unsigned octx, ctx; + struct task_struct *tsk; + unsigned room; + + tsk = task[tid]; + if (!tsk || !tsk->aplib) + return; + + octx = srmmu_get_context(); + ctx = MPP_TASK_TO_CTX(tid); + if (octx != ctx) + srmmu_set_context(ctx); + aplib = tsk->aplib; + + if (aplib->write_pointer < aplib->read_pointer) + room = aplib->read_pointer - (aplib->write_pointer+1); + else + room = aplib->ringbuf_size - + ((aplib->write_pointer+1)-aplib->read_pointer); + + if (room < size) { + send_sig(SIGLOST,tsk,1); + goto finished; + } + + tnet_copyin(&aplib->ringbuf[aplib->write_pointer], msgp, size); + + aplib->write_pointer += size; + if (aplib->write_pointer >= aplib->ringbuf_size) + aplib->write_pointer -= aplib->ringbuf_size; + + aplib->rbuf_flag1++; + +finished: + if (octx != ctx) + srmmu_set_context(octx); +} + + + +/* a aplib message has arrived on the system message queue - process + it immediately and return the number of bytes taken by the message in + the system ringbuffer + + Note that this function may be called from interrupt level + */ +static inline void aplib_system_recv(unsigned *msgp) +{ + unsigned tag = msgp[1]>>28; + unsigned size, tid; + + if (tag == RBUF_BIGSEND) { + aplib_bigrecv(msgp); + return; + } + + size = (msgp[0]&0xFFFFF); + tid = (msgp[1]&0x3FF); + + memcpy_to_rbuf(tid,msgp,size+2); +} + + +void tnet_ip_complete(struct sk_buff *skb,int from) +{ +#if IP_DEBUG + char *data = skb->data; + int i; + printk("CID(%d) tnet ip complete from %d\n",_cid,from); + + for (i=0;ilen;i+=4) + printk("(%08x)%c",*(int *)(data+i),i==32?'\n':' '); + printk("\n"); +#endif + /* ap_phys_put(from,(u_long)&dummy,4,MC_INTP_0,0,0); */ + bif_rx(skb); + tnet_stats.bytes_received += skb->len; + tnet_stats.packets_received++; +} + + +static void tnet_ip_recv(int cid,u_long *info) +{ + u_long flag; + u_long ipsize = info[1]; + u_long remote_addr = info[0]; + u_long remote_flag = info[2]; + struct sk_buff *skb = dev_alloc_skb(ipsize+8); + char *p; + + if (!skb) { + ap_put(cid,0,0,0,remote_flag,0); + ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0); + tnet_stats.alloc_errors++; + return; + } + + skb_reserve(skb,8); /* align on 16 byte boundary */ + + flag = tnet_add_completion(tnet_ip_complete,(int)skb,(int)cid); + + p = (char *)skb_put(skb,ipsize); +#if 0 +{ + static unsigned count=0; + if (count%500 == 0) + printk("CID(%d) fetching %d bytes from %x to %x\n", + _cid,ipsize,remote_addr,p); + count++; +} +#endif + ap_get(cid,p,ipsize,remote_addr,flag,remote_flag); + ap_phys_get(cid,MC_INTP_0,4,(u_long)&dummy,0,0); +#if IP_DEBUG + printk("CID(%d) ip packet of length %ld from %ld\n",_cid,ipsize,cid); +#endif +} + + +static void tnet_ip_recv_small(u_long *data,int size) +{ + struct sk_buff *skb = dev_alloc_skb(size+8); + if (skb) { + skb_reserve(skb,8); + tnet_copyin((unsigned *)skb_put(skb,size),(unsigned *)data,(size+3)>>2); + bif_rx(skb); + tnet_stats.bytes_received += size; + tnet_stats.packets_received++; + tnet_stats.small_packets_received++; + } else { + tnet_stats.alloc_errors++; + } +} + + +/* we've got an RPC from a remote cell */ +static void tnet_rpc_recv(u_long *data,int size) +{ + struct fnp { + void (*fn)(); + } fnp; + fnp = *(struct fnp *)data; + fnp.fn(data,size); +} + +/* + * receive messages from the system ringbuffer. We don't bother with + * all the niceities that are done in user space, we just always + * process the messages in order + */ +static inline void tnet_recv(void) +{ + unsigned flags; + u_long from,*data,fix,align,size1,size,type; + + if (system_recv_flag == system_recv_count) + return; + + save_flags(flags); cli(); + while (system_recv_flag != system_recv_count) { + u_long read_ptr = + (system_read_ptr + 1) % (SYSTEM_RINGBUF_SIZE>>5); + u_long *msgp = + ((u_long *)system_ringbuf.ringbuf) + (read_ptr<<3); + u_long tag = (msgp[1]>>28) & 0xF; + size1 = (msgp[0]&0xFFFFF)<<2; + + /* move our read pointer past this message */ + system_read_ptr = (system_read_ptr + + ((size1+8+31)>>5))%(SYSTEM_RINGBUF_SIZE>>5); + system_recv_count++; + + + if (tag != RBUF_SYSTEM) { + aplib_system_recv(msgp); + continue; + } + + from = msgp[0] >> 22; + data = msgp+2; + fix = (msgp[0]>>20)&3; + align = (msgp[1]>>26)&3; + size = ((size1 - align) & ~3) | fix; + type = (msgp[1]&0xFF); + + switch (type) { + case TNET_IP: + tnet_ip_recv(from,data); + break; + + case TNET_IP_SMALL: + tnet_ip_recv_small(data,size); + break; + + case TNET_RPC: + tnet_rpc_recv(data,size); + break; + + default: + tnet_stats.errors++; + printk("unknown Tnet type %ld\n",type); + } + +#if DEBUG + printk("CID(%d) recvd %d bytes of type %d read_ptr=%x\n", + _cid,size,type,system_read_ptr); +#endif + } + restore_flags(flags); +} + + +#define COMPLETION_LIST_LENGTH 256 + +static unsigned completion_list_rp = 0; +static unsigned completion_list_wp = 0; + +static volatile struct completion_struct { + u_long flag; + void (*fn)(int a1,...); + u_long args[2]; +} completion_list[COMPLETION_LIST_LENGTH]; + + +void tnet_check_completion(void) +{ + struct completion_struct *cs; + unsigned flags; + + tnet_recv(); + + if (completion_list[completion_list_rp].flag != 2) + return; + + save_flags(flags); cli(); + + while (completion_list[completion_list_rp].flag == 2) { + cs = &completion_list[completion_list_rp]; + cs->flag = 0; + if (++completion_list_rp == COMPLETION_LIST_LENGTH) + completion_list_rp = 0; + + restore_flags(flags); + + cs->fn(cs->args[0],cs->args[1]); + + if (completion_list[completion_list_rp].flag != 2) + return; + + save_flags(flags); cli(); + } + + restore_flags(flags); +} + + +static u_long tnet_add_completion(void (*fn)(int a1,...),int a1,int a2) +{ + unsigned flags; + struct completion_struct *cs; + + save_flags(flags); cli(); + + while (completion_list[completion_list_wp].flag != 0) + tnet_check_completion(); + + cs = &completion_list[completion_list_wp]; + + if (++completion_list_wp == COMPLETION_LIST_LENGTH) + completion_list_wp = 0; + + restore_flags(flags); + + cs->flag = 1; + cs->fn = fn; + cs->args[0] = a1; + cs->args[1] = a2; + + return (u_long)&cs->flag; +} + + +/* + * send a message to the tnet ringuffer on another cell. When the send has + * completed call fn with the args supplied + */ +static void tnet_send(long cid,long type,char *src_addr,long byteSize, + int immediate,u_long flag) +{ + int wordSize; + int byteAlign, byteFix; + u_long src; + u_long info1, info2; + volatile u_long *entry = (volatile u_long *)MSC_SEND_QUEUE_S; + SAVE_PID(); + + byteAlign = ((u_long)src_addr) & 0x3; + byteFix = byteSize & 0x3; + + src = (u_long)src_addr & ~3; + + wordSize = (byteSize + byteAlign + 3) >> 2; + + info1 = (_cid << 22) | (byteFix << 20) | wordSize; + info2 = (RBUF_SYSTEM<<28) | (byteAlign << 26) | type; + + *entry = tnet_rel_cid_table[cid]; + *entry = wordSize; + *entry = (u_long)&system_recv_flag; + *entry = flag; + *entry = (u_long)src; + *entry = 0; + *entry = info1; + *entry = info2; + RESTORE_PID(); + + ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0); + if (immediate && flag) + ap_phys_put(_cid,(u_long)&dummy,4,MC_INTP_0,0,0); +} + + +static void free_skb(struct sk_buff *skb, int op) +{ + dev_kfree_skb(skb,op); +} + +void tnet_send_ip(int cid,struct sk_buff *skb) +{ + char *data = skb->data + sizeof(struct cap_request); + int size = skb->len - sizeof(struct cap_request); + u_long flag; +#if IP_DEBUG + int i; + for (i=0;i TNET_IP_THRESHOLD) { + 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); + tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0); + } else { + flag = tnet_add_completion(free_skb, + (int)skb,(int)FREE_WRITE); + tnet_send(cid,TNET_IP_SMALL,data,size,0,flag); + tnet_stats.small_packets_sent++; + } + tnet_stats.packets_sent++; + tnet_stats.bytes_sent += size; +#if IP_DEBUG + printk("CID(%d) sent IP of size %d to %d\n",_cid,size,cid); +#endif +} + +static void reschedule(void) +{ + need_resched = 1; + mark_bh(TQUEUE_BH); +} + + +/* make a remote procedure call + If free is set then free the data after sending it + The first element of data is presumed to be a function pointer +*/ +int tnet_rpc(int cell,char *data,int size,int free) +{ + unsigned flag=0; + + if (free) { + flag = tnet_add_completion(kfree,data,0); + } + + tnet_send(cell,TNET_RPC,data,size,0,flag); + return 0; +} + + +static void iport_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int i; + u_long intr = MC_IN(MC_INTR_PORT); + + for (i=0;i<4;i++) { + if (intr & (AP_INTR_REQ << iports[i].shift)) { + MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift); + if (iports[i].fn) iports[i].fn(); + } + } +} + + +void ap_tnet_init(void) +{ + int i; + + bif_add_debug_key('T',tnet_info,"Tnet status"); + + memset(completion_list,0,sizeof(completion_list)); + + request_irq(APIPORT_IRQ, iport_irq, SA_INTERRUPT, "iport", 0); + + for (i=0;i<4;i++) { + MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift); + MC_OUT(MC_INTR_PORT,AP_CLR_INTR_MASK << iports[i].shift); + } + + + tnet_rel_cid_table = (int *)kmalloc(sizeof(int)*_ncel,GFP_ATOMIC); + for (i=0;i<_ncel;i++) + tnet_rel_cid_table[i] = rel_cid(i); + + if(_cid == 0) { + xy_global_head = (((_ncelx -1) << 8) & 0xff00) | + ((_ncely - 1) & 0xff); + } + else { + for(i = 1; i < _ncel; i *= 2){ + if(i & _cid) { + int rcidx = (_cid-i)%_ncelx - _cid%_ncelx; + int rcidy = (_cid-i)/_ncelx - _cid/_ncelx; + xy_global_head = ((rcidx << 8) & 0xff00) | + (rcidy & 0xff); + break; + } + } + } +} + +static void tnet_info(void) +{ + struct completion_struct *cs; + + printk( + "errors=%d alloc_errors=%d +bytes_received=%d bytes_sent=%d +packets_received=%d packets_sent=%d +small_received=%d small_sent=%d +", + tnet_stats.errors, tnet_stats.alloc_errors, + tnet_stats.bytes_received, + tnet_stats.bytes_sent, tnet_stats.packets_received, + tnet_stats.packets_sent, tnet_stats.small_packets_received, + tnet_stats.small_packets_sent); + + printk("recv_flag=%d recv_count=%d read_ptr=%d\n", + system_recv_flag,system_recv_count,system_read_ptr); + printk("completion_list_rp=%d completion_list_wp=%d\n", + completion_list_rp,completion_list_wp); +} diff --git a/arch/sparc/ap1000/util.c b/arch/sparc/ap1000/util.c new file mode 100644 index 000000000000..18a65c53874d --- /dev/null +++ b/arch/sparc/ap1000/util.c @@ -0,0 +1,436 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* general utility functions for the AP1000 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APLOG 0 + +struct cap_init cap_init; + +/* find what cell id we are running on */ +int mpp_cid(void) +{ + return(BIF_IN(BIF_CIDR1)); +} + +/* find how many cells there are */ +int mpp_num_cells(void) +{ + return(cap_init.numcells); +} + +/* this can be used to ensure some data is readable before DMAing + it. */ +int ap_verify_data(char *d,int len) +{ + int res = 0; + while (len--) res += *d++; + return res; +} + +/* How many bogo mips in the entire machine +Dont worry about float because when it gets this big, its irrelevant */ +int mpp_agg_bogomips(void) +{ + return mpp_num_cells()*loops_per_sec/500000; /* cheat in working it out */ +} + +/* Puts multiprocessor configuration info into a buffer */ +int get_mppinfo(char *buffer) +{ + return sprintf(buffer, + "Machine Type:\t\t: %s\nNumber of Cells\t\t: %d\nAggregate BogoMIPS\t: %d\n", + "Fujitsu AP1000+", + mpp_num_cells(), + mpp_agg_bogomips()); +} + +#if APLOG +static int do_logging = 0; + + +void ap_log(char *buf,int len) +{ +#define LOG_MAGIC 0x8736526 + static char *logbase; + static char *logptr; + static int logsize = 1024; + int l,i; + + if (buf == NULL && len == -1) { + logbase = kmalloc(logsize + 8,GFP_ATOMIC); + + if (!logbase) { + printk("log init failed\n"); + return; + } + for (i=0;i len) l = len; + memcpy(logptr,buf,l); + len -= l; + logptr += l; + if (logptr == logbase + logsize) + logptr = logbase; + } + *(int *)(logbase - 4) = (logptr - logbase); +} +#endif + +int ap_current_uid = -1; + +/* set output only to a particular uid */ +void ap_set_user(int uid) +{ + ap_current_uid = uid; +} + +/* write some data to a filedescriptor on the front end */ +int ap_write(int fd,char *buf,int nbytes) +{ + struct cap_request req; + + if (nbytes == 0) return 0; + +#if APLOG + ap_log(buf,nbytes); + + if (buf[0] == '|') return nbytes; +#endif + + req.cid = mpp_cid(); + req.type = REQ_WRITE; + req.size = nbytes + sizeof(req); + req.data[0] = fd; + if (ap_current_uid == -1 && current && current->pid) { + req.data[1] = current->uid; + } else { + req.data[1] = ap_current_uid; + } + req.header = MAKE_HEADER(HOST_CID); + + bif_queue(&req,buf,nbytes); + + return(nbytes); +} + +/* write one character to stdout on the front end */ +int ap_putchar(char c) +{ + struct cap_request req; + +#if APLOG + ap_log(&c,1); +#endif + + req.cid = mpp_cid(); + req.type = REQ_PUTCHAR; + req.size = sizeof(req); + req.data[0] = c; + req.header = MAKE_HEADER(HOST_CID); + + bif_queue(&req,0,0); + + return(0); +} + +/* start the debugger (kgdb) on this cell */ +void ap_start_debugger(void) +{ + static int done = 0; + extern void set_debug_traps(void); + extern void breakpoint(void); + if (!done) + set_debug_traps(); + done = 1; + breakpoint(); +} + +void ap_panic(char *msg,int a1,int a2,int a3,int a4,int a5) +{ + ap_led(0xAA); + printk(msg,a1,a2,a3,a4,a5); + ap_start_debugger(); +} + +void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5) +{ + printk(msg,a1,a2,a3,a4,a5); + /* bif_queue_flush(); */ +} + +/* get the command line arguments from the front end */ +void ap_getbootargs(char *buf) +{ + struct cap_request req; + int size; + + req.cid = mpp_cid(); + req.type = REQ_GETBOOTARGS; + req.size = sizeof(req); + req.header = MAKE_HEADER(HOST_CID); + + write_bif_polled((char *)&req,sizeof(req),NULL,0); + + ap_wait_request(&req,REQ_GETBOOTARGS); + + size = req.size - sizeof(req); + if (size == 0) + buf[0] = '\0'; + else { + read_bif(buf, size); + } + + req.cid = mpp_cid(); + req.type = REQ_INIT; + req.size = sizeof(req); + req.header = MAKE_HEADER(HOST_CID); + + write_bif_polled((char *)&req,sizeof(req),NULL,0); + + ap_wait_request(&req,REQ_INIT); + + if (req.size != sizeof(req)) + read_bif((char *)&cap_init,req.size - sizeof(req)); + if ((req.size - sizeof(req)) != sizeof(cap_init)) + printk("WARNING: Init structure is wrong size, recompile util.c\n"); + + if (cap_init.gdbcell == mpp_cid()) + ap_start_debugger(); + + printk("Got command line arguments from server\n"); +} + +/* a useful utility for debugging pagetable setups */ +void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm) +{ + unsigned *pgtable; + int entry[3]; + int level = 0; + + if (!ctp) ctp = (unsigned *)mmu_p2v(srmmu_get_ctable_ptr()); + + printk("ctp=0x%x ",(int)ctp); + + pgtable = ctp + context; + + /* get the virtual page */ + Vm = Vm>>12; + + printk("Vm page 0x%x is ",Vm); + + entry[0] = Vm>>12; + entry[1] = (Vm>>6) & 0x3f; + entry[2] = Vm & 0x3f; + + while (1) { + +#if 1 + printk("(%08x) ",pgtable[0]); +#endif + + if ((pgtable[0] & 3) == 2) { + printk("mapped at level %d to 0x%x\n",level,pgtable[0]>>8); + return; + } + + if ((pgtable[0] & 3) == 0) { + printk("unmapped at level %d\n",level); + return; + } + + if ((pgtable[0] & 3) == 3) { + printk("invalid at level %d\n",level); + return; + } + + if ((pgtable[0] & 3) == 1) { + pgtable = (unsigned *)(((pgtable[0]>>2)<<6)|0xf0000000); + pgtable += entry[level]; + level++; + } + } +} + + + +static unsigned char current_led = 0; + +void ap_led(unsigned char d) +{ + unsigned paddr = 0x1000; + unsigned word = 0xff & ~d; + current_led = d; + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (word), "r" (paddr), "i" (0x2c) : + "memory"); +} + +void ap_xor_led(unsigned char d) +{ + ap_led(current_led ^ d); +} + +void ap_set_led(unsigned char d) +{ + ap_led(current_led | d); +} + +void ap_unset_led(unsigned char d) +{ + ap_led(current_led & ~d); +} + + +void kbd_put_char(char c) +{ + ap_putchar(c); +} + + +void ap_enter_irq(int irq) +{ + unsigned char v = current_led; + switch (irq) { + case 2: v |= (1<<1); break; + case 4: v |= (1<<2); break; + case 8: v |= (1<<3); break; + case 9: v |= (1<<4); break; + case 10: v |= (1<<5); break; + case 11: v |= (1<<6); break; + default: v |= (1<<7); break; + } + ap_led(v); +} + +void ap_exit_irq(int irq) +{ + unsigned char v = current_led; + switch (irq) { + case 2: v &= ~(1<<1); break; + case 4: v &= ~(1<<2); break; + case 8: v &= ~(1<<3); break; + case 9: v &= ~(1<<4); break; + case 10: v &= ~(1<<5); break; + case 11: v &= ~(1<<6); break; + default: v &= ~(1<<7); break; + } + ap_led(v); +} + + +static struct wait_queue *timer_wait = NULL; + +static void wait_callback(unsigned long _ignored) +{ + wake_up(&timer_wait); +} + +/* wait till x == *p */ +int wait_on_int(volatile int *p,int x,int interval) +{ + struct timer_list *timer = kmalloc(sizeof(*timer),GFP_KERNEL); + if (!timer) panic("out of memory in wait_on_int()\n"); + timer->next = NULL; + timer->prev = NULL; + timer->data = 0; + timer->function = wait_callback; + while (*p != x) { + timer->expires = jiffies + interval; + add_timer(timer); + interruptible_sleep_on(&timer_wait); + del_timer(timer); + if (current->signal & ~current->blocked) + return -EINTR; + } + kfree_s(timer,sizeof(*timer)); + return 0; +} + + +/* an ugly hack to get nfs booting from a central cell to work */ +void ap_nfs_hook(unsigned long server) +{ + unsigned cid = server - cap_init.baseIP; + if (cid < cap_init.bootcid + cap_init.numcells && + cid != mpp_cid()) { + unsigned end = jiffies + 20*HZ; + /* we are booting from another cell */ + printk("waiting for the master cell\n"); + while (jiffies < end) ; + printk("continuing\n"); + } +} + +/* convert a IP address to a cell id */ +int ap_ip_to_cid(u_long ip) +{ + unsigned cid; + + if ((ip & cap_init.netmask) != (cap_init.baseIP & cap_init.netmask)) + return -1; + + if ((ip & ~cap_init.netmask) == AP_ALIAS_IP) + cid = cap_init.bootcid; + else + cid = ip - cap_init.baseIP; + if (cid >= cap_init.bootcid + cap_init.numcells) + return -1; + return cid; +} + + +void ap_reboot(char *bootstr) +{ + printk("cell(%d) - don't know how to reboot\n",mpp_cid()); + sti(); + while (1) ; +} + + +void dumb_memset(char *buf,char val,int len) +{ + while (len--) *buf++ = val; +} + +void ap_init_time(struct timeval *xtime) +{ + xtime->tv_sec = cap_init.init_time; + xtime->tv_usec = 0; +} diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 73de5c34e95a..fee858a172cf 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.31 1996/12/18 06:18:35 tridge Exp $ +# $Id: config.in,v 1.32 1997/01/25 23:10:12 ecd Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -126,7 +126,7 @@ if [ "$CONFIG_NET" = "y" ]; then bool ' Keepalive and linefill' CONFIG_SLIP_SMART bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 fi - bool 'Sun LANCE support' CONFIG_SUNLANCE + tristate 'Sun LANCE support' CONFIG_SUNLANCE tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL tristate 'Sun QuadEthernet support' CONFIG_SUNQE tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 3730c64a7833..0317f9f7ba91 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -11,7 +11,7 @@ CONFIG_EXPERIMENTAL=y # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set +CONFIG_MODVERSIONS=y CONFIG_KERNELD=y # @@ -114,6 +114,7 @@ CONFIG_IPX=m CONFIG_ATALK=m # CONFIG_AX25 is not set CONFIG_X25=m +# CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set @@ -184,6 +185,7 @@ CONFIG_ISO9660_FS=y CONFIG_HPFS_FS=m CONFIG_SYSV_FS=m CONFIG_AFFS_FS=m +CONFIG_ROMFS_FS=m CONFIG_AMIGA_PARTITION=y CONFIG_UFS_FS=y CONFIG_BSD_DISKLABEL=y diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index c6c542d512f7..10f839b8c47c 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.35 1996/11/13 05:09:15 davem Exp $ +# $Id: Makefile,v 1.37 1997/01/06 06:52:15 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -27,7 +27,7 @@ else endif -all: kernel.o head.o initobj.o finitobj.o +all: kernel.o head.o O_TARGET := kernel.o IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o @@ -41,7 +41,7 @@ O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \ OX_OBJS := sparc_ksyms.o ifdef SMP -O_OBJS += trampoline.o smp.o rirq.o +O_OBJS += trampoline.o smp.o endif ifdef CONFIG_SUN_AUXIO @@ -60,11 +60,4 @@ head.o: head.S endif -initobj.o: initobj.S - $(CC) -D__ASSEMBLY__ -ansi -c initobj.S -o initobj.o - -finitobj.o: initobj.S - $(CC) -D__ASSEMBLY__ -ansi -c finitobj.S -o finitobj.o - - include $(TOPDIR)/Rules.make diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 72168f594a03..3f5beade77d4 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.129 1996/12/30 00:31:07 davem Exp $ +/* $Id: entry.S,v 1.131 1997/01/12 09:06:55 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -54,7 +54,6 @@ in_trap_handler: C_LABEL(trap_low): rd %wim, %l3 SAVE_ALL - ENTER_SYSCALL sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 @@ -246,7 +245,6 @@ floppy_overrun: floppy_dosoftint: rd %wim, %l3 SAVE_ALL - ENTER_IRQ /* Set all IRQs off. */ or %l0, PSR_PIL, %l4 @@ -257,10 +255,9 @@ floppy_dosoftint: mov 11, %o0 ! floppy irq level (unused anyway) mov %g0, %o1 ! devid is not used in fast interrupts - call C_LABEL(floppy_interrupt) + call C_LABEL(sparc_floppy_irq) add %sp, REGWIN_SZ, %o2 ! struct pt_regs *regs - LEAVE_IRQ RESTORE_ALL #endif /* (CONFIG_BLK_DEV_FD) */ @@ -269,7 +266,6 @@ floppy_dosoftint: .globl bad_trap_handler bad_trap_handler: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -290,27 +286,6 @@ bad_trap_handler: .globl real_irq_entry real_irq_entry: SAVE_ALL -#ifdef __SMP__ - cmp %l7, 9 - bne 1f - nop - - GET_PROCESSOR_MID(l4, l5) - set C_LABEL(sun4m_interrupts), %l5 - ld [%l5], %l5 - sethi %hi(0x02000000), %l6 - sll %l4, 12, %l4 - add %l5, %l4, %l5 - ld [%l5], %l4 - andcc %l4, %l6, %g0 - be 1f - nop - - b,a linux_trap_ipi9_sun4m - -1: -#endif - ENTER_IRQ #ifdef __SMP__ cmp %l7, 13 @@ -335,14 +310,9 @@ real_irq_entry: #endif - /* start atomic operation with respect to software interrupts */ - sethi %hi(C_LABEL(intr_count)), %l6 - ld [%l6 + %lo(C_LABEL(intr_count))], %l5 or %l0, PSR_PIL, %g2 - add %l5, 0x1, %l4 wr %g2, 0x0, %psr WRITE_PAUSE - st %l4, [%l6 + %lo(C_LABEL(intr_count))] wr %g2, PSR_ET, %psr WRITE_PAUSE mov %l7, %o0 ! irq level @@ -350,8 +320,7 @@ real_irq_entry: add %sp, REGWIN_SZ, %o1 ! pt_regs ptr wr %l0, PSR_ET, %psr WRITE_PAUSE - st %l5, [%l6 + %lo(C_LABEL(intr_count))] - LEAVE_IRQ + RESTORE_ALL /* This routine handles illegal instructions and privileged @@ -361,7 +330,6 @@ real_irq_entry: .globl bad_instruction bad_instruction: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -378,7 +346,6 @@ bad_instruction: .globl priv_instruction priv_instruction: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -400,7 +367,6 @@ mna_handler: nop SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -413,7 +379,6 @@ mna_handler: mna_fromuser: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -429,7 +394,6 @@ mna_fromuser: .globl fpd_trap_handler fpd_trap_handler: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -469,7 +433,6 @@ fpe_trap_handler: 2: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -487,7 +450,6 @@ fpe_trap_handler: .globl do_tag_overflow do_tag_overflow: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -505,7 +467,6 @@ do_tag_overflow: .globl do_watchpoint do_watchpoint: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -523,7 +484,6 @@ do_watchpoint: .globl do_reg_access do_reg_access: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -541,7 +501,6 @@ do_reg_access: .globl do_cp_disabled do_cp_disabled: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -559,7 +518,6 @@ do_cp_disabled: .globl do_bad_flush do_bad_flush: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -577,7 +535,6 @@ do_bad_flush: .globl do_cp_exception do_cp_exception: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -595,7 +552,6 @@ do_cp_exception: .globl do_hw_divzero do_hw_divzero: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -612,7 +568,6 @@ do_hw_divzero: .globl do_flush_windows do_flush_windows: SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -683,7 +638,6 @@ setcc_trap_handler: .globl linux_trap_nmi_sun4c linux_trap_nmi_sun4c: SAVE_ALL - ENTER_SYSCALL /* Ugh, we need to clear the IRQ line. This is now * a very sun4c specific trap handler... @@ -718,46 +672,9 @@ linux_trap_nmi_sun4c: RESTORE_ALL #ifdef __SMP__ - - .align 4 - .globl linux_trap_ipi9_sun4m -linux_trap_ipi9_sun4m: - sethi %hi(0x02000000), %o2 - GET_PROCESSOR_MID(o0, o1) - set C_LABEL(sun4m_interrupts), %l5 - ld [%l5], %o5 - sll %o0, 12, %o0 - add %o5, %o0, %o5 - st %o2, [%o5 + 4] - WRITE_PAUSE - - ld [%o5], %g0 - WRITE_PAUSE - - /* IRQ's off else we deadlock. */ - or %l0, PSR_PIL, %l4 - wr %l4, 0x0, %psr - WRITE_PAUSE - - wr %l4, PSR_ET, %psr - WRITE_PAUSE - - call C_LABEL(smp_message_irq) - nop - - RESTORE_ALL_FASTIRQ - .align 4 .globl linux_trap_ipi13_sun4m linux_trap_ipi13_sun4m: - /* NOTE: real_irq_entry saved state and grabbed klock already. */ - - /* start atomic operation with respect to software interrupts */ - sethi %hi(C_LABEL(intr_count)), %l4 - ld [%l4 + %lo(C_LABEL(intr_count))], %l5 - add %l5, 0x1, %l5 - st %l5, [%l4 + %lo(C_LABEL(intr_count))] - sethi %hi(0x20000000), %o2 GET_PROCESSOR_MID(o0, o1) set C_LABEL(sun4m_interrupts), %l5 @@ -781,12 +698,6 @@ linux_trap_ipi13_sun4m: call C_LABEL(smp_reschedule_irq) nop - sethi %hi(C_LABEL(intr_count)), %l4 - ld [%l4 + %lo(C_LABEL(intr_count))], %l5 - sub %l5, 0x1, %l5 - st %l5, [%l4 + %lo(C_LABEL(intr_count))] - - LEAVE_IRQ RESTORE_ALL .align 4 @@ -829,7 +740,7 @@ linux_trap_ipi15_sun4m: ld [%l5], %g0 WRITE_PAUSE - RESTORE_ALL_FASTIRQ + RESTORE_ALL 1: sethi %hi(0x80000000), %o2 @@ -855,7 +766,8 @@ linux_trap_ipi15_sun4m: call C_LABEL(smp_message_irq) nop - RESTORE_ALL_FASTIRQ + b ret_trap_lockless_ipi + clr %l6 #endif @@ -1104,7 +1016,6 @@ C_LABEL(num_context_patch2): sun4c_fault_fromuser: SAVE_ALL - ENTER_SYSCALL mov %l7, %o1 ! Decode the info from %l7 mov %l7, %o2 @@ -1139,7 +1050,6 @@ C_LABEL(srmmu_fault): or %l6, %l7, %l7 ! l7 = [addr,write,txtfault] SAVE_ALL - ENTER_SYSCALL mov %l7, %o1 mov %l7, %o2 @@ -1355,6 +1265,20 @@ C_LABEL(ret_from_syscall): b C_LABEL(ret_sys_call) ld [%sp + REGWIN_SZ + PT_I0], %o0 +#ifdef __SMP__ + .globl C_LABEL(ret_from_smpfork) +C_LABEL(ret_from_smpfork): + mov NO_PROC_ID, %o5 + sethi %hi(C_LABEL(klock_info)), %o4 + or %o4, %lo(C_LABEL(klock_info)), %o4 + stb %o5, [%o4 + 1] + stb %g0, [%o4 + 0] + wr %l0, PSR_ET, %psr + WRITE_PAUSE + b C_LABEL(ret_sys_call) + ld [%sp + REGWIN_SZ + PT_I0], %o0 +#endif + /* Linux native and SunOS system calls enter here... */ .align 4 .globl linux_sparc_syscall @@ -1372,7 +1296,6 @@ linux_sparc_syscall: syscall_is_too_hard: SAVE_ALL_HEAD rd %wim, %l3 - ENTER_SYSCALL wr %l0, PSR_ET, %psr mov %i0, %o0 @@ -1462,7 +1385,6 @@ solaris_syscall: 1: SAVE_ALL_HEAD rd %wim, %l3 - ENTER_SYSCALL wr %l0, PSR_ET, %psr nop @@ -1535,7 +1457,6 @@ bsd_syscall: bsd_is_too_hard: rd %wim, %l3 SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -1703,7 +1624,6 @@ C_LABEL(udelay): breakpoint_trap: rd %wim,%l3 SAVE_ALL - ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE diff --git a/arch/sparc/kernel/finitobj.S b/arch/sparc/kernel/finitobj.S deleted file mode 100644 index e75694d67d8e..000000000000 --- a/arch/sparc/kernel/finitobj.S +++ /dev/null @@ -1,9 +0,0 @@ -#if defined (__svr4__) || defined (__ELF__) - - .section ".text.init",#alloc,#execinstr - .globl text_init_end -text_init_end: - .section ".data.init",#alloc,#write - .globl data_init_end -data_init_end: -#endif diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index 8484eb4b785b..35b0a6e0243f 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.76 1996/12/30 00:31:09 davem Exp $ +/* $Id: head.S,v 1.78 1997/01/06 06:52:20 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,7 @@ #include #include #include +#include .data /* @@ -973,8 +974,8 @@ sun4c_continue_boot: mov 0, %fp /* And for good luck */ /* Zero out our BSS section. */ - set C_LABEL(edata) , %o0 ! First address of BSS - set C_LABEL(end) , %o1 ! Last address of BSS + set C_LABEL(__bss_start) , %o0 ! First address of BSS + set C_LABEL(end) , %o1 ! Last address of BSS add %o0, 0x1, %o0 1: stb %g0, [%o0] @@ -1052,17 +1053,6 @@ sun4c_continue_boot: PATCH_INSN(rtrap_7win_patch4, rtrap_patch4) PATCH_INSN(rtrap_7win_patch5, rtrap_patch5) -#ifdef __SMP__ - - /* Patch for returning from an ipi... */ - PATCH_INSN(rirq_7win_patch1, rirq_patch1) - PATCH_INSN(rirq_7win_patch2, rirq_patch2) - PATCH_INSN(rirq_7win_patch3, rirq_patch3) - PATCH_INSN(rirq_7win_patch4, rirq_patch4) - PATCH_INSN(rirq_7win_patch5, rirq_patch5) - -#endif - /* Patch for killing user windows from the register file. */ PATCH_INSN(kuw_patch1_7win, kuw_patch1) @@ -1201,3 +1191,8 @@ C_LABEL(lvl14_save): .word 0 .word t_irq14 + .section ".fixup",#alloc,#execinstr + .globl __ret_efault +__ret_efault: + ret + restore %g0, -EFAULT, %o0 diff --git a/arch/sparc/kernel/initobj.S b/arch/sparc/kernel/initobj.S deleted file mode 100644 index c55a8a19faae..000000000000 --- a/arch/sparc/kernel/initobj.S +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#if defined (__svr4__) || defined (__ELF__) - - .section ".text.init",#alloc,#execinstr - .globl text_init_begin -text_init_begin: - .section ".data.init",#alloc,#write - .globl data_init_begin -data_init_begin: -#endif - - .section ".fixup",#alloc,#execinstr - .globl __ret_efault -__ret_efault: - ret - restore %g0, -EFAULT, %o0 - diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 600d5ad9b6b2..0f089c41d288 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.58 1996/12/18 06:33:41 tridge Exp $ +/* $Id: irq.c,v 1.59 1997/01/06 06:52:21 davem 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 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -204,6 +206,8 @@ void handler_irq(int irq, struct pt_regs * regs) struct irqaction * action; unsigned int cpu_irq; + lock_kernel(); + intr_count++; cpu_irq = irq & NR_IRQS; action = *(cpu_irq + irq_action); kstat.interrupts[cpu_irq]++; @@ -213,8 +217,23 @@ void handler_irq(int irq, struct pt_regs * regs) action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + intr_count--; + unlock_kernel(); } +#ifdef CONFIG_BLK_DEV_FD +extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + lock_kernel(); + intr_count++; + floppy_interrupt(irq, dev_id, regs); + intr_count--; + unlock_kernel(); +} +#endif + /* Fast IRQ's on the Sparc can only have one routine attached to them, * thus no sharing possible. */ diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 2d39132566de..e13374090c02 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.87 1996/12/30 06:16:21 davem Exp $ +/* $Id: process.c,v 1.89 1997/01/06 06:52:23 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -47,8 +49,11 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); */ asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; @@ -85,7 +90,10 @@ asmlinkage int sys_idle(void) } schedule(); } - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } #else @@ -95,13 +103,19 @@ asmlinkage int sys_idle(void) */ asmlinkage int sys_idle(void) { + int ret = -EPERM; + + lock_kernel(); if (current->pid != 0) - return -EPERM; + goto out; /* endless idle loop with no priority at all */ current->counter = -100; schedule(); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } /* This is being executed in task 0 'user space'. */ @@ -280,7 +294,6 @@ void show_thread(struct thread_struct *tss) */ void exit_thread(void) { - kill_user_windows(); #ifndef __SMP__ if(last_task_used_math == current) { #else @@ -300,9 +313,7 @@ void exit_thread(void) void flush_thread(void) { - /* Make sure old user windows don't get in the way. */ - kill_user_windows(); - + current->tss.w_saved = 0; current->tss.sstk_info.cur_status = 0; current->tss.sstk_info.the_stack = 0; @@ -406,7 +417,11 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) * allocate the task_struct and kernel stack in * do_fork(). */ +#ifdef __SMP__ +extern void ret_from_smpfork(void); +#else extern void ret_from_syscall(void); +#endif int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct *p, struct pt_regs *regs) @@ -439,8 +454,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack; +#ifdef __SMP__ + p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8); + p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL; +#else p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8); p->tss.kpsr = current->tss.fork_kpsr; +#endif p->tss.kwim = current->tss.fork_kwim; p->tss.kregs = childregs; @@ -548,11 +568,14 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(regs->u_regs[UREG_G1] == 0) base = 1; + lock_kernel(); error = getname((char *) regs->u_regs[base + UREG_I0], &filename); if(error) - return error; + goto out; error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], (char **) regs->u_regs[base + UREG_I2], regs); putname(filename); +out: + unlock_kernel(); return error; } diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index ad65a502d231..6523c0330b74 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -256,8 +258,7 @@ static int write_byte(struct task_struct * tsk, unsigned long addr, * is a valid errno will mean setting the condition codes to indicate * an error return. This doesn't work, so we have this hook. */ -static inline void -pt_error_return(struct pt_regs *regs, unsigned long error) +static inline void pt_error_return(struct pt_regs *regs, unsigned long error) { regs->u_regs[UREG_I0] = error; regs->psr |= PSR_C; @@ -265,8 +266,7 @@ pt_error_return(struct pt_regs *regs, unsigned long error) regs->npc += 4; } -static inline void -pt_succ_return(struct pt_regs *regs, unsigned long value) +static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) { regs->u_regs[UREG_I0] = value; regs->psr &= ~PSR_C; @@ -497,6 +497,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long addr2 = regs->u_regs[UREG_I4]; struct task_struct *child; + lock_kernel(); #ifdef DEBUG_PTRACE { char *s; @@ -518,32 +519,33 @@ asmlinkage void do_ptrace(struct pt_regs *regs) /* are we already being traced? */ if (current->flags & PF_PTRACED) { pt_error_return(regs, EPERM); - return; + goto out; } /* set the ptrace bit in the process flags. */ current->flags |= PF_PTRACED; pt_succ_return(regs, 0); - return; + goto out; } #ifndef ALLOW_INIT_TRACING if(pid == 1) { /* Can't dork with init. */ pt_error_return(regs, EPERM); - return; + goto out; } #endif if(!(child = get_task(pid))) { pt_error_return(regs, ESRCH); - return; + goto out; } - if(request == PTRACE_SUNATTACH || request == PTRACE_ATTACH) { + if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) + || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) */ pt_error_return(regs, EPERM); - return; + goto out; } if((!child->dumpable || (current->uid != child->euid) || @@ -551,12 +553,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (current->gid != child->egid) || (current->gid != child->gid)) && !suser()) { pt_error_return(regs, EPERM); - return; + goto out; } /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) { pt_error_return(regs, EPERM); - return; + goto out; } child->flags |= PF_PTRACED; if(child->p_pptr != current) { @@ -566,22 +568,23 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); - return; + goto out; } - if(!(child->flags & PF_PTRACED) && (request!=PTRACE_SUNATTACH) && - (request!=PTRACE_ATTACH)) { + if (!(child->flags & PF_PTRACED) + && ((current->personality & PER_BSD) && (request != PTRACE_SUNATTACH)) + && (!(current->personality & PER_BSD) && (request != PTRACE_ATTACH))) { pt_error_return(regs, ESRCH); - return; + goto out; } if(child->state != TASK_STOPPED) { if(request != PTRACE_KILL) { pt_error_return(regs, ESRCH); - return; + goto out; } } if(child->p_pptr != current) { pt_error_return(regs, ESRCH); - return; + goto out; } switch(request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -592,24 +595,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs) /* Non-word alignment _not_ allowed on Sparc. */ if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); - return; + goto out; } res = read_long(child, addr, &tmp); if (res < 0) { pt_error_return(regs, -res); - return; + goto out; } pt_os_succ_return(regs, tmp, (long *) data); - return; + goto out; } case PTRACE_PEEKUSR: read_sunos_user(regs, addr, child, (long *) data); - return; + goto out; case PTRACE_POKEUSR: write_sunos_user(regs, addr, child); - return; + goto out; case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { @@ -619,7 +622,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) /* Non-word alignment _not_ allowed on Sparc. */ if(addr & (sizeof(unsigned long) - 1)) { pt_error_return(regs, EINVAL); - return; + goto out; } vma = find_extend_vma(child, addr); res = write_long(child, addr, data); @@ -627,7 +630,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, -res); else pt_succ_return(regs, res); - return; + goto out; } case PTRACE_GETREGS: { @@ -636,8 +639,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int rval; rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs)); - if(rval) - return pt_error_return(regs, -rval); + if(rval) { + pt_error_return(regs, -rval); + goto out; + } __put_user(cregs->psr, (&pregs->psr)); __put_user(cregs->pc, (&pregs->pc)); __put_user(cregs->npc, (&pregs->npc)); @@ -648,7 +653,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) #ifdef DEBUG_PTRACE printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]); #endif - return; + goto out; } case PTRACE_SETREGS: { @@ -661,8 +666,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) * bits in the psr. */ i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs)); - if(i) - return pt_error_return(regs, -i); + if(i) { + pt_error_return(regs, -i); + goto out; + } __get_user(psr, (&pregs->psr)); __get_user(pc, (&pregs->pc)); __get_user(npc, (&pregs->npc)); @@ -678,7 +685,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) for(i = 1; i < 16; i++) __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1])); pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_GETFPREGS: { @@ -696,8 +703,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int i; i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps)); - if(i) - return pt_error_return(regs, -i); + if(i) { + pt_error_return(regs, -i); + goto out; + } for(i = 0; i < 32; i++) __put_user(child->tss.float_regs[i], (&fps->regs[i])); __put_user(child->tss.fsr, (&fps->fsr)); @@ -710,7 +719,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) __put_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_SETFPREGS: { @@ -728,8 +737,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int i; i = verify_area(VERIFY_READ, fps, sizeof(struct fps)); - if(i) - return pt_error_return(regs, -i); + if(i) { + pt_error_return(regs, -i); + goto out; + } copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * 4)); __get_user(child->tss.fsr, (&fps->fsr)); __get_user(child->tss.fpqdepth, (&fps->fpqd)); @@ -739,7 +750,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) __get_user(child->tss.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_READTEXT: @@ -750,17 +761,21 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int res, len = data; res = verify_area(VERIFY_WRITE, dest, len); - if(res) - return pt_error_return(regs, -res); + if(res) { + pt_error_return(regs, -res); + goto out; + } while(len) { res = read_byte(child, src, &tmp); - if(res < 0) - return pt_error_return(regs, -res); + if(res < 0) { + pt_error_return(regs, -res); + goto out; + } __put_user(tmp, dest); src++; dest++; len--; } pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_WRITETEXT: @@ -770,19 +785,23 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int res, len = data; res = verify_area(VERIFY_READ, src, len); - if(res) - return pt_error_return(regs, -res); + if(res) { + pt_error_return(regs, -res); + goto out; + } while(len) { unsigned long tmp; __get_user(tmp, src); res = write_byte(child, dest, tmp); - if(res < 0) - return pt_error_return(regs, -res); + if(res < 0) { + pt_error_return(regs, -res); + goto out; + } src++; dest++; len--; } pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ @@ -791,12 +810,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_CONT: { /* restart after signal. */ if ((unsigned long) data > NSIG) { pt_error_return(regs, EIO); - return; + goto out; } if (addr != 1) { if (addr & 3) { pt_error_return(regs, EINVAL); - return; + goto out; } #ifdef DEBUG_PTRACE printk ("Original: %08lx %08lx\n", child->tss.kregs->pc, child->tss.kregs->npc); @@ -821,7 +840,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) #endif wake_up_process(child); pt_succ_return(regs, 0); - return; + goto out; } /* @@ -832,18 +851,18 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_KILL: { if (child->state == TASK_ZOMBIE) { /* already dead */ pt_succ_return(regs, 0); - return; + goto out; } wake_up_process(child); child->exit_code = SIGKILL; pt_succ_return(regs, 0); - return; + goto out; } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ if ((unsigned long) data > NSIG) { pt_error_return(regs, EIO); - return; + goto out; } child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -852,25 +871,28 @@ asmlinkage void do_ptrace(struct pt_regs *regs) child->p_pptr = child->p_opptr; SET_LINKS(child); pt_succ_return(regs, 0); - return; + goto out; } /* PTRACE_DUMPCORE unsupported... */ default: pt_error_return(regs, EIO); - return; + goto out; } +out: + unlock_kernel(); } asmlinkage void syscall_trace(void) { + lock_kernel(); #ifdef DEBUG_PTRACE printk("%s [%d]: syscall_trace\n", current->comm, current->pid); #endif if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - return; + goto out; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; current->tss.flags ^= MAGIC_CONSTANT; @@ -889,4 +911,6 @@ asmlinkage void syscall_trace(void) current->signal |= (1 << (current->exit_code - 1)); } current->exit_code = 0; +out: + unlock_kernel(); } diff --git a/arch/sparc/kernel/rirq.S b/arch/sparc/kernel/rirq.S deleted file mode 100644 index 28fc8cd652d5..000000000000 --- a/arch/sparc/kernel/rirq.S +++ /dev/null @@ -1,289 +0,0 @@ -/* rirq.S: Needed to return from an interrupt on SMP with no - * locks held or released. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define t_psr l0 -#define t_pc l1 -#define t_npc l2 -#define t_wim l3 -#define twin_tmp1 l4 -#define twin_tmp2 l5 -#define twin_tmp3 l6 -#define curptr g6 - - /* 7 WINDOW SPARC PATCH INSTRUCTIONS */ - .globl rirq_7win_patch1, rirq_7win_patch2, rirq_7win_patch3 - .globl rirq_7win_patch4, rirq_7win_patch5 -rirq_7win_patch1: srl %t_wim, 0x6, %twin_tmp2 -rirq_7win_patch2: and %twin_tmp2, 0x7f, %twin_tmp2 -rirq_7win_patch3: srl %g1, 7, %g2 -rirq_7win_patch4: srl %g2, 6, %g2 -rirq_7win_patch5: and %g1, 0x7f, %g1 - /* END OF PATCH INSTRUCTIONS */ - - .globl ret_irq_entry, rirq_patch1, rirq_patch2 - .globl rirq_patch3, rirq_patch4, rirq_patch5 -ret_irq_entry: - ld [%sp + REGWIN_SZ + PT_PSR], %t_psr - andcc %t_psr, PSR_PS, %g0 - bne ret_irq_kernel - nop - -ret_irq_user: - wr %t_psr, 0x0, %psr - WRITE_PAUSE - - ld [%curptr + THREAD_W_SAVED], %twin_tmp1 - orcc %g0, %twin_tmp1, %g0 - be ret_irq_nobufwins - nop - - /* User has toasty windows, must grab klock. */ - ENTER_SYSCALL - - wr %t_psr, PSR_ET, %psr - WRITE_PAUSE - - mov 1, %o1 - call C_LABEL(try_to_clear_window_buffer) - add %sp, REGWIN_SZ, %o0 - - /* We have klock, so we must return just like a normal trap. */ - b ret_trap_entry - clr %l5 - -ret_irq_nobufwins: - /* Load up the user's out registers so we can pull - * a window from the stack, if necessary. - */ - LOAD_PT_INS(sp) - - /* If there are already live user windows in the - * set we can return from trap safely. - */ - ld [%curptr + THREAD_UMASK], %twin_tmp1 - orcc %g0, %twin_tmp1, %g0 - bne ret_irq_userwins_ok - nop - - /* Calculate new %wim, we have to pull a register - * window from the users stack. - */ -ret_irq_pull_one_window: - rd %wim, %t_wim - sll %t_wim, 0x1, %twin_tmp1 -rirq_patch1: srl %t_wim, 0x7, %twin_tmp2 - or %twin_tmp2, %twin_tmp1, %twin_tmp2 -rirq_patch2: and %twin_tmp2, 0xff, %twin_tmp2 - - wr %twin_tmp2, 0x0, %wim - WRITE_PAUSE - - /* Here comes the architecture specific - * branch to the user stack checking routine - * for return from traps. - */ - .globl C_LABEL(rirq_mmu_patchme) -C_LABEL(rirq_mmu_patchme): b C_LABEL(sun4c_reti_stackchk) - andcc %fp, 0x7, %g0 - -ret_irq_userwins_ok: - LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) - or %t_pc, %t_npc, %g2 - andcc %g2, 0x3, %g0 - bne ret_irq_unaligned_pc - nop - - LOAD_PT_YREG(sp, g1) - LOAD_PT_GLOBALS(sp) - - wr %t_psr, 0x0, %psr - WRITE_PAUSE - - jmp %t_pc - rett %t_npc - -ret_irq_unaligned_pc: - add %sp, REGWIN_SZ, %o0 - ld [%sp + REGWIN_SZ + PT_PC], %o1 - ld [%sp + REGWIN_SZ + PT_NPC], %o2 - ld [%sp + REGWIN_SZ + PT_PSR], %o3 - - wr %t_wim, 0x0, %wim ! or else... - WRITE_PAUSE - - /* User has unaligned crap, must grab klock. */ - ENTER_SYSCALL - - wr %t_psr, PSR_ET, %psr - WRITE_PAUSE - - call C_LABEL(do_memaccess_unaligned) - nop - - /* We have klock, so we must return just like a normal trap. */ - b ret_trap_entry - clr %l5 - -ret_irq_kernel: - wr %t_psr, 0x0, %psr - WRITE_PAUSE - - /* Will the rett land us in the invalid window? */ - mov 2, %g1 - sll %g1, %t_psr, %g1 -rirq_patch3: srl %g1, 8, %g2 - or %g1, %g2, %g1 - rd %wim, %g2 - andcc %g2, %g1, %g0 - be 1f ! Nope, just return from the trap - nop - - /* We have to grab a window before returning. */ - sll %g2, 0x1, %g1 -rirq_patch4: srl %g2, 7, %g2 - or %g1, %g2, %g1 -rirq_patch5: and %g1, 0xff, %g1 - - wr %g1, 0x0, %wim - WRITE_PAUSE - - restore %g0, %g0, %g0 - LOAD_WINDOW(sp) - save %g0, %g0, %g0 - - /* Reload the entire frame in case this is from a - * kernel system call or whatever... - */ -1: - LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) - - wr %t_psr, 0x0, %psr - WRITE_PAUSE - - jmp %t_pc - rett %t_npc - -ret_irq_user_stack_is_bolixed: - wr %t_wim, 0x0, %wim - WRITE_PAUSE - - /* User has a toasty window, must grab klock. */ - ENTER_SYSCALL - - wr %t_psr, PSR_ET, %psr - WRITE_PAUSE - - call C_LABEL(window_ret_fault) - add %sp, REGWIN_SZ, %o0 - - /* We have klock, so we must return just like a normal trap. */ - b ret_trap_entry - clr %l5 - - .globl C_LABEL(sun4c_reti_stackchk) -C_LABEL(sun4c_reti_stackchk): - be 1f - and %fp, 0xfff, %g1 ! delay slot - - b,a ret_irq_user_stack_is_bolixed - - /* See if we have to check the sanity of one page or two */ -1: - add %g1, 0x38, %g1 - sra %fp, 29, %g2 - add %g2, 0x1, %g2 - andncc %g2, 0x1, %g0 - be 1f - andncc %g1, 0xff8, %g0 - - /* %sp is in vma hole, yuck */ - b,a ret_irq_user_stack_is_bolixed - -1: - be sun4c_reti_onepage /* Only one page to check */ - lda [%fp] ASI_PTE, %g2 - -sun4c_reti_twopages: - add %fp, 0x38, %g1 - sra %g1, 29, %g2 - add %g2, 0x1, %g2 - andncc %g2, 0x1, %g0 - be 1f - lda [%g1] ASI_PTE, %g2 - - /* Second page is in vma hole */ - b,a ret_irq_user_stack_is_bolixed - -1: - srl %g2, 29, %g2 - andcc %g2, 0x4, %g0 - bne sun4c_reti_onepage - lda [%fp] ASI_PTE, %g2 - - /* Second page has bad perms */ - b,a ret_irq_user_stack_is_bolixed - -sun4c_reti_onepage: - srl %g2, 29, %g2 - andcc %g2, 0x4, %g0 - bne 1f - nop - - /* A page had bad page permissions, losing... */ - b,a ret_irq_user_stack_is_bolixed - - /* Whee, things are ok, load the window and continue. */ -1: - restore %g0, %g0, %g0 - - LOAD_WINDOW(sp) - - save %g0, %g0, %g0 - b,a ret_irq_userwins_ok - - .globl C_LABEL(srmmu_reti_stackchk) -C_LABEL(srmmu_reti_stackchk): - sethi %hi(C_LABEL(page_offset)), %g1 - bne ret_irq_user_stack_is_bolixed - ld [%g1 + %lo(C_LABEL(page_offset))], %g1 - cmp %g1, %fp - bleu ret_irq_user_stack_is_bolixed - mov AC_M_SFSR, %g1 - lda [%g1] ASI_M_MMUREGS, %g0 - - lda [%g0] ASI_M_MMUREGS, %g1 - or %g1, 0x2, %g1 - sta %g1, [%g0] ASI_M_MMUREGS - - restore %g0, %g0, %g0 - - LOAD_WINDOW(sp) - - save %g0, %g0, %g0 - - andn %g1, 0x2, %g1 - sta %g1, [%g0] ASI_M_MMUREGS - - mov AC_M_SFAR, %g2 - lda [%g2] ASI_M_MMUREGS, %g2 - - mov AC_M_SFSR, %g1 - lda [%g1] ASI_M_MMUREGS, %g1 - andcc %g1, 0x2, %g0 - bne ret_irq_user_stack_is_bolixed - nop - - b,a ret_irq_userwins_ok diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index 04b0695e470e..da4c66d6fc2c 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.41 1996/12/28 18:14:21 davem Exp $ +/* $Id: rtrap.S,v 1.44 1997/01/14 05:56:17 davem Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -46,25 +46,25 @@ rtrap_7win_patch5: and %g1, 0x7f, %g1 .globl ret_trap_entry, rtrap_patch1, rtrap_patch2 .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 + .globl C_LABEL(ret_trap_lockless_ipi) ret_trap_entry: - sethi %hi(C_LABEL(intr_count)), %g2 - ld [%g2 + %lo(C_LABEL(intr_count))], %g3 - orcc %g0, %g3, %g0 - bne 0f - sethi %hi(C_LABEL(bh_active)), %l3 - sethi %hi(C_LABEL(bh_mask)), %l4 + sethi %hi(C_LABEL(intr_count)), %g4 + ld [%g4 + %lo(C_LABEL(intr_count))], %g5 + orcc %g5, 0x0, %g0 + sethi %hi(C_LABEL(bh_active)), %l3 + bne C_LABEL(ret_trap_lockless_ipi) + sethi %hi(C_LABEL(bh_mask)), %l4 9: ld [%l4 + %lo(C_LABEL(bh_mask))], %g5 ld [%l3 + %lo(C_LABEL(bh_active))], %g4 - sethi %hi(C_LABEL(intr_count)), %l7 andcc %g4, %g5, %g0 - be 0f - mov 1, %g7 + be C_LABEL(ret_trap_lockless_ipi) + nop call C_LABEL(do_bottom_half) - st %g7, [%l7 + %lo(C_LABEL(intr_count))] - b 9b - st %g0, [%l7 + %lo(C_LABEL(intr_count))] -0: + nop + b,a 9b + +C_LABEL(ret_trap_lockless_ipi): andcc %t_psr, PSR_PS, %g0 be 1f sethi %hi(C_LABEL(need_resched)), %twin_tmp1 @@ -164,8 +164,6 @@ ret_trap_userwins_ok: LOAD_PT_YREG(sp, g1) LOAD_PT_GLOBALS(sp) - LEAVE_SYSCALL - wr %t_psr, 0x0, %psr WRITE_PAUSE @@ -219,8 +217,6 @@ rtrap_patch5: and %g1, 0xff, %g1 1: LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) 2: - LEAVE_SYSCALL - wr %t_psr, 0x0, %psr WRITE_PAUSE diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 150eab9d4716..cccb9533dc40 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.79 1996/12/23 10:57:02 ecd Exp $ +/* $Id: setup.c,v 1.80 1997/01/25 02:39:54 miguel Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -183,11 +183,11 @@ __initfunc(static void boot_flags_init(char *commands)) #ifdef CONFIG_SUN_SERIAL case 'a': rs_kgdb_hook(0); - printk("KGDB: Using serial line /dev/ttya.\n"); + prom_printf("KGDB: Using serial line /dev/ttya.\n"); break; case 'b': rs_kgdb_hook(1); - printk("KGDB: Using serial line /dev/ttyb.\n"); + prom_printf("KGDB: Using serial line /dev/ttyb.\n"); break; #endif #ifdef CONFIG_AP1000 @@ -327,6 +327,7 @@ __initfunc(void setup_arch(char **cmdline_p, } if((boot_flags & BOOTME_KGDB)) { set_debug_traps(); + prom_printf ("Breakpoint!\n"); breakpoint(); } @@ -441,8 +442,6 @@ extern char *sparc_fpu_type[]; extern char *smp_info(void); -extern int linux_num_cpus; - int get_cpuinfo(char *buffer) { int cpuid=get_cpuid(); diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index b1b157aa7944..64add983abe5 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,9 +1,10 @@ -/* $Id: signal.c,v 1.66 1996/12/20 07:54:58 davem Exp $ +/* $Id: signal.c,v 1.71 1997/01/19 22:32:21 ecd Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ #include @@ -14,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -67,10 +70,11 @@ struct signal_sframe { */ struct new_signal_frame { - struct sparc_stackf ss; - __siginfo_t info; - unsigned long __pad; - unsigned long insns [2]; + struct sparc_stackf ss; + __siginfo_t info; + __siginfo_fpu_t *fpu_save; + unsigned long insns [2] __attribute__ ((aligned (8))); + __siginfo_fpu_t fpu_state; }; /* Align macros */ @@ -111,59 +115,86 @@ asmlinkage inline void _sigpause_common(unsigned int set, struct pt_regs *regs) asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs) { + lock_kernel(); _sigpause_common(set, regs); + unlock_kernel(); } asmlinkage void do_sigsuspend (struct pt_regs *regs) { + lock_kernel(); _sigpause_common(regs->u_regs[UREG_I0], regs); + unlock_kernel(); +} + + +static inline void +restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) + regs->psr &= ~PSR_EF; +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->psr &= ~PSR_EF; + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; + + copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 64)); + __get_user(current->tss.fsr, &fpu->si_fsr); + __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); + if (current->tss.fpqdepth != 0) + copy_from_user(¤t->tss.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); } void do_new_sigreturn (struct pt_regs *regs) { struct new_signal_frame *sf; - unsigned long up_psr; + unsigned long up_psr, pc, npc, mask; + lock_kernel(); sf = (struct new_signal_frame *) regs->u_regs [UREG_FP]; + /* 1. Make sure we are not getting garbage from the user */ if (verify_area (VERIFY_READ, sf, sizeof (*sf))){ do_exit (SIGSEGV); - return; + goto out; } if (((uint) sf) & 3){ do_exit (SIGSEGV); - return; + goto out; } - if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){ + + __get_user(pc, &sf->info.si_regs.pc); + __get_user(npc, &sf->info.si_regs.npc); + + if ((pc | npc) & 3) { do_exit (SIGSEGV); - return; + goto out; } /* 2. Restore the state */ up_psr = regs->psr; - memcpy (regs, &sf->info.si_regs, sizeof (struct pt_regs)); + copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); - /* User can only change condition codes and FPU enabling in the %psr. */ - regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | (regs->psr & (PSR_ICC | PSR_EF)); + /* 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 (regs->psr & PSR_EF) { - regs->psr &= ~(PSR_EF); -#ifndef __SMP__ - if(current == last_task_used_math) - last_task_used_math = 0; -#endif - current->used_math = 1; - current->flags &= ~(PF_USEDFPU); + if (sf->fpu_save) + restore_fpu_state(regs, sf->fpu_save); - /* Copy signal FPU state into thread struct FPU state. */ - memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0], - (sizeof(unsigned long) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16)); - } - current->blocked = sf->info.si_mask & _BLOCKABLE; + __get_user(mask, &sf->info.si_mask); + current->blocked = (mask & _BLOCKABLE); +out: + unlock_kernel(); } asmlinkage void do_sigreturn(struct pt_regs *regs) @@ -171,10 +202,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) struct sigcontext *scptr; unsigned long pc, npc, psr; + lock_kernel(); synchronize_user_stack(); if (current->tss.new_signal){ do_new_sigreturn (regs); - return; + goto out; } scptr = (struct sigcontext *) regs->u_regs[UREG_I0]; /* Check sanity of the user arg. */ @@ -204,6 +236,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) __get_user(psr, &scptr->sigc_psr); regs->psr &= ~(PSR_ICC); regs->psr |= (psr & PSR_ICC); +out: + unlock_kernel(); } /* Checks if the fp is valid */ @@ -287,77 +321,83 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, regs->npc = (regs->pc + 4); } -/* To align the structure properly. */ + +static inline void +save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + last_task_used_math = 0; + regs->psr &= ~(PSR_EF); + } +#endif + copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + (sizeof(unsigned long) * 64)); + __put_user(current->tss.fsr, &fpu->si_fsr); + __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); + if (current->tss.fpqdepth != 0) + copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); + current->used_math = 0; +} + static inline void new_setup_frame(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned long oldmask) { struct new_signal_frame *sf; + int sigframe_size; /* 1. Make sure everything is clean */ synchronize_user_stack(); - sf = (struct new_signal_frame *) regs->u_regs[UREG_FP]; - sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ); - - if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){ + + sigframe_size = NF_ALIGNEDSZ; + if (!current->used_math) + sigframe_size -= sizeof(__siginfo_fpu_t); + + sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size); + + if (invalid_frame_pointer (sf, sigframe_size)){ do_exit(SIGILL); return; } if (current->tss.w_saved != 0){ - printk ("%s[%d]: Invalid user stack frame for signal delivery.\n", - current->comm, current->pid); + printk ("%s [%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); do_exit (SIGILL); return; } /* 2. Save the current process state */ - memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs)); -#ifdef __SMP__ - if(current->flags & PF_USEDFPU) { - put_psr(get_psr() | PSR_EF); - fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr, - &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth); - - /* Save a copy into thread struct as well. */ - memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0], - (sizeof(unsigned long) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16)); + copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs)); - regs->psr &= ~(PSR_EF); - current->flags &= ~(PF_USEDFPU); - } -#else - if(current == last_task_used_math) { - put_psr(get_psr() | PSR_EF); - fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr, - &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth); - - /* Save a copy into thread struct as well. */ - memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0], - (sizeof(unsigned long) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16)); - - last_task_used_math = NULL; - regs->psr &= ~(PSR_EF); + if (current->used_math) { + save_fpu_state(regs, &sf->fpu_state); + sf->fpu_save = &sf->fpu_state; + } else { + sf->fpu_save = NULL; } -#endif - - /* This new thread of control has not used the FPU. */ - current->used_math = 0; - sf->info.si_mask = oldmask; - memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window)); + __put_user(oldmask, &sf->info.si_mask); + copy_to_user(sf, (char *) regs->u_regs [UREG_FP], + sizeof (struct reg_window)); /* 3. return to kernel instructions */ - sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */ - sf->insns [1] = 0x91d02010; /* t 0x10 */ + __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 */ regs->u_regs[UREG_FP] = (unsigned long) sf; @@ -373,6 +413,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } + /* Setup a Solaris stack frame */ static inline void setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, @@ -491,21 +532,23 @@ svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) { svr4_gregset_t *gr; svr4_mcontext_t *mc; + int ret = -EFAULT; + lock_kernel(); synchronize_user_stack(); if (current->tss.w_saved){ printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved); do_exit (SIGSEGV); } if(clear_user(uc, sizeof (*uc))) - return -EFAULT; + goto out; /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; /* We only have < 32 signals, fill the first slot only */ - __put_user(current->sig->action->sa_mask, &uc->sigmask.sigbits [0]); + __put_user(current->blocked, &uc->sigmask.sigbits [0]); /* Store registers */ __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); @@ -525,7 +568,10 @@ svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) /* The register file is not saved * we have already stuffed all of it with sync_user_stack */ - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } @@ -535,7 +581,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; + int ret = -EINTR; + lock_kernel(); /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? */ @@ -544,15 +592,18 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) if (tp->w_saved){ printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); do_exit(SIGSEGV); + goto out; } if (((uint) c) & 3){ printk ("Unaligned structure passed\n"); do_exit (SIGSEGV); + goto out; } if(!__access_ok((unsigned long)c, sizeof(*c))) { /* Miguel, add nice debugging msg _here_. ;-) */ do_exit(SIGSEGV); + goto out; } /* Check for valid PC and nPC */ @@ -562,6 +613,7 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) if((pc | npc) & 3) { printk ("setcontext, PC or nPC were bogus\n"); do_exit (SIGSEGV); + goto out; } /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ @@ -578,8 +630,9 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) /* Restore g[1..7] and o[0..7] registers */ copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); - - return -EINTR; +out: + unlock_kernel(); + return ret; } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -630,7 +683,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, unsigned long signr, mask = ~current->blocked; struct sigaction *sa; int svr4_signal = current->personality == PER_SVR4; + int ret; + lock_kernel(); while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); clear_bit(signr, ¤t->signal); @@ -701,7 +756,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, if(restart_syscall) syscall_restart(orig_i0, regs, sa); handle_signal(signr, sa, oldmask, regs, svr4_signal); - return 1; + ret = 1; + goto out; } if(restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || @@ -712,22 +768,31 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, regs->pc -= 4; regs->npc -= 4; } - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr) { + int ret = -EFAULT; + + lock_kernel(); /* First see if old state is wanted. */ if(ossptr) { if(copy_to_user(ossptr, ¤t->tss.sstk_info, sizeof(struct sigstack))) - return -EFAULT; + goto out; } /* Now see if we want to update the new state. */ if(ssptr) { if(copy_from_user(¤t->tss.sstk_info, ssptr, sizeof(struct sigstack))) - return -EFAULT; + goto out; } - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 25c5969cd97d..4189c01e40b2 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include extern ctxd_t *srmmu_ctx_table_phys; extern int linux_num_cpus; @@ -58,10 +60,8 @@ volatile int cpu_logical_map[NR_CPUS]; * compared to the Alpha and the intel no? Most Sparcs have 'swap' * instruction which is much better... */ -klock_t kernel_flag = KLOCK_CLEAR; -volatile unsigned char active_kernel_processor = NO_PROC_ID; -volatile unsigned long kernel_counter = 0; -volatile unsigned long syscall_count = 0; +struct klock_info klock_info = { KLOCK_CLEAR, 0, 0 }; + volatile unsigned long ipi_count; #ifdef __SMP_PROF__ volatile unsigned long smp_spins[NR_CPUS]={0}; @@ -99,10 +99,10 @@ char *smp_info(void) sprintf(smp_buf, " CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" "State: %s\t\t%s\t\t%s\t\t%s\n", -(cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline", -(cpu_present_map & 2) ? ((active_kernel_processor == 1) ? "akp" : "online") : "offline", -(cpu_present_map & 4) ? ((active_kernel_processor == 2) ? "akp" : "online") : "offline", -(cpu_present_map & 8) ? ((active_kernel_processor == 3) ? "akp" : "online") : "offline"); +(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline", +(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline", +(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline", +(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline"); return smp_buf; } @@ -150,31 +150,32 @@ void smp_callin(void) { int cpuid = smp_processor_id(); - sti(); local_flush_cache_all(); local_flush_tlb_all(); + set_irq_udt(mid_xlate[boot_cpu_id]); calibrate_delay(); smp_store_cpu_info(cpuid); local_flush_cache_all(); local_flush_tlb_all(); - cli(); /* Allow master to continue. */ swap((unsigned long *)&cpu_callin_map[cpuid], 1); local_flush_cache_all(); local_flush_tlb_all(); - while(!smp_commenced) + + while(!task[cpuid] || current_set[cpuid] != task[cpuid]) barrier(); - local_flush_cache_all(); - local_flush_tlb_all(); /* Fix idle thread fields. */ __asm__ __volatile__("ld [%0], %%g6\n\t" - : : "r" (¤t_set[smp_processor_id()]) + : : "r" (¤t_set[cpuid]) : "memory" /* paranoid */); current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + + while(!smp_commenced) + barrier(); local_flush_cache_all(); local_flush_tlb_all(); @@ -207,7 +208,6 @@ void smp_boot_cpus(void) penguin_ctable.reg_size = 0; sti(); - cpu_present_map |= (1 << smp_processor_id()); cpu_present_map = 0; for(i=0; i < linux_num_cpus; i++) cpu_present_map |= (1<", smp_processor_id()); + printk("C%d(%d)<", smp_processor_id(), cap_info.capture_level); #endif save_and_cli(flags); - if(!capture_level) { - release = 0; - smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 1); + + if (! cap_info.capture_level++) { + int timeout; + + /* Initialize Capture Info. */ + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + cap_info.processors_in[cpu] = 0; + cap_info.processors_out[cpu] = 0; + } + cap_info.processors_in[me] = 1; + cap_info.processors_out[me] = 1; + + smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 4); + + timeout = CCALL_TIMEOUT; + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + while (!cap_info.processors_in[cpu] && timeout-- > 0) + barrier(); + if (!cap_info.processors_in[cpu]) + goto procs_time_out; +#ifdef DEBUG_CAPTURE + printk("%d", cpu); +#endif + } } - capture_level++; +#ifdef DEBUG_CAPTURE + printk(">"); +#endif + restore_flags(flags); + return; + +procs_time_out: + printk("smp_capture (%d): Wheee, penguin drops off the bus\n", + smp_processor_id()); + printk("smp_capture: map: %ld %ld %ld %ld\n", + cap_info.processors_in[0], cap_info.processors_in[1], + cap_info.processors_in[2], cap_info.processors_in[3]); + smp_cpu_in_msg[me]--; + message_cpu = NO_PROC_ID; restore_flags(flags); } void smp_release(void) { unsigned long flags; - int i; + int me = smp_processor_id(); + int cpu; - if(!smp_activated || !smp_commenced) + if(!smp_processors_ready) return; #ifdef DEBUG_CAPTURE - printk("R<%d>", smp_processor_id()); + printk("R%d(%d)<", smp_processor_id(), cap_info.capture_level); #endif + + if (me != klock_info.akp) + panic("SMP Release on CPU #%d, but #%d is active.\n", + me, klock_info.akp); + save_and_cli(flags); - if(!(capture_level - 1)) { - release = 1; - for(i = 0; i < smp_num_cpus; i++) - while(cpu_callin_map[i]) + + if (! --cap_info.capture_level) { + int timeout; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) + cap_info.processors_in[cpu] = 0; + + timeout = CCALL_TIMEOUT; + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + while (!cap_info.processors_out[cpu] && timeout-- > 0) barrier(); + if (!cap_info.processors_out[cpu]) + goto procs_time_out; +#ifdef DEBUG_CAPTURE + printk("%d", cpu); +#endif + } + + /* See wait case 4 in smp_message_pass()... */ + smp_cpu_in_msg[me]--; } - capture_level -= 1; +#ifdef DEBUG_CAPTURE + printk(">"); +#endif restore_flags(flags); -} + return; -/* Park a processor, we must watch for more IPI's to invalidate - * our cache's and TLB's. And also note we can only wait for - * "lock-less" IPI's and process those, as a result of such IPI's - * being non-maskable traps being on is enough to receive them. - */ +procs_time_out: + printk("smp_release (%d): Wheee, penguin drops off the bus\n", + smp_processor_id()); + printk("smp_release: map: %ld %ld %ld %ld\n", + cap_info.processors_out[0], cap_info.processors_out[1], + cap_info.processors_out[2], cap_info.processors_out[3]); + smp_cpu_in_msg[me]--; + restore_flags(flags); +} /* Message call back. */ void smp_message_irq(void) @@ -642,6 +724,14 @@ void smp_message_irq(void) ccall_info.processors_out[i] = 1; break; + case MSG_CAPTURE: + flush_user_windows(); + cap_info.processors_in[i] = 1; + while (cap_info.processors_in[i]) + barrier(); + cap_info.processors_out[i] = 1; + break; + /* * Halt other CPU's for a panic or reboot */ diff --git a/arch/sparc/kernel/solaris.c b/arch/sparc/kernel/solaris.c index 17305712ec04..c5434b7a0102 100644 --- a/arch/sparc/kernel/solaris.c +++ b/arch/sparc/kernel/solaris.c @@ -6,43 +6,22 @@ #include #include #include +#include +#include +#include #include #include -#if 0 -/* Not used - actually translated in iBCS */ -unsigned long solaris_xlatb_rorl[] = { - 0, SOL_EPERM, SOL_ENOENT, SOL_ESRCH, SOL_EINTR, SOL_EIO, - SOL_ENXIO, SOL_E2BIG, SOL_ENOEXEC, SOL_EBADF, SOL_ECHILD, - SOL_EAGAIN, SOL_ENOMEM, SOL_EACCES, SOL_EFAULT, - SOL_ENOTBLK, SOL_EBUSY, SOL_EEXIST, SOL_EXDEV, SOL_ENODEV, - SOL_ENOTDIR, SOL_EISDIR, SOL_EINVAL, SOL_ENFILE, SOL_EMFILE, - SOL_ENOTTY, SOL_ETXTBSY, SOL_EFBIG, SOL_ENOSPC, SOL_ESPIPE, - SOL_EROFS, SOL_EMLINK, SOL_EPIPE, SOL_EDOM, SOL_ERANGE, - SOL_EWOULDBLOCK, SOL_EINPROGRESS, SOL_EALREADY, SOL_ENOTSOCK, - SOL_EDESTADDRREQ, SOL_EMSGSIZE, SOL_EPROTOTYPE, SOL_ENOPROTOOPT, - SOL_EPROTONOSUPPORT, SOL_ESOCKTNOSUPPORT, SOL_EOPNOTSUPP, - SOL_EPFNOSUPPORT, SOL_EAFNOSUPPORT, SOL_EADDRINUSE, - SOL_EADDRNOTAVAIL, SOL_ENETDOWN, SOL_ENETUNREACH, SOL_ENETRESET, - SOL_ECONNABORTED, SOL_ECONNRESET, SOL_ENOBUFS, SOL_EISCONN, - SOL_ENOTCONN, SOL_ESHUTDOWN, SOL_ETOOMANYREFS, SOL_ETIMEDOUT, - SOL_ECONNREFUSED, SOL_ELOOP, SOL_ENAMETOOLONG, SOL_EHOSTDOWN, - SOL_EHOSTUNREACH, SOL_ENOTEMPTY, SOL_EUSERS, SOL_EUSERS, - SOL_EDQUOT, SOL_ESTALE, SOL_EREMOTE, SOL_ENOSTR, SOL_ETIME, - SOL_ENOSR, SOL_ENOMSG, SOL_EBADMSG, SOL_EIDRM, SOL_EDEADLK, - SOL_ENOLCK, SOL_ENONET, SOL_EINVAL, SOL_ENOLINK, SOL_EADV, - SOL_ESRMNT, SOL_ECOMM, SOL_EPROTO, SOL_EMULTIHOP, SOL_EINVAL, - SOL_EREMCHG, SOL_ENOSYS -}; -#endif - extern asmlinkage int sys_open(const char *,int,int); asmlinkage int solaris_open(const char *filename, int flags, int mode) { - int newflags = flags & 0xf; + int newflags; + int ret; + lock_kernel(); + newflags = flags & 0xf; flags &= ~0xf; if(flags & 0x8050) newflags |= FASYNC; @@ -56,7 +35,9 @@ asmlinkage int solaris_open(const char *filename, int flags, int mode) newflags |= O_EXCL; if(flags & 0x800) newflags |= O_NOCTTY; - return sys_open(filename, newflags, mode); + ret = sys_open(filename, newflags, mode); + unlock_kernel(); + return ret; } diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c index 5fa429ba577e..008e9c4508a4 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.19 1996/09/30 02:21:48 davem Exp $ +/* $Id: sparc-stub.c,v 1.20 1997/01/06 06:52:31 davem Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -97,6 +97,8 @@ #include #include #include +#include +#include #include #include @@ -475,6 +477,7 @@ handle_exception (unsigned long *registers) "restore\n\t" "restore\n\t"); + lock_kernel(); if (registers[PC] == (unsigned long)breakinst) { /* Skip over breakpoint trap insn */ registers[PC] = registers[NPC]; @@ -646,6 +649,7 @@ handle_exception (unsigned long *registers) * some location may have changed something that is in the instruction cache. */ flush_cache_all(); + unlock_kernel(); return; /* kill the program */ diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 941420f35db6..3eb4764e33e1 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.33 1996/12/29 20:46:01 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.43 1997/01/26 07:12:30 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -27,6 +27,7 @@ #include #ifdef CONFIG_SBUS #include +#include #endif #include @@ -38,12 +39,12 @@ struct poll { extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); -extern int sunos_poll(struct poll * ufds, size_t nfds, int timeout); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); extern void __copy_1page(void *, const void *); -extern void *__memcpy(void *, const void *, __kernel_size_t); +extern void __memcpy(void *, const void *, __kernel_size_t); +extern void __memmove(void *, const void *, __kernel_size_t); extern void *__memset(void *, int, __kernel_size_t); extern void *bzero_1page(void *); extern void *__bzero(void *, size_t); @@ -70,18 +71,34 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int __sparc_dot_ ## sym (int) __asm__("." #sym); \ __EXPORT_SYMBOL(__sparc_dot_ ## sym, "." #sym) +#define EXPORT_SYMBOL_PRIVATE(sym) \ +extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym); \ +const struct module_symbol __export_priv_##sym \ +__attribute__((section("__ksymtab"))) = \ +{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym } /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); #ifdef __SMP__ -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(kernel_counter); -EXPORT_SYMBOL(active_kernel_processor); -EXPORT_SYMBOL(syscall_count); +EXPORT_SYMBOL(klock_info); #endif +EXPORT_SYMBOL_PRIVATE(_lock_kernel); +EXPORT_SYMBOL_PRIVATE(_unlock_kernel); EXPORT_SYMBOL(page_offset); EXPORT_SYMBOL(stack_top); +/* Atomic operations. */ +EXPORT_SYMBOL_PRIVATE(_xchg32); +EXPORT_SYMBOL_PRIVATE(_atomic_add); +EXPORT_SYMBOL_PRIVATE(_atomic_sub); + +/* Bit operations. */ +EXPORT_SYMBOL_PRIVATE(_set_bit); +EXPORT_SYMBOL_PRIVATE(_clear_bit); +EXPORT_SYMBOL_PRIVATE(_change_bit); +EXPORT_SYMBOL_PRIVATE(_set_le_bit); +EXPORT_SYMBOL_PRIVATE(_clear_le_bit); + EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(mstk48t02_regs); #if CONFIG_SUN_AUXIO @@ -90,6 +107,7 @@ EXPORT_SYMBOL(auxio_register); EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); +EXPORT_SYMBOL(io_remap_page_range); EXPORT_SYMBOL(mmu_v2p); EXPORT_SYMBOL(mmu_unlockarea); EXPORT_SYMBOL(mmu_lockarea); @@ -102,6 +120,7 @@ EXPORT_SYMBOL(sun4c_unmapioaddr); EXPORT_SYMBOL(srmmu_unmapioaddr); #if CONFIG_SBUS EXPORT_SYMBOL(SBus_chain); +EXPORT_SYMBOL(dma_chain); #endif /* Solaris/SunOS binary compatibility */ @@ -109,7 +128,6 @@ EXPORT_SYMBOL(svr4_setcontext); EXPORT_SYMBOL(svr4_getcontext); EXPORT_SYMBOL(_sigpause_common); EXPORT_SYMBOL(sunos_mmap); -EXPORT_SYMBOL(sunos_poll); /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); @@ -124,7 +142,8 @@ EXPORT_SYMBOL(prom_firstprop); EXPORT_SYMBOL(prom_nextprop); EXPORT_SYMBOL(prom_getproplen); EXPORT_SYMBOL(prom_getproperty); -EXPORT_SYMOBL(prom_setprop); +EXPORT_SYMBOL(prom_node_has_property); +EXPORT_SYMBOL(prom_setprop); EXPORT_SYMBOL(prom_nodeops); EXPORT_SYMBOL(prom_getbootargs); EXPORT_SYMBOL(prom_apply_obio_ranges); @@ -138,7 +157,6 @@ EXPORT_SYMBOL(romvec); /* sparc library symbols */ EXPORT_SYMBOL(bcopy); -EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); @@ -165,6 +183,7 @@ EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); EXPORT_SYMBOL(__memcmp); EXPORT_SYMBOL(__strncmp); +EXPORT_SYMBOL(__memmove); /* Moving data to/from userspace. */ EXPORT_SYMBOL(__copy_user); @@ -174,12 +193,13 @@ EXPORT_SYMBOL(__strncpy_from_user); /* No version information on this, heavily used in inline asm, * and will always be 'void __ret_efault(void)'. */ -EXPORT_SYMBOLNOVERS(__ret_efault); +EXPORT_SYMBOL_NOVERS(__ret_efault); /* No version information on these, as gcc produces such symbols. */ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_DOT(rem); diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index a1bc01af1327..d39e788bc8b7 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -35,7 +35,6 @@ static unsigned long dummy; -extern int linux_num_cpus; struct sun4m_intregs *sun4m_interrupts; unsigned long *irq_rcvreg = &dummy; diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c index f8c264647bc1..82500a55d737 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.26 1996/10/31 00:59:06 davem Exp $ +/* $Id: sunos_ioctl.c,v 1.27 1997/01/06 06:52:33 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #if 0 @@ -32,10 +34,11 @@ extern asmlinkage int sys_setsid(void); asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) { struct file *filp; - int ret; + int ret = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(filp = current->files->fd [fd])) - return -EBADF; + goto out; /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { @@ -43,69 +46,95 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) int tmp, oldfs; p = (int *) arg; + ret = -EFAULT; if(get_user(tmp, p)) - return -EFAULT; + goto out; if(tmp == 2) { oldfs = get_fs(); set_fs(KERNEL_DS); ret = sys_ioctl(fd, cmd, (int) &ntty); set_fs(oldfs); - return (ret == -EINVAL ? -EOPNOTSUPP : ret); + ret = (ret == -EINVAL ? -EOPNOTSUPP : ret); + goto out; } } /* Binary compatibility is good American knowhow fuckin' up. */ - if(cmd == TIOCNOTTY) - return sys_setsid(); + if(cmd == TIOCNOTTY) { + ret = sys_setsid(); + goto out; + } /* SunOS networking ioctls. */ switch (cmd) { case _IOW('r', 10, struct rtentry): - return sys_ioctl(fd, SIOCADDRT, arg); + ret = sys_ioctl(fd, SIOCADDRT, arg); + goto out; case _IOW('r', 11, struct rtentry): - return sys_ioctl(fd, SIOCDELRT, arg); + ret = sys_ioctl(fd, SIOCDELRT, arg); + goto out; case _IOW('i', 12, struct ifreq): - return sys_ioctl(fd, SIOCSIFADDR, arg); + ret = sys_ioctl(fd, SIOCSIFADDR, arg); + goto out; case _IOWR('i', 13, struct ifreq): - return sys_ioctl(fd, SIOCGIFADDR, arg); + ret = sys_ioctl(fd, SIOCGIFADDR, arg); + goto out; case _IOW('i', 14, struct ifreq): - return sys_ioctl(fd, SIOCSIFDSTADDR, arg); + ret = sys_ioctl(fd, SIOCSIFDSTADDR, arg); + goto out; case _IOWR('i', 15, struct ifreq): - return sys_ioctl(fd, SIOCGIFDSTADDR, arg); + ret = sys_ioctl(fd, SIOCGIFDSTADDR, arg); + goto out; case _IOW('i', 16, struct ifreq): - return sys_ioctl(fd, SIOCSIFFLAGS, arg); + ret = sys_ioctl(fd, SIOCSIFFLAGS, arg); + goto out; case _IOWR('i', 17, struct ifreq): - return sys_ioctl(fd, SIOCGIFFLAGS, arg); + ret = sys_ioctl(fd, SIOCGIFFLAGS, arg); + goto out; case _IOW('i', 18, struct ifreq): - return sys_ioctl(fd, SIOCSIFMEM, arg); + ret = sys_ioctl(fd, SIOCSIFMEM, arg); + goto out; case _IOWR('i', 19, struct ifreq): - return sys_ioctl(fd, SIOCGIFMEM, arg); + ret = sys_ioctl(fd, SIOCGIFMEM, arg); + goto out; case _IOWR('i', 20, struct ifconf): - return sys_ioctl(fd, SIOCGIFCONF, arg); + ret = sys_ioctl(fd, SIOCGIFCONF, arg); + goto out; case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */ - return sys_ioctl(fd, SIOCSIFMTU, arg); + ret = sys_ioctl(fd, SIOCSIFMTU, arg); + goto out; case _IOWR('i', 22, struct ifreq): /* SIOCGIFMTU */ - return sys_ioctl(fd, SIOCGIFMTU, arg); + ret = sys_ioctl(fd, SIOCGIFMTU, arg); + goto out; case _IOWR('i', 23, struct ifreq): - return sys_ioctl(fd, SIOCGIFBRDADDR, arg); + ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg); + goto out; case _IOW('i', 24, struct ifreq): - return sys_ioctl(fd, SIOCGIFBRDADDR, arg); + ret = sys_ioctl(fd, SIOCGIFBRDADDR, arg); + goto out; case _IOWR('i', 25, struct ifreq): - return sys_ioctl(fd, SIOCGIFNETMASK, arg); + ret = sys_ioctl(fd, SIOCGIFNETMASK, arg); + goto out; case _IOW('i', 26, struct ifreq): - return sys_ioctl(fd, SIOCSIFNETMASK, arg); + ret = sys_ioctl(fd, SIOCSIFNETMASK, arg); + goto out; case _IOWR('i', 27, struct ifreq): - return sys_ioctl(fd, SIOCGIFMETRIC, arg); + ret = sys_ioctl(fd, SIOCGIFMETRIC, arg); + goto out; case _IOW('i', 28, struct ifreq): - return sys_ioctl(fd, SIOCSIFMETRIC, arg); + ret = sys_ioctl(fd, SIOCSIFMETRIC, arg); + goto out; case _IOW('i', 30, struct arpreq): - return sys_ioctl(fd, SIOCSARP, arg); + ret = sys_ioctl(fd, SIOCSARP, arg); + goto out; case _IOWR('i', 31, struct arpreq): - return sys_ioctl(fd, SIOCGARP, arg); + ret = sys_ioctl(fd, SIOCGARP, arg); + goto out; case _IOW('i', 32, struct arpreq): - return sys_ioctl(fd, SIOCDARP, arg); + ret = sys_ioctl(fd, SIOCDARP, arg); + goto out; case _IOW('i', 40, struct ifreq): /* SIOCUPPER */ case _IOW('i', 41, struct ifreq): /* SIOCLOWER */ @@ -114,12 +143,15 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) case _IOW('i', 46, struct ifreq): /* SIOCSSDSTATS */ case _IOW('i', 47, struct ifreq): /* SIOCSSESTATS */ case _IOW('i', 48, struct ifreq): /* SIOCSPROMISC */ - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out; case _IOW('i', 49, struct ifreq): - return sys_ioctl(fd, SIOCADDMULTI, arg); + ret = sys_ioctl(fd, SIOCADDMULTI, arg); + goto out; case _IOW('i', 50, struct ifreq): - return sys_ioctl(fd, SIOCDELMULTI, arg); + ret = sys_ioctl(fd, SIOCDELMULTI, arg); + goto out; /* FDDI interface ioctls, unsupported. */ @@ -133,20 +165,24 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) case _IOW('i', 58, struct ifreq): /* SIOCFDGNETMAP */ case _IOW('i', 59, struct ifreq): /* SIOCFDGIOCTL */ printk("FDDI ioctl, returning EOPNOTSUPP\n"); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out; + case _IOW('t', 125, int): /* More stupid tty sunos ioctls, just * say it worked. */ - return 0; + ret = 0; + goto out; /* Non posix grp */ case _IOW('t', 118, int): { int oldval, newval, *ptr; cmd = TIOCSPGRP; ptr = (int *) arg; + ret = -EFAULT; if(get_user(oldval, ptr)) - return -EFAULT; + goto out; ret = sys_ioctl(fd, cmd, arg); __get_user(newval, ptr); if(newval == -1) { @@ -155,7 +191,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) } if(ret == -ENOTTY) ret = -EIO; - return ret; + goto out; } case _IOR('t', 119, int): { @@ -163,8 +199,9 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) cmd = TIOCGPGRP; ptr = (int *) arg; + ret = -EFAULT; if(get_user(oldval, ptr)) - return -EFAULT; + goto out; ret = sys_ioctl(fd, cmd, arg); __get_user(newval, ptr); if(newval == -1) { @@ -173,7 +210,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) } if(ret == -ENOTTY) ret = -EIO; - return ret; + goto out; } } @@ -185,7 +222,10 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) ret = sys_ioctl(fd, cmd, arg); /* so stupid... */ - return (ret == -EINVAL ? -EOPNOTSUPP : ret); + ret = (ret == -EINVAL ? -EOPNOTSUPP : ret); +out: + unlock_kernel(); + return ret; } diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c index 0b90f5d9635e..6bef6e5232db 100644 --- a/arch/sparc/kernel/sys_solaris.c +++ b/arch/sparc/kernel/sys_solaris.c @@ -11,19 +11,31 @@ #include #include #include +#include +#include asmlinkage int do_solaris_syscall (struct pt_regs *regs) { + int ret; + + lock_kernel(); current->personality = PER_SVR4; current->exec_domain = lookup_exec_domain(PER_SVR4); if (current->exec_domain && current->exec_domain->handler){ current->exec_domain->handler (regs); - current->exec_domain->use_count = 0; - return regs->u_regs [UREG_I0]; + + /* What is going on here? Why do we do this? */ + + /* XXX current->exec_domain->use_count = 0; XXX */ + + ret = regs->u_regs [UREG_I0]; + } else { + printk ("No solaris handler\n"); + send_sig (SIGSEGV, current, 1); + ret = 0; } - printk ("No solaris handler\n"); - send_sig (SIGSEGV, current, 1); - return 0; + unlock_kernel(); + return ret; } diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 947c9ae047b7..736b9e63421b 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.33 1996/12/24 08:59:33 davem Exp $ +/* $Id: sys_sparc.c,v 1.34 1997/01/06 06:52:35 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -33,11 +35,19 @@ extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { + unsigned long ret; + + lock_kernel(); if(sparc_cpu_model == sun4c) { - if(brk >= 0x20000000 && brk < 0xe0000000) - return current->mm->brk; + if(brk >= 0x20000000 && brk < 0xe0000000) { + ret = current->mm->brk; + goto out; + } } - return sys_brk(brk); + ret = sys_brk(brk); +out: + unlock_kernel(); + return ret; } /* @@ -49,13 +59,15 @@ asmlinkage int sparc_pipe(struct pt_regs *regs) int fd[2]; int error; + lock_kernel(); error = do_pipe(fd); - if (error) { - return error; - } else { - regs->u_regs[UREG_I1] = fd[1]; - return fd[0]; - } + if (error) + goto out; + regs->u_regs[UREG_I1] = fd[1]; + error = fd[0]; +out: + unlock_kernel(); + return error; } /* @@ -66,52 +78,67 @@ asmlinkage int sparc_pipe(struct pt_regs *regs) asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { - int version; + int version, err; + lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + err = sys_semop (first, (struct sembuf *)ptr, second); + goto out; case SEMGET: - return sys_semget (first, second, third); + err = sys_semget (first, second, third); + goto out; case SEMCTL: { union semun fourth; + err = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + err = -EFAULT; if(get_user(fourth.__pad, (void **)ptr)) - return -EFAULT; - return sys_semctl (first, second, third, fourth); + goto out; + err = sys_semctl (first, second, third, fourth); + goto out; } default: - return -EINVAL; + err = -EINVAL; + goto out; } if (call <= MSGCTL) switch (call) { case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); + err = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; + err = -EINVAL; if (!ptr) - return -EINVAL; + goto out; + err = -EFAULT; if(copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp))) - return -EFAULT; - return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; } case 1: default: - return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; } case MSGGET: - return sys_msgget ((key_t) first, second); + err = sys_msgget ((key_t) first, second); + goto out; case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + err = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; default: - return -EINVAL; + err = -EINVAL; + goto out; } if (call <= SHMCTL) switch (call) { @@ -119,28 +146,37 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, switch (version) { case 0: default: { ulong raddr; - int err; - err = sys_shmat (first, (char *) ptr, second, &raddr); if (err) - return err; + goto out; + err = -EFAULT; if(put_user (raddr, (ulong *) third)) - return -EFAULT; - return 0; + goto out; + err = 0; + goto out; } case 1: /* iBCS2 emulator entry point */ - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + err = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; } case SHMDT: - return sys_shmdt ((char *)ptr); + err = sys_shmdt ((char *)ptr); + goto out; case SHMGET: - return sys_shmget (first, second, third); + err = sys_shmget (first, second, third); + goto out; case SHMCTL: - return sys_shmctl (first, second, (struct shmid_ds *) ptr); + err = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; default: - return -EINVAL; + err = -EINVAL; + goto out; } - return -EINVAL; + else + err = -EINVAL; +out: + unlock_kernel(); + return err; } extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); @@ -151,30 +187,37 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long off) { struct file * file = NULL; - long retval; + unsigned long retval = -EBADF; + lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])){ - return -EBADF; + goto out; } } + retval = -ENOMEM; if(!(flags & MAP_FIXED) && !addr) { addr = get_unmapped_area(addr, len); if(!addr){ - return -ENOMEM; + goto out; } } /* See asm-sparc/uaccess.h */ + retval = -EINVAL; if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) - return -EINVAL; + goto out; if(sparc_cpu_model == sun4c) { - if(((addr >= 0x20000000) && (addr < 0xe0000000))) - return current->mm->brk; + if(((addr >= 0x20000000) && (addr < 0xe0000000))) { + retval = current->mm->brk; + goto out; + } } retval = do_mmap(file, addr, len, prot, flags, off); +out: + unlock_kernel(); return retval; } @@ -182,8 +225,10 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) { + lock_kernel(); printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]); show_regs (regs); + unlock_kernel(); return -ENOSYS; } @@ -192,6 +237,7 @@ c_sys_nis_syscall (struct pt_regs *regs) asmlinkage void sparc_breakpoint (struct pt_regs *regs) { + lock_kernel(); #ifdef DEBUG_SPARC_BREAKPOINT printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc); #endif @@ -199,6 +245,7 @@ sparc_breakpoint (struct pt_regs *regs) #ifdef DEBUG_SPARC_BREAKPOINT printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc); #endif + unlock_kernel(); } extern void check_pending(int signum); @@ -207,33 +254,38 @@ asmlinkage int sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) { struct sigaction new_sa, *p; + int err = -EINVAL; + lock_kernel(); if(signum < 0) { current->tss.new_signal = 1; signum = -signum; } if (signum<1 || signum>32) - return -EINVAL; + goto out; p = signum - 1 + current->sig->action; if (action) { - int err = verify_area(VERIFY_READ,action,sizeof(struct sigaction)); + err = verify_area(VERIFY_READ,action,sizeof(struct sigaction)); if (err) - return err; + goto out; + err = -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; + goto out; + err = -EFAULT; if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) - return -EFAULT; + goto out; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) - return err; + goto out; } } if (oldaction) { + err = -EFAULT; if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - return -EFAULT; + goto out; } if (action) { @@ -241,7 +293,10 @@ sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *o check_pending(signum); } - return 0; + err = 0; +out: + unlock_kernel(); + return err; } #ifndef CONFIG_AP1000 diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 6add5e36bcb2..df403b6fc12e 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.71 1996/12/29 20:46:02 davem Exp $ +/* $Id: sys_sunos.c,v 1.75 1997/01/26 07:12:31 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,22 +8,6 @@ * * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) * - * The sunos_poll routine is based on iBCS2's poll routine, this - * is the copyright message for that file: - * - * This file contains the procedures for the handling of poll. - * - * Copyright (C) 1994 Eric Youngdale - * - * Created for Linux based loosely upon linux select code, which - * in turn is loosely based upon Mathius Lattner's minix - * patches by Peter MacDonald. Heavily edited by Linus. - * - * Poll is used by SVr4 instead of select, and it has considerably - * more functionality. Parts of it are related to STREAMS, and since - * we do not have streams, we fake it. In fact, select() still exists - * under SVr4, but libc turns it into a poll() call instead. We attempt - * to do the inverse mapping. */ #include @@ -46,6 +30,8 @@ #include #include #include +#include +#include #include #ifndef KERNEL_DS @@ -79,19 +65,22 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, struct file * file = NULL; unsigned long retval, ret_type; + lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", current->comm); flags &= ~MAP_NORESERVE; } + retval = -EBADF; if(!(flags & MAP_ANONYMOUS)) if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + retval = -ENOMEM; if(!(flags & MAP_FIXED) && !addr) { addr = get_unmapped_area(addr, len); if(!addr) - return -ENOMEM; + goto out; } /* If this is ld.so or a shared library doing an mmap * of /dev/zero, transform it into an anonymous mapping. @@ -108,19 +97,23 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, flags &= ~_MAP_NEW; /* See asm-sparc/uaccess.h */ + retval = -EINVAL; if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) - return -EINVAL; + goto out; if(sparc_cpu_model == sun4c) { - if(((addr >= 0x20000000) && (addr < 0xe0000000))) - return current->mm->brk; + if(((addr >= 0x20000000) && (addr < 0xe0000000))) { + retval = current->mm->brk; + goto out; + } } retval = do_mmap(file, addr, len, prot, flags, off); - if(ret_type) - return retval; - else - return ((retval < PAGE_OFFSET) ? 0 : retval); + if(!ret_type) + retval = ((retval < PAGE_OFFSET) ? 0 : retval); +out: + unlock_kernel(); + return retval; } /* lmbench calls this, just say "yeah, ok" */ @@ -135,23 +128,26 @@ asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, c */ asmlinkage int sunos_brk(unsigned long brk) { - int freepages; + int freepages, retval = -ENOMEM; unsigned long rlim; unsigned long newbrk, oldbrk; + lock_kernel(); if(sparc_cpu_model == sun4c) { - if(brk >= 0x20000000 && brk < 0xe0000000) - return -ENOMEM; + if(brk >= 0x20000000 && brk < 0xe0000000) { + goto out; + } } if (brk < current->mm->end_code) - return -ENOMEM; + goto out; newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(current->mm->brk); + retval = 0; if (oldbrk == newbrk) { current->mm->brk = brk; - return 0; + goto out; } /* @@ -160,22 +156,23 @@ asmlinkage int sunos_brk(unsigned long brk) if (brk <= current->mm->brk) { current->mm->brk = brk; do_munmap(newbrk, oldbrk-newbrk); - return 0; + goto out; } /* * Check against rlimit and stack.. */ + retval = -ENOMEM; rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (brk - current->mm->end_code > rlim) - return -ENOMEM; + goto out; /* * Check against existing mmap mappings. */ if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE)) - return -ENOMEM; + goto out; /* * stupid algorithm to decide if we have enough memory: while @@ -190,7 +187,7 @@ asmlinkage int sunos_brk(unsigned long brk) freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; if (freepages < 0) - return -ENOMEM; + goto out; /* * Ok, we have probably got enough memory - let it rip. */ @@ -198,20 +195,25 @@ asmlinkage int sunos_brk(unsigned long brk) do_mmap(NULL, oldbrk, newbrk-oldbrk, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - return 0; + retval = 0; +out: + unlock_kernel(); + return retval; } asmlinkage unsigned long sunos_sbrk(int increment) { int error; - unsigned long oldbrk = current->mm->brk; + unsigned long oldbrk; /* This should do it hopefully... */ + lock_kernel(); + oldbrk = current->mm->brk; error = sunos_brk(((int) current->mm->brk) + increment); - if(error) - return error; - else - return oldbrk; + if(!error) + error = oldbrk; + unlock_kernel(); + return error; } /* XXX Completely undocumented, and completely magic... @@ -221,8 +223,10 @@ asmlinkage unsigned long sunos_sbrk(int increment) */ asmlinkage unsigned long sunos_sstk(int increment) { + lock_kernel(); printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n", current->comm, increment); + unlock_kernel(); return -1; } @@ -243,10 +247,11 @@ static char *vstrings[] = { asmlinkage void sunos_vadvise(unsigned long strategy) { /* I wanna see who uses this... */ + lock_kernel(); printk("%s: Advises us to use %s paging strategy\n", current->comm, strategy <= 3 ? vstrings[strategy] : "BOGUS"); - return; /* We don't do diddly... */ + unlock_kernel(); } /* Same as vadvise, and just as bogus, but for a range of virtual @@ -270,11 +275,12 @@ asmlinkage void sunos_madvise(unsigned long address, unsigned long len, unsigned long strategy) { /* I wanna see who uses this... */ + lock_kernel(); printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n", current->comm, strategy <= 4 ? mstrings[strategy] : "BOGUS", address, len); - return; /* We don't do diddly... */ + unlock_kernel(); } /* Places into character array, the status of all the pages in the passed @@ -293,33 +299,39 @@ asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array) pmd_t *pmdp; pte_t *ptep; unsigned long limit; - int num_pages, pnum; + int num_pages, pnum, retval = -EINVAL; + lock_kernel(); if(addr & ~(PAGE_MASK)) - return -EINVAL; + goto out; num_pages = (len / PAGE_SIZE); + retval = -EFAULT; if(verify_area(VERIFY_WRITE, array, num_pages)) - return -EFAULT; + goto out; + retval = -ENOMEM; if((addr >= PAGE_OFFSET) || ((addr + len) > PAGE_OFFSET)) - return -ENOMEM; /* I'm sure you're curious about kernel mappings.. */ + goto out; /* I'm sure you're curious about kernel mappings.. */ /* Wheee, go through pte's */ pnum = 0; for(limit = addr + len; addr < limit; addr += PAGE_SIZE, pnum++) { pgdp = pgd_offset(current->mm, addr); if(pgd_none(*pgdp)) - return -ENOMEM; /* As per SunOS manpage */ + goto out; /* As per SunOS manpage */ pmdp = pmd_offset(pgdp, addr); if(pmd_none(*pmdp)) - return -ENOMEM; /* As per SunOS manpage */ + goto out; /* As per SunOS manpage */ ptep = pte_offset(pmdp, addr); if(pte_none(*ptep)) - return -ENOMEM; /* As per SunOS manpage */ + goto out; /* As per SunOS manpage */ /* Page in core or Swapped page? */ __put_user((pte_present(*ptep) ? 1 : 0), &array[pnum]); } - return 0; /* Success... I think... */ + retval = 0; /* Success... I think... */ +out: + unlock_kernel(); + return retval; } /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE @@ -339,10 +351,12 @@ 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(); return old; } @@ -351,10 +365,12 @@ 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(); return retval; } @@ -410,14 +426,17 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) struct file * file; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; - int error; + int error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) - return -EINVAL; + goto out; buf.curr = (struct sunos_dirent *) dirent; buf.previous = NULL; @@ -425,12 +444,17 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir); if (error < 0) - return error; + goto out; lastdirent = buf.previous; - if (!lastdirent) - return buf.error; - put_user(file->f_pos, &lastdirent->d_off); - return cnt - buf.count; + if (!lastdirent) { + error = buf.error; + } else { + put_user(file->f_pos, &lastdirent->d_off); + error = cnt - buf.count; + } +out: + unlock_kernel(); + return error; } /* Old sunos getdirentries, severely broken compatibility stuff here. */ @@ -477,14 +501,17 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi struct file * file; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; - int error; + int error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) - return -EINVAL; + goto out; buf.curr = (struct sunos_direntry *) dirent; buf.previous = NULL; @@ -492,26 +519,36 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry); if (error < 0) - return error; + goto out; lastdirent = buf.previous; - if (!lastdirent) - return buf.error; - put_user(file->f_pos, basep); - return cnt - buf.count; + if (!lastdirent) { + error = buf.error; + } else { + put_user(file->f_pos, basep); + error = cnt - buf.count; + } +out: + unlock_kernel(); + return error; } asmlinkage int sunos_getdomainname(char *name, int len) { int nlen = strlen(system_utsname.domainname); + int ret = -EFAULT; + lock_kernel(); if (nlen < len) len = nlen; if(len > __NEW_UTS_LEN) - return -EFAULT; + goto out; if(copy_to_user(name, system_utsname.domainname, len)) - return -EFAULT; - return 0; + goto out; + ret = 0; +out: + unlock_kernel(); + return ret; } struct sunos_utsname { @@ -525,22 +562,29 @@ struct sunos_utsname { asmlinkage int sunos_uname(struct sunos_utsname *name) { + int ret = -EFAULT; + + lock_kernel(); if(!name) - return -EFAULT; + goto out; if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1)) - return -EFAULT; + goto out; copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); put_user('\0', &name->nname[8]); copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } asmlinkage int sunos_nosys(void) { struct pt_regs *regs; + lock_kernel(); regs = current->tss.kregs; current->tss.sig_address = regs->pc; current->tss.sig_desc = regs->u_regs[UREG_G1]; @@ -548,6 +592,7 @@ asmlinkage int sunos_nosys(void) printk("Process makes ni_syscall number %d, register dump:\n", (int) regs->u_regs[UREG_G1]); show_regs(regs); + unlock_kernel(); return -ENOSYS; } @@ -556,33 +601,51 @@ asmlinkage int sunos_nosys(void) */ asmlinkage int sunos_fpathconf(int fd, int name) { + int ret; + + lock_kernel(); switch(name) { case _PCONF_LINK: - return LINK_MAX; + ret = LINK_MAX; + break; case _PCONF_CANON: - return MAX_CANON; + ret = MAX_CANON; + break; case _PCONF_INPUT: - return MAX_INPUT; + ret = MAX_INPUT; + break; case _PCONF_NAME: - return NAME_MAX; + ret = NAME_MAX; + break; case _PCONF_PATH: - return PATH_MAX; + ret = PATH_MAX; + break; case _PCONF_PIPE: - return PIPE_BUF; - case _PCONF_CHRESTRICT: - return 1; /* XXX Investigate XXX */ - case _PCONF_NOTRUNC: - return 0; /* XXX Investigate XXX */ + ret = PIPE_BUF; + break; + case _PCONF_CHRESTRICT: /* XXX Investigate XXX */ + ret = 1; + break; + case _PCONF_NOTRUNC: /* XXX Investigate XXX */ case _PCONF_VDISABLE: - return 0; + ret = 0; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + unlock_kernel(); + return ret; } asmlinkage int sunos_pathconf(char *path, int name) { - return sunos_fpathconf(0, name); /* XXX cheese XXX */ + int ret; + + lock_kernel(); + ret = sunos_fpathconf(0, name); /* XXX cheese XXX */ + unlock_kernel(); + return ret; } /* SunOS mount system call emulation */ @@ -591,9 +654,14 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp); asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { + int ret; + /* SunOS binaries expect that select won't change the tvp contents */ + lock_kernel(); current->personality |= STICKY_TIMEOUTS; - return sys_select (width, inp, outp, exp, tvp); + ret = sys_select (width, inp, outp, exp, tvp); + unlock_kernel(); + return ret; } asmlinkage void sunos_nop(void) @@ -757,15 +825,17 @@ asmlinkage int sunos_mount(char *type, char *dir, int flags, void *data) { int linux_flags = MS_MGC_MSK; /* new semantics */ + int ret = -EINVAL; char *dev_fname = 0; + lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) - return -EINVAL; + goto out; /* Do not allow for those flags we don't support */ if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5)) - return -EINVAL; + goto out; if(flags & SMNT_REMOUNT) linux_flags |= MS_REMOUNT; @@ -780,14 +850,20 @@ sunos_mount(char *type, char *dir, int flags, void *data) } else if(strcmp(type, "minix") == 0) { dev_fname = (char *) data; } else if(strcmp(type, "nfs") == 0) { - return sunos_nfs_mount (dir, flags, data); + ret = sunos_nfs_mount (dir, flags, data); + goto out; } else if(strcmp(type, "ufs") == 0) { printk("Warning: UFS filesystem mounts unsupported.\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } else if(strcmp(type, "proc")) { - return -ENODEV; + ret = -ENODEV; + goto out; } - return sys_mount(dev_fname, dir, type, linux_flags, NULL); + ret = sys_mount(dev_fname, dir, type, linux_flags, NULL); +out: + unlock_kernel(); + return ret; } extern asmlinkage int sys_setsid(void); @@ -795,217 +871,102 @@ extern asmlinkage int sys_setpgid(pid_t, pid_t); asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) { + int ret; + /* So stupid... */ + lock_kernel(); if((!pid || pid == current->pid) && !pgid) { sys_setsid(); - return 0; + ret = 0; } else { - return sys_setpgid(pid, pgid); + ret = sys_setpgid(pid, pgid); } + unlock_kernel(); + return ret; } /* So stupid... */ extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *); asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru) { - return sys_wait4((pid ? pid : -1), stat_addr, options, ru); + int ret; + + lock_kernel(); + ret = sys_wait4((pid ? pid : -1), stat_addr, options, ru); + unlock_kernel(); + return ret; } extern int kill_pg(int, int, int); asmlinkage int sunos_killpg(int pgrp, int sig) { - return kill_pg(pgrp, sig, 0); + int ret; + + lock_kernel(); + ret = kill_pg(pgrp, sig, 0); + unlock_kernel(); + return ret; } asmlinkage int sunos_audit(void) { + lock_kernel(); printk ("sys_audit\n"); + unlock_kernel(); return -1; } extern asmlinkage unsigned long sunos_gethostid(void) { - return ((unsigned long)idprom->id_machtype << 24) | - (unsigned long)idprom->id_sernum; + unsigned long ret; + + lock_kernel(); + ret = ((unsigned long)idprom->id_machtype << 24) | + (unsigned long)idprom->id_sernum; + unlock_kernel(); + return ret; } extern asmlinkage long sunos_sysconf (int name) { + long ret; + + lock_kernel(); switch (name){ case _SC_ARG_MAX: - return ARG_MAX; + ret = ARG_MAX; + break; case _SC_CHILD_MAX: - return CHILD_MAX; + ret = CHILD_MAX; + break; case _SC_CLK_TCK: - return HZ; + ret = HZ; + break; case _SC_NGROUPS_MAX: - return NGROUPS_MAX; + ret = NGROUPS_MAX; + break; case _SC_OPEN_MAX: - return OPEN_MAX; + ret = OPEN_MAX; + break; case _SC_JOB_CONTROL: - return 1; /* yes, we do support job control */ + ret = 1; /* yes, we do support job control */ + break; case _SC_SAVED_IDS: - return 1; /* yes, we do support saved uids */ + ret = 1; /* yes, we do support saved uids */ + break; case _SC_VERSION: /* mhm, POSIX_VERSION is in /usr/include/unistd.h * should it go on /usr/include/linux? */ - return 199009L; - } - return -1; -} - -#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y)) - -#define POLLIN 1 -#define POLLPRI 2 -#define POLLOUT 4 -#define POLLERR 8 -#define POLLHUP 16 -#define POLLNVAL 32 -#define POLLRDNORM 64 -#define POLLWRNORM POLLOUT -#define POLLRDBAND 128 -#define POLLWRBAND 256 - -#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN) -#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT) -#define LINUX_POLLERR (POLLERR) - -static inline void free_wait(select_table * p) -{ - struct select_table_entry * entry = p->entry + p->nr; - - while (p->nr > 0) { - p->nr--; - entry--; - remove_wait_queue(entry->wait_address,&entry->wait); - } -} - - -/* Copied directly from fs/select.c */ -static int check(int flag, select_table * wait, struct file * file) -{ - struct inode * inode; - struct file_operations *fops; - int (*select) (struct inode *, struct file *, int, select_table *); - - inode = file->f_inode; - if ((fops = file->f_op) && (select = fops->select)) - return select(inode, file, flag, wait) - || (wait && select(inode, file, flag, NULL)); - if (S_ISREG(inode->i_mode)) - return 1; - return 0; -} - -struct poll { - int fd; - short events; - short revents; -}; - -int sunos_poll(struct poll * ufds, size_t nfds, int timeout) -{ - int i,j, count, fdcount, retflag; - struct poll * fdpnt; - struct poll * fds, *fds1; - select_table wait_table, *wait; - struct select_table_entry *entry; - - if (nfds > NR_OPEN) - return -EINVAL; - - if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL)) - || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) - return -ENOMEM; - - if(copy_from_user(fds, ufds, nfds*sizeof(struct poll))) { - free_page((unsigned long)entry); - kfree(fds); - return -EFAULT; - } - - if (timeout < 0) - current->timeout = 0x7fffffff; - else { - current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ)); - if (current->timeout <= jiffies) - current->timeout = 0; - } - - count = 0; - wait_table.nr = 0; - wait_table.entry = entry; - wait = &wait_table; - - for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { - i = fdpnt->fd; - fdpnt->revents = 0; - if (!current->files->fd[i] || !current->files->fd[i]->f_inode) - fdpnt->revents = POLLNVAL; - } -repeat: - current->state = TASK_INTERRUPTIBLE; - for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { - i = fdpnt->fd; - - if(i < 0) continue; - if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue; - - if ((fdpnt->events & LINUX_POLLIN) - && check(SEL_IN, wait, current->files->fd[i])) { - retflag = 0; - if (fdpnt->events & POLLIN) - retflag = POLLIN; - if (fdpnt->events & POLLRDNORM) - retflag = POLLRDNORM; - fdpnt->revents |= retflag; - count++; - wait = NULL; - } - - if ((fdpnt->events & LINUX_POLLOUT) && - check(SEL_OUT, wait, current->files->fd[i])) { - fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events); - count++; - wait = NULL; - } - - if (check(SEL_EX, wait, current->files->fd[i])) { - fdpnt->revents |= POLLHUP; - count++; - wait = NULL; - } - } - - if ((current->signal & (~current->blocked))) - return -EINTR; - - wait = NULL; - if (!count && current->timeout > jiffies) { - schedule(); - goto repeat; - } - - free_wait(&wait_table); - free_page((unsigned long) entry); - - /* OK, now copy the revents fields back to user space. */ - fds1 = fds; - fdcount = 0; - for(i=0; i < (int)nfds; i++, ufds++, fds++) { - if (fds->revents) { - fdcount++; - } - __put_user(fds->revents, &ufds->revents); - } - kfree(fds1); - current->timeout = 0; - current->state = TASK_RUNNING; - return fdcount; + ret = 199009L; + break; + default: + ret = -1; + break; + }; + unlock_kernel(); + return ret; } extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); @@ -1016,7 +977,9 @@ asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3, void *ptr) { union semun arg4; + int ret; + lock_kernel(); switch (op) { case 0: /* Most arguments match on a 1:1 basis but cmd doesn't */ @@ -1038,16 +1001,22 @@ asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, } /* sys_semctl(): */ arg4.__pad=ptr; /* value to modify semaphore to */ - return sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 ); + ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 ); + break; case 1: /* sys_semget(): */ - return sys_semget((key_t)arg1, (int)arg2, (int)arg3); + ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3); + break; case 2: /* sys_semop(): */ - return sys_semop((int)arg1, (struct sembuf *)arg2, (unsigned)arg3); + ret = sys_semop((int)arg1, (struct sembuf *)arg2, (unsigned)arg3); + break; default: - return -EINVAL; - } + ret = -EINVAL; + break; + }; + unlock_kernel(); + return ret; } extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); @@ -1061,32 +1030,43 @@ asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2, unsigned long raddr; int rval; + lock_kernel(); switch(op) { case 0: /* sys_shmat(): attach a shared memory area */ rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr); - if(rval != 0) - return rval; - return (int) raddr; + if(!rval) + rval = (int) raddr; + break; case 1: /* sys_shmctl(): modify shared memory area attr. */ rval = sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3); - return (rval); + break; case 2: /* sys_shmdt(): detach a shared memory area */ - return sys_shmdt((char *)arg1); + rval = sys_shmdt((char *)arg1); + break; case 3: /* sys_shmget(): get a shared memory area */ - return sys_shmget((key_t)arg1,(int)arg2,(int)arg3); + rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3); + break; default: - return -EINVAL; - } + rval = -EINVAL; + break; + }; + unlock_kernel(); + return rval; } asmlinkage int sunos_open(const char *filename, int flags, int mode) { + int ret; + + lock_kernel(); current->personality |= PER_BSD; - return sys_open (filename, flags, mode); + ret = sys_open (filename, flags, mode); + unlock_kernel(); + return ret; } @@ -1115,37 +1095,72 @@ extern asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, asmlinkage int sunos_read(unsigned int fd,char *buf,int count) { - return check_nonblock(sys_read(fd,buf,count),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_read(fd,buf,count),fd); + unlock_kernel(); + return ret; } asmlinkage int sunos_readv(unsigned long fd, const struct iovec * vector, long count) { - return check_nonblock(sys_readv(fd,vector,count),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_readv(fd,vector,count),fd); + lock_kernel(); + return ret; } asmlinkage int sunos_write(unsigned int fd,char *buf,int count) { - return check_nonblock(sys_write(fd,buf,count),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_write(fd,buf,count),fd); + unlock_kernel(); + return ret; } asmlinkage int sunos_writev(unsigned long fd, const struct iovec * vector, long count) { - return check_nonblock(sys_writev(fd,vector,count),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_writev(fd,vector,count),fd); + unlock_kernel(); + return ret; } asmlinkage int sunos_recv(int fd, void * ubuf, int size, unsigned flags) { - return check_nonblock(sys_recv(fd,ubuf,size,flags),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_recv(fd,ubuf,size,flags),fd); + unlock_kernel(); + return ret; } asmlinkage int sunos_send(int fd, void * buff, int len, unsigned flags) { - return check_nonblock(sys_send(fd,buff,len,flags),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_send(fd,buff,len,flags),fd); + unlock_kernel(); + return ret; } asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen) { - return check_nonblock(sys_accept(fd,sa,addrlen),fd); + int ret; + + lock_kernel(); + ret = check_nonblock(sys_accept(fd,sa,addrlen),fd); + unlock_kernel(); + return ret; } #define SUNOS_SV_INTERRUPT 2 @@ -1157,33 +1172,38 @@ asmlinkage int sunos_sigaction(int signum, const struct sigaction *action, { struct sigaction new_sa, *p; const int sigaction_size = sizeof (struct sigaction) - sizeof (void *); - int err; + int err = -EINVAL; + lock_kernel(); current->personality |= PER_BSD; if (signum<1 || signum>32) - return -EINVAL; + goto out; p = signum - 1 + current->sig->action; if (action) { + err = -EFAULT; if(copy_from_user(&new_sa, action, sigaction_size)) - return -EFAULT; + goto out; + err = -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; + goto out; memset(&new_sa, 0, sizeof(struct sigaction)); + err = -EFAULT; if(copy_from_user(&new_sa, action, sigaction_size)) - return -EFAULT; + goto out; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) - return err; + goto out; } new_sa.sa_flags ^= SUNOS_SV_INTERRUPT; } if (oldaction) { + err = -EFAULT; if (copy_to_user(oldaction, p, sigaction_size)) - return -EFAULT; + goto out; if (oldaction->sa_flags & SA_RESTART) oldaction->sa_flags &= ~SA_RESTART; else @@ -1194,8 +1214,10 @@ asmlinkage int sunos_sigaction(int signum, const struct sigaction *action, *p = new_sa; check_pending(signum); } - - return 0; + err = 0; +out: + unlock_kernel(); + return err; } @@ -1206,34 +1228,32 @@ asmlinkage int sunos_setsockopt(int fd, int level, int optname, char *optval, int optlen) { int tr_opt = optname; + int ret; - if (level == SOL_IP) - { - /* - * Multicast socketopts (ttl, membership) - */ + lock_kernel(); + if (level == SOL_IP) { + /* Multicast socketopts (ttl, membership) */ if (tr_opt >=2 && tr_opt <= 6) - { tr_opt += 30; - } } - return sys_setsockopt(fd, level, tr_opt, optval, optlen); + ret = sys_setsockopt(fd, level, tr_opt, optval, optlen); + unlock_kernel(); + return ret; } asmlinkage int sunos_getsockopt(int fd, int level, int optname, char *optval, int *optlen) { int tr_opt = optname; + int ret; - if (level == SOL_IP) - { - /* - * Multicast socketopts (ttl, membership) - */ + lock_kernel(); + if (level == SOL_IP) { + /* Multicast socketopts (ttl, membership) */ if (tr_opt >=2 && tr_opt <= 6) - { tr_opt += 30; - } } - return sys_getsockopt(fd, level, tr_opt, optval, optlen); + ret = sys_getsockopt(fd, level, tr_opt, optval, optlen); + unlock_kernel(); + return ret; } diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 4bf526c1d643..32f3a7676e4e 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.56 1996/12/29 20:46:03 davem Exp $ +/* $Id: systbls.S,v 1.58 1997/01/26 07:12:31 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -11,30 +11,6 @@ #include - /* READ THIS BEFORE DICKING WITH THIS TABLE... - * - * The format of these entries is kind of peculiar - * to optimize non-blocking easy syscalls. If - * it is a difficult call or it will sleep the entry - * is just to word aligned address of the function - * routine to call. If the lowest bit of the entry - * is set then (entry & ~1) is the address of the low - * in-trap-window assembler routine which will handle - * the system call at the lowest possible level. For - * these low level optimized routines no state is saved - * at all and the usual restrictions reply. Act as - * if you got called directly from the trap table. - * Some of these optimized routines try really hard - * to get around a state save, if you run into trouble - * you can still survive by branching to the label - * syscall_is_too_hard which is in entry.S If you - * have to back out like this you _must_ preserve the - * value of %l0, %l1, %l2, and %l7 when you were called - * so be _careful_. - */ - -#define LOWSYS(func) (CONCAT(func, _low) + 1) - .data .align 4 @@ -78,25 +54,29 @@ 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), 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_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_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage) +/*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) + .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) + .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_readv) .long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown) .long C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid) .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate) .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), 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_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_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_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) @@ -193,7 +173,7 @@ C_LABEL(sunos_sys_table): .long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) /*150*/ .long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) + .long C_LABEL(sys_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs) .long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname) @@ -228,257 +208,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) - -#if 0 -/* Not used yet - {net, open}bsd is a TODO */ - /* {net, open}bsd system call table. */ - - .align 4 - .globl C_LABEL(bsd_sys_table) -C_LABEL(bsd_sys_table): - .long C_LABEL(sunos_nosys)/*SYSCALL*/, C_LABEL(sunos_nosys)/*EXIT*/ - .long C_LABEL(sunos_nosys)/*FORK*/, C_LABEL(sunos_nosys)/*READ*/ - .long C_LABEL(sunos_nosys)/*WRITE*/, C_LABEL(sunos_nosys)/*OPEN*/ - .long C_LABEL(sunos_nosys)/*CLOSE*/, C_LABEL(sunos_nosys)/*WAIT4*/ - .long C_LABEL(sunos_nosys)/*CREAT*/, C_LABEL(sunos_nosys)/*LINK*/ - .long C_LABEL(sunos_nosys)/*UNLINK*/, C_LABEL(sunos_nosys)/*EXECV*/ - .long C_LABEL(sunos_nosys)/*CHDIR*/, C_LABEL(sunos_nosys)/*FCHDIR*/ - .long C_LABEL(sunos_nosys)/*MKNOD*/, C_LABEL(sunos_nosys)/*CHMOD*/ - .long C_LABEL(sunos_nosys)/*CHOWN*/, C_LABEL(sunos_nosys)/*BREAK*/ - .long C_LABEL(sunos_nosys)/*GETFSSTAT*/, C_LABEL(sunos_nosys)/*OLSEEK*/ - .long C_LABEL(sunos_nosys)/*GETPID*/, C_LABEL(sunos_nosys)/*MOUNT*/ - .long C_LABEL(sunos_nosys)/*UNMOUNT*/, C_LABEL(sunos_nosys)/*SETUID*/ - .long C_LABEL(sunos_nosys)/*GETUID*/, C_LABEL(sunos_nosys)/*GETEUID*/ - .long C_LABEL(sunos_nosys)/*PTRACE*/, C_LABEL(sunos_nosys)/*RECVMSG*/ - .long C_LABEL(sunos_nosys)/*SENDMSG*/, C_LABEL(sunos_nosys)/*RECVFROM*/ - .long C_LABEL(sunos_nosys)/*ACCEPT*/, C_LABEL(sunos_nosys)/*GETPEERNAME*/ - .long C_LABEL(sunos_nosys)/*GETSOCKNAME*/, C_LABEL(sunos_nosys)/*ACCESS*/ - .long C_LABEL(sunos_nosys)/*CHFLAGS*/, C_LABEL(sunos_nosys)/*FCHFLAGS*/ - .long C_LABEL(sunos_nosys)/*SYNC*/, C_LABEL(sunos_nosys)/*KILL*/ - .long C_LABEL(sunos_nosys)/*OSTAT*/, C_LABEL(sunos_nosys)/*GETPPID*/ - .long C_LABEL(sunos_nosys)/*OLSTAT*/, C_LABEL(sunos_nosys)/*DUP*/ - .long C_LABEL(sunos_nosys)/*PIPE*/, C_LABEL(sunos_nosys)/*GETEGID*/ - .long C_LABEL(sunos_nosys)/*PROFIL*/, C_LABEL(sunos_nosys)/*KTRACE*/ - .long C_LABEL(sunos_nosys)/*SIGACTION*/, C_LABEL(sunos_nosys)/*GETGID*/ - .long C_LABEL(sunos_nosys)/*SIGPROCMASK*/, C_LABEL(sunos_nosys)/*GETLOGIN*/ - .long C_LABEL(sunos_nosys)/*SETLOGIN*/, C_LABEL(sunos_nosys)/*ACCT*/ - .long C_LABEL(sunos_nosys)/*SIGPENDING*/, C_LABEL(sunos_nosys)/*SIGALTSTACK*/ - .long C_LABEL(sunos_nosys)/*IOCTL*/, C_LABEL(sunos_nosys)/*REBOOT*/ - .long C_LABEL(sunos_nosys)/*REVOKE*/, C_LABEL(sunos_nosys)/*SYMLINK*/ - .long C_LABEL(sunos_nosys)/*READLINK*/, C_LABEL(sunos_nosys)/*EXECVE*/ - .long C_LABEL(sunos_nosys)/*UMASK*/, C_LABEL(sunos_nosys)/*CHROOT*/ - .long C_LABEL(sunos_nosys)/*OFSTAT*/, C_LABEL(sunos_nosys)/*OGETKERNINFO*/ - .long C_LABEL(sunos_nosys)/*OGETPAGESIZE*/, C_LABEL(sunos_nosys)/*MSYNC*/ - .long C_LABEL(sunos_nosys)/*VFORK*/, C_LABEL(sunos_nosys)/*VREAD*/ - .long C_LABEL(sunos_nosys)/*VWRITE*/, C_LABEL(sunos_nosys)/*SBRK*/ - .long C_LABEL(sunos_nosys)/*SSTK*/, C_LABEL(sunos_nosys)/*OMMAP*/ - .long C_LABEL(sunos_nosys)/*VADVISE*/, C_LABEL(sunos_nosys)/*MUNMAP*/ - .long C_LABEL(sunos_nosys)/*MPROTECT*/, C_LABEL(sunos_nosys)/*MADVISE*/ - .long C_LABEL(sunos_nosys)/*VHANGUP*/, C_LABEL(sunos_nosys)/*VLIMIT*/ - .long C_LABEL(sunos_nosys)/*MINCORE*/, C_LABEL(sunos_nosys)/*GETGROUPS*/ - .long C_LABEL(sunos_nosys)/*SETGROUPS*/, C_LABEL(sunos_nosys)/*GETPGRP*/ - .long C_LABEL(sunos_nosys)/*SETPGID*/, C_LABEL(sunos_nosys)/*SETITIMER*/ - .long C_LABEL(sunos_nosys)/*OWAIT*/, C_LABEL(sunos_nosys)/*SWAPON*/ - .long C_LABEL(sunos_nosys)/*GETITIMER*/, C_LABEL(sunos_nosys)/*OGETHOSTNAME*/ - .long C_LABEL(sunos_nosys)/*OSETHOSTNAME*/, C_LABEL(sunos_nosys)/*OGETDTABLESIZE*/ - .long C_LABEL(sunos_nosys)/*DUP2*/, C_LABEL(sunos_nosys)/*GETDOPT*/ - .long C_LABEL(sunos_nosys)/*FCNTL*/, C_LABEL(sunos_nosys)/*SELECT*/ - .long C_LABEL(sunos_nosys)/*SETDOPT*/, C_LABEL(sunos_nosys)/*FSYNC*/ - .long C_LABEL(sunos_nosys)/*SETPRIORITY*/, C_LABEL(sunos_nosys)/*SOCKET*/ - .long C_LABEL(sunos_nosys)/*CONNECT*/, C_LABEL(sunos_nosys)/*OACCEPT*/ - .long C_LABEL(sunos_nosys)/*GETPRIORITY*/, C_LABEL(sunos_nosys)/*OSEND*/ - .long C_LABEL(sunos_nosys)/*ORECV*/, C_LABEL(sunos_nosys)/*SIGRETURN*/ - .long C_LABEL(sunos_nosys)/*BIND*/, C_LABEL(sunos_nosys)/*SETSOCKOPT*/ - .long C_LABEL(sunos_nosys)/*LISTEN*/, C_LABEL(sunos_nosys)/*VTIMES*/ - .long C_LABEL(sunos_nosys)/*OSIGVEC*/, C_LABEL(sunos_nosys)/*OSIGBLOCK*/ - .long C_LABEL(sunos_nosys)/*OSIGSETMASK*/, C_LABEL(sunos_nosys)/*SIGSUSPEND*/ - .long C_LABEL(sunos_nosys)/*OSIGSTACK*/, C_LABEL(sunos_nosys)/*ORECVMSG*/ - .long C_LABEL(sunos_nosys)/*OSENDMSG*/, C_LABEL(sunos_nosys)/*VTRACE*/ - .long C_LABEL(sunos_nosys)/*GETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*GETRUSAGE*/ - .long C_LABEL(sunos_nosys)/*GETSOCKOPT*/, C_LABEL(sunos_nosys)/*ORESUBA*/ - .long C_LABEL(sunos_nosys)/*READV*/, C_LABEL(sunos_nosys)/*WRITEV*/ - .long C_LABEL(sunos_nosys)/*SETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*FCHOWN*/ - .long C_LABEL(sunos_nosys)/*FCHMOD*/, C_LABEL(sunos_nosys)/*ORECVFROM*/ - .long C_LABEL(sunos_nosys)/*OSETREUID*/, C_LABEL(sunos_nosys)/*OSETREGID*/ - .long C_LABEL(sunos_nosys)/*RENAME*/, C_LABEL(sunos_nosys)/*OTRUNCATE*/ - .long C_LABEL(sunos_nosys)/*OFTRUNCATE*/, C_LABEL(sunos_nosys)/*FLOCK*/ - .long C_LABEL(sunos_nosys)/*MKFIFO*/, C_LABEL(sunos_nosys)/*SENDTO*/ - .long C_LABEL(sunos_nosys)/*SHUTDOWN*/, C_LABEL(sunos_nosys)/*SOCKETPAIR*/ - .long C_LABEL(sunos_nosys)/*MKDIR*/, C_LABEL(sunos_nosys)/*RMDIR*/ - .long C_LABEL(sunos_nosys)/*UTIMES*/, C_LABEL(sunos_nosys)/*OSIGRETURN*/ - .long C_LABEL(sunos_nosys)/*ADJTIME*/, C_LABEL(sunos_nosys)/*OGETPEERNAME*/ - .long C_LABEL(sunos_nosys)/*OGETHOSTID*/, C_LABEL(sunos_nosys)/*OSETHOSTID*/ - .long C_LABEL(sunos_nosys)/*OGETRLIMIT*/, C_LABEL(sunos_nosys)/*OSETRLIMIT*/ - .long C_LABEL(sunos_nosys)/*OKILLPG*/, C_LABEL(sunos_nosys)/*SETSID*/ - .long C_LABEL(sunos_nosys)/*QUOTACTL*/, C_LABEL(sunos_nosys)/*OQUOTA*/ - .long C_LABEL(sunos_nosys)/*OGETSOCKNAME*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NFSSVC*/ - .long C_LABEL(sunos_nosys)/*OGETDIRENTRIES*/, C_LABEL(sunos_nosys)/*STATFS*/ - .long C_LABEL(sunos_nosys)/*FSTATFS*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*GETFH*/ - .long C_LABEL(sunos_nosys)/*OGETDOMAINNAME*/ - .long C_LABEL(sunos_nosys)/*OSETDOMAINNAME*/ - .long C_LABEL(sunos_nosys)/*OUNAME*/, C_LABEL(sunos_nosys)/*SYSARCH*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*OSEMSYS*/ - .long C_LABEL(sunos_nosys)/*OMSGSYS*/, C_LABEL(sunos_nosys)/*OSHMSYS*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*SETGID*/ - .long C_LABEL(sunos_nosys)/*SETEGID*/, C_LABEL(sunos_nosys)/*SETEUID*/ - .long C_LABEL(sunos_nosys)/*LFS_BMAPV*/, C_LABEL(sunos_nosys)/*LFS_MARKV*/ - .long C_LABEL(sunos_nosys)/*LFS_SEGCLEAN*/, C_LABEL(sunos_nosys)/*LFS_SEGWAIT*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*STAT*/, C_LABEL(sunos_nosys)/*FSTAT*/ - .long C_LABEL(sunos_nosys)/*LSTAT*/, C_LABEL(sunos_nosys)/*PATHCONF*/ - .long C_LABEL(sunos_nosys)/*FPATHCONF*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*GETRLIMIT*/, C_LABEL(sunos_nosys)/*SETRLIMIT*/ - .long C_LABEL(sunos_nosys)/*GETDIRENTRIES*/, C_LABEL(sunos_nosys)/*MMAP*/ - .long C_LABEL(sunos_nosys)/*__SYSCALL*/, C_LABEL(sunos_nosys)/*LSEEK*/ - .long C_LABEL(sunos_nosys)/*TRUNCATE*/, C_LABEL(sunos_nosys)/*FTRUNCATE*/ - .long C_LABEL(sunos_nosys)/*__SYSCTL*/, C_LABEL(sunos_nosys)/*MLOCK*/ - .long C_LABEL(sunos_nosys)/*MUNLOCK*/, C_LABEL(sunos_nosys)/*UNDELETE*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/ - .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/ - .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/ - .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/ - .long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*__SEMCTL*/, C_LABEL(sunos_nosys)/*SEMGET*/ - .long C_LABEL(sunos_nosys)/*SEMOP*/, C_LABEL(sunos_nosys)/*SEMCONFIG*/ - .long C_LABEL(sunos_nosys)/*MSGCTL*/, C_LABEL(sunos_nosys)/*MSGGET*/ - .long C_LABEL(sunos_nosys)/*MSGSND*/, C_LABEL(sunos_nosys)/*MSGRCV*/ - .long C_LABEL(sunos_nosys)/*SHMAT*/, C_LABEL(sunos_nosys)/*SHMCTL*/ - .long C_LABEL(sunos_nosys)/*SHMDT*/, C_LABEL(sunos_nosys)/*SHMGET*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/ - .long C_LABEL(sunos_nosys)/*MINHERIT*/, C_LABEL(sunos_nosys)/*RFORK*/ -#endif - -#if 0 -/* Not needed - iBCS has its own */ - /* One thing left, Solaris syscall table, TODO */ - .globl C_LABEL(solaris_sys_table) -C_LABEL(solaris_sys_table): -/*0*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_exit), C_LABEL(sys_fork) - .long C_LABEL(sys_read), C_LABEL(sys_write) -/*5*/ .long C_LABEL(solaris_open), C_LABEL(sys_close), C_LABEL(sys_wait4) - .long C_LABEL(sys_creat), C_LABEL(sys_link) -/*10*/ .long C_LABEL(sys_unlink), C_LABEL(sys_nis_syscall), C_LABEL(sys_chdir) - .long C_LABEL(sys_time), C_LABEL(sys_mknod) -/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk) - .long C_LABEL(sys_stat), C_LABEL(sys_lseek) -/*20*/ .long C_LABEL(sunos_getpid), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setuid), C_LABEL(sunos_getuid) -/*25*/ .long C_LABEL(sys_stime), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_alarm), C_LABEL(sys_nis_syscall), C_LABEL(sys_pause) -/*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) -/*35*/ .long C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall) -/*40*/ .long 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) -/*45*/ .long 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) -/*50*/ .long 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) -/*55*/ .long 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) -/*60*/ .long 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) -/*65*/ .long 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) -/*70*/ .long 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) -/*75*/ .long 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) -/*80*/ .long 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) -/*85*/ .long 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) -/*90*/ .long 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) -/*95*/ .long 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) -/*100*/ .long 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) -/*105*/ .long 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) -/*110*/ .long 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) -/*115*/ .long 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) -/*120*/ .long 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) -/*125*/ .long 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) -/*130*/ .long 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) -/*135*/ .long 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) -/*140*/ .long 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) -/*145*/ .long 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) -/*150*/ .long 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) -/*155*/ .long 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) -/*160*/ .long 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) -/*165*/ .long 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) -/*170*/ .long 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) -/*175*/ .long 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) -/*180*/ .long 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) -/*185*/ .long 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) -/*190*/ .long 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) -/*195*/ .long 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) -/*200*/ .long 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) -/*205*/ .long 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) -/*210*/ .long 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) -/*215*/ .long 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) -/*220*/ .long 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) -/*225*/ .long 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) -/*230*/ .long 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) -/*235*/ .long 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) -/*240*/ .long 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) -/*245*/ .long 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) -/*250*/ .long 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) -/*255*/ .long C_LABEL(sys_nis_syscall) -#endif diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index a9be659d45bd..cd1d5e59929f 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.22 1996/12/19 08:06:32 davem Exp $ +/* $Id: time.c,v 1.23 1997/01/26 04:28:34 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -239,6 +239,8 @@ __initfunc(void time_init(void)) unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; + do_get_fast_time = do_gettimeofday; + #if CONFIG_AP1000 init_timers(timer_interrupt); ap_init_time(&xtime); diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 08cd59fda570..19a3afbd0b0c 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.50 1996/12/29 20:46:05 davem Exp $ +/* $Id: traps.c,v 1.53 1997/01/25 02:43:05 miguel Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,8 @@ #include /* for jiffies */ #include #include +#include +#include #include #include @@ -21,7 +23,6 @@ #include #include #include -#include /* #define TRAP_DEBUG */ @@ -93,6 +94,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) { + lock_kernel(); if(type < 0x80) { /* Sun OS's puke from bad traps, Linux survives! */ printk("Unimplemented Sparc TRAP, type = %02lx\n", type); @@ -101,20 +103,21 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) if(type == SP_TRAP_SBPT) { send_sig(SIGTRAP, current, 1); - return; - } - - if(psr & PSR_PS) - die_if_kernel("Kernel bad trap", current->tss.kregs); + } else { + if(psr & PSR_PS) + die_if_kernel("Kernel bad trap", current->tss.kregs); - current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80); - current->tss.sig_address = pc; - send_sig(SIGILL, current, 1); + current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80); + current->tss.sig_address = pc; + send_sig(SIGILL, current, 1); + } + unlock_kernel(); } void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); if(psr & PSR_PS) die_if_kernel("Kernel illegal instruction", regs); #ifdef TRAP_DEBUG @@ -124,21 +127,25 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon if (sparc_cpu_model == sun4c || sparc_cpu_model == sun4) { extern int do_user_muldiv (struct pt_regs *, unsigned long); if (!do_user_muldiv (regs, pc)) - return; + goto out; } current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); +out: + unlock_kernel(); } void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); if(psr & PSR_PS) die_if_kernel("Penguin instruction from Penguin mode??!?!", regs); current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); + unlock_kernel(); } /* XXX User may want to be allowed to do this. XXX */ @@ -146,6 +153,7 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); if(regs->psr & PSR_PS) { printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc, regs->u_regs[UREG_RETPC]); @@ -160,6 +168,7 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon printk ("do_MNA!\n"); #endif send_sig(SIGBUS, current, 1); + unlock_kernel(); } extern void fpsave(unsigned long *fpregs, unsigned long *fsr, @@ -176,6 +185,7 @@ static unsigned long init_fregs[32] __attribute__ ((aligned (8))) = void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); /* Sanity check... */ if(psr & PSR_PS) die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs); @@ -184,7 +194,7 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, regs->psr |= PSR_EF; #ifndef __SMP__ if(last_task_used_math == current) - return; + goto out; if(last_task_used_math) { /* Other processes fpu state, save away */ struct task_struct *fptask = last_task_used_math; @@ -208,6 +218,10 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, } current->flags |= PF_USEDFPU; #endif +#ifndef __SMP__ +out: +#endif + unlock_kernel(); } static unsigned long fake_regs[32] __attribute__ ((aligned (8))); @@ -224,7 +238,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, #else struct task_struct *fpt = current; #endif - + lock_kernel(); put_psr(get_psr() | PSR_EF); /* If nobody owns the fpu right now, just clear the * error into our fake static buffer and hope it don't @@ -237,7 +251,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, #endif fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth); regs->psr &= ~PSR_EF; - return; + goto out; } fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr, &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth); @@ -258,7 +272,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, if(calls > 2) die_if_kernel("Too many Penguin-FPU traps from kernel mode", regs); - return; + goto out; } send_sig(SIGFPE, fpt, 1); #ifndef __SMP__ @@ -267,21 +281,26 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, regs->psr &= ~PSR_EF; if(calls > 0) calls=0; +out: + unlock_kernel(); } void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); if(psr & PSR_PS) die_if_kernel("Penguin overflow trap from kernel mode", regs); current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_TAG; /* as good as any */ send_sig(SIGEMT, current, 1); + unlock_kernel(); } void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); #ifdef TRAP_DEBUG printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); @@ -289,49 +308,60 @@ void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc if(psr & PSR_PS) panic("Tell me what a watchpoint trap is, and I'll then deal " "with such a beast..."); + unlock_kernel(); } void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); #ifdef TRAP_DEBUG printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); #endif send_sig(SIGILL, current, 1); + unlock_kernel(); } void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); send_sig(SIGILL, current, 1); + unlock_kernel(); } void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); #ifdef TRAP_DEBUG printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); #endif printk("INSTRUCTION=%08lx\n", *((unsigned long *) regs->pc)); send_sig(SIGILL, current, 1); + unlock_kernel(); } void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); #ifdef TRAP_DEBUG printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); #endif send_sig(SIGILL, current, 1); + unlock_kernel(); } void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { + lock_kernel(); send_sig(SIGILL, current, 1); + unlock_kernel(); } /* Since we have our mappings set up, on multiprocessors we can spin them @@ -340,7 +370,6 @@ void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc extern void sparc_cpu_startup(void); -extern int linux_num_cpus; extern ctxd_t *srmmu_ctx_table_phys; int linux_smp_still_initting; diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index 6fec431535de..bc4f165c69f1 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.13 1996/11/26 14:01:57 jj Exp $ +/* $Id: unaligned.c,v 1.15 1997/01/16 14:14:42 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -14,6 +14,8 @@ #include #include #include +#include +#include /* #define DEBUG_MNA */ @@ -206,7 +208,7 @@ __asm__ __volatile__ ( \ : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed) \ : "l1", "l2", "g7", "g1"); \ }) - + #define store_common(dst_addr, size, src_val, errh) ({ \ __asm__ __volatile__ ( \ "ld [%2], %%l1\n" \ @@ -332,6 +334,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) enum direction dir = decode_direction(insn); int size = decode_access_size(insn); + lock_kernel(); if(!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n", regs->pc); @@ -344,8 +347,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) " mov %1, %%o1\n\t" : : "r" (regs), "r" (insn) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); - - return; } else { unsigned long addr = compute_effective_address(regs, insn); @@ -379,6 +380,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) } advance(regs); } + unlock_kernel(); } static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, @@ -431,6 +433,7 @@ asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) { enum direction dir; + lock_kernel(); if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) || (((insn >> 30) & 3) != 3)) goto kill_user; @@ -477,15 +480,16 @@ asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) " mov %1, %%o1\n\t" : : "r" (regs), "r" (insn) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); - - return; + goto out; } advance(regs); - return; + goto out; } kill_user: current->tss.sig_address = regs->pc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); +out: + unlock_kernel(); } diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c index 874d7e0f539e..bcde9084a764 100644 --- a/arch/sparc/kernel/windows.c +++ b/arch/sparc/kernel/windows.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include @@ -111,6 +113,7 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who) struct thread_struct *tp; int window; + lock_kernel(); flush_user_windows(); tp = ¤t->tss; for(window = 0; window < tp->w_saved; window++) { @@ -121,4 +124,5 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who) do_exit(SIGILL); } tp->w_saved = 0; + unlock_kernel(); } diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S index 823f9d1fce5e..14416800fe8c 100644 --- a/arch/sparc/kernel/wof.S +++ b/arch/sparc/kernel/wof.S @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.31 1996/12/28 18:14:22 davem Exp $ +/* $Id: wof.S,v 1.32 1997/01/06 06:52:43 davem Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -244,8 +244,6 @@ spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1) mov %l4, %g6 - ENTER_SYSCALL - /* Turn on traps and call c-code to deal with it. */ wr %t_psr, PSR_ET, %psr nop diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S index a1f198050375..7fa420fd694d 100644 --- a/arch/sparc/kernel/wuf.S +++ b/arch/sparc/kernel/wuf.S @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.29 1996/12/28 18:14:23 davem Exp $ +/* $Id: wuf.S,v 1.30 1997/01/06 06:52:44 davem Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -181,8 +181,6 @@ fwin_user_stack_is_bolixed: st %g5, [%curptr + THREAD_UMASK] ! one live user window still st %g0, [%curptr + THREAD_W_SAVED] ! no windows in the buffer - ENTER_SYSCALL - wr %t_psr, PSR_ET, %psr ! enable traps nop call C_LABEL(window_underflow_fault) diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index aad48f23336d..71126ea45ddd 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 1996/11/22 11:57:00 ecd Exp $ +# $Id: Makefile,v 1.21 1997/01/25 06:48:43 davem Exp $ # Makefile for Sparc library files.. # @@ -7,7 +7,7 @@ CFLAGS := $(CFLAGS) -ansi OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ - copy_user.o clear_user.o + copy_user.o clear_user.o locks.o atomic.o bitops.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) @@ -46,6 +46,30 @@ blockops.o: blockops.S memset.o: memset.S $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S +ifdef SMP + +locks.o: locks.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S + +atomic.o: atomic.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S + +bitops.o: bitops.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S + +else + +locks.o: locks.S + $(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S + +atomic.o: atomic.S + $(CC) -D__ASSEMBLY__ -ansi -c -o atomic.o atomic.S + +bitops.o: bitops.S + $(CC) -D__ASSEMBLY__ -ansi -c -o bitops.o bitops.S + +endif + strlen.o: strlen.S $(CC) -ansi -c -o strlen.o strlen.S diff --git a/arch/sparc/lib/atomic.S b/arch/sparc/lib/atomic.S new file mode 100644 index 000000000000..2318dda88761 --- /dev/null +++ b/arch/sparc/lib/atomic.S @@ -0,0 +1,84 @@ +/* atomic.S: Move this stuff here for better ICACHE hit rates. + * + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + */ + +#include +#include +#include + + .text + .align 4 + + /* XXX At boot time patch this with swap [x], y; retl; if + * XXX processor is found to have that instruction. + */ + + .globl ___xchg32 +___xchg32: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + andcc %g3, PSR_PIL, %g0 + ld [%g1], %g7 + bne 1f + st %g2, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + mov %g7, %g2 + jmpl %o7, %g0 /* Note, not + 0x8, see call in system.h */ + mov %g4, %o7 + + .globl ___xchg32_hw +___xchg32_hw: + swap [%g1], %g2 + jmpl %o7, %g0 /* Note, not + 0x8, see call in system.h */ + mov %g4, %o7 + + /* Atomic add/sub routines. Returns the final value whether you + * want it or not for even _better_ cache hit rates. + */ + .globl ___atomic_add +___atomic_add: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop; +1: + ld [%g1], %g7 + andcc %g3, PSR_PIL, %g0 + add %g7, %g2, %g2 + bne 1f + st %g2, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop; +1: + jmpl %o7, %g0 /* NOTE: not + 8, see callers in atomic.h */ + mov %g4, %o7 + + .globl ___atomic_sub +___atomic_sub: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop; +1: + ld [%g1], %g7 + andcc %g3, PSR_PIL, %g0 + sub %g7, %g2, %g2 + bne 1f + st %g2, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop; +1: + jmpl %o7, %g0 /* NOTE: not + 8, see callers in atomic.h */ + mov %g4, %o7 diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S new file mode 100644 index 000000000000..526bf86bd881 --- /dev/null +++ b/arch/sparc/lib/bitops.S @@ -0,0 +1,126 @@ +/* bitops.S: Low level assembler bit operations. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + + .text + .align 4 + + /* Take bits in %g2 and set them in word at %g1, + * return whether bits were set in original value + * in %g2. %g4 holds value to restore into %o7 + * in delay slot of jmpl return, %g3 + %g5 + %g7 can be + * used as temporaries and thus is considered clobbered + * by all callers. + */ + .globl ___set_bit +___set_bit: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + ld [%g1], %g7 + or %g7, %g2, %g5 + andcc %g3, PSR_PIL, %g0 + and %g7, %g2, %g2 + bne 1f + st %g5, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + jmpl %o7, %g0 + mov %g4, %o7 + + /* Same as above, but clears the bits from %g2 instead. */ + .globl ___clear_bit +___clear_bit: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + ld [%g1], %g7 + andn %g7, %g2, %g5 + andcc %g3, PSR_PIL, %g0 + and %g7, %g2, %g2 + bne 1f + st %g5, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + jmpl %o7, %g0 + mov %g4, %o7 + + /* Same thing again, but this time toggles the bits from %g2. */ + .globl ___change_bit +___change_bit: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + ld [%g1], %g7 + xor %g7, %g2, %g5 + andcc %g3, PSR_PIL, %g0 + and %g7, %g2, %g2 + bne 1f + st %g5, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + jmpl %o7, %g0 + mov %g4, %o7 + + /* Now the little endian versions. */ + .globl ___set_le_bit +___set_le_bit: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + ldub [%g1], %g7 + or %g7, %g2, %g5 + andcc %g3, PSR_PIL, %g0 + and %g7, %g2, %g2 + bne 1f + stb %g5, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + jmpl %o7, %g0 + mov %g4, %o7 + + .globl ___clear_le_bit +___clear_le_bit: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + ldub [%g1], %g7 + andn %g7, %g2, %g5 + andcc %g3, PSR_PIL, %g0 + and %g7, %g2, %g2 + bne 1f + stb %g5, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + jmpl %o7, %g0 + mov %g4, %o7 diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S new file mode 100644 index 000000000000..4ad7db6c2b9b --- /dev/null +++ b/arch/sparc/lib/locks.S @@ -0,0 +1,114 @@ +/* $Id: locks.S,v 1.3 1997/01/12 11:36:44 davem Exp $ + * locks.S: SMP low-level lock primitives on Sparc. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + + .text + .align 4 + + /* This is called when the initial acquisition attempt of a spin + * lock fails. The calling convention is weird, return address + * is in %o7 as usual but we agree with the caller to only touch + * and use %g2 as a temporary. We are passed a ptr to the lock + * itself in %g1, %g4 must be restored into %o7 when we return, + * and the caller wants us to return to him at three instructions + * previous to the call instruction which got us here. See how + * this is used in asm-sparc/smp_lock.h if what I just said + * confuses you to no end. + */ + .globl ___spinlock_waitfor +___spinlock_waitfor: +1: orcc %g2, 0x0, %g0 + bne 1b + ldub [%g1], %g2 + ldstub [%g1], %g2 + jmpl %o7 - 12, %g0 + mov %g4, %o7 + + /* This is called when the kernel master lock holder changes, + * caller's PC is in %o7, %o7 must be restored to the value + * in %g4 when returning. The interrupt receiver cpu is to + * change to the new kernel lock holder before returning. + * The current implementation assumes that irq_rcvreg is a + * pointer to a word sized register which can be written with + * the MID value of the cpu to receive undirected interrupts. + * CPUID is in %g5, and mid_xlate is a byte table which translates + * CPUID values into the corresponding MID. + */ + .globl ___become_idt +___become_idt: +#ifdef __SMP__ + sethi %hi(C_LABEL(mid_xlate)), %g2 + or %g2, %lo(C_LABEL(mid_xlate)), %g2 + ldub [%g5 + %g2], %g7 + sethi %hi(C_LABEL(irq_rcvreg)), %g2 + ld [%g2 + %lo(C_LABEL(irq_rcvreg))], %g2 + st %g7, [%g2] +#endif + jmpl %o7 + 8, %g0 + mov %g4, %o7 + +___lk_busy_spin: + orcc %g2, 0, %g0 + bne ___lk_busy_spin + ldub [%g1 + 0], %g2 + b 1f + ldstub [%g1 + 0], %g2 + + .globl ___lock_kernel +___lock_kernel: + addcc %g2, -1, %g2 + bcs,a 9f + st %g2, [%g6 + TASK_LOCK_DEPTH] + rd %psr, %g3 + or %g3, PSR_PIL, %g2 + wr %g2, 0x0, %psr + nop; nop; nop + ldstub [%g1 + 0], %g2 +1: orcc %g2, 0, %g0 + bne,a ___lk_busy_spin + ldub [%g1 + 0], %g2 + ldub [%g1 + 2], %g2 + cmp %g2, %g5 + be 2f + stb %g5, [%g1 + 1] + stb %g5, [%g1 + 2] +#ifdef __SMP__ + set C_LABEL(mid_xlate), %g2 + ldub [%g2 + %g5], %g7 + sethi %hi(C_LABEL(irq_rcvreg)), %g2 + ld [%g2 + %lo(C_LABEL(irq_rcvreg))], %g2 + st %g7, [%g2] +#endif +2: mov -1, %g2 + st %g2, [%g6 + TASK_LOCK_DEPTH] + wr %g3, 0x0, %psr + nop; nop; nop +9: jmpl %o7 + 0x8, %g0 + mov %g4, %o7 + +#undef NO_PROC_ID +#define NO_PROC_ID 0xff + + .globl ___unlock_kernel +___unlock_kernel: + addcc %g2, 1, %g2 + bne,a 1f + st %g2, [%g6 + TASK_LOCK_DEPTH] + rd %psr, %g3 + or %g3, PSR_PIL, %g2 + wr %g2, 0x0, %psr + nop; nop; nop + mov NO_PROC_ID, %g2 + stb %g2, [%g1 + 1] + stb %g0, [%g1 + 0] + st %g0, [%g6 + TASK_LOCK_DEPTH] + wr %g3, 0x0, %psr + nop; nop; nop; +1: jmpl %o7 + 0x8, %g0 + mov %g4, %o7 diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 2089d1955c08..54cc7b460646 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -1,188 +1,606 @@ -/* memcpy.S: Sparc optimized memcpy code. - * - * Copyright(C) 1995 Linus Torvalds - * Copyright(C) 1996 David S. Miller - * Copyright(C) 1996 Eddie C. Dost - * Copyright(C) 1996 Jakub Jelinek - * - * derived from: - * e-mail between David and Eddie. +/* memcpy.S: Sparc optimized memcpy, bcopy and memmove code + * Hand optimized from GNU libc's memcpy, bcopy and memmove + * Copyright (C) 1991,1996 Free Software Foundation + * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi) + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#ifdef __KERNEL__ + #include -#include + +#define FUNC(x) \ + .globl C_LABEL(x); \ + .type C_LABEL(x),@function; \ + .align 4; \ +C_LABEL(x): + +#undef FASTER_REVERSE +#undef FASTER_NONALIGNED +#define FASTER_ALIGNED + +/* In kernel these functions don't return a value. + * One should use macros in asm/string.h for that purpose. + * We return 0, so that bugs are more apparent. + */ +#define SETUP_RETL +#define RETL_INSN clr %o0 + +#else + +/* libc */ + +#include "DEFS.h" + +#define FASTER_REVERSE +#define FASTER_NONALIGNED +#define FASTER_ALIGNED + +#define SETUP_RETL mov %o0, %g6 +#define RETL_INSN mov %g6, %o0 + +#endif /* Both these macros have to start with exactly the same insn */ -#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - st %t0, [%dst + offset + 0x00]; \ - st %t1, [%dst + offset + 0x04]; \ - st %t2, [%dst + offset + 0x08]; \ - st %t3, [%dst + offset + 0x0c]; \ - st %t4, [%dst + offset + 0x10]; \ - st %t5, [%dst + offset + 0x14]; \ - st %t6, [%dst + offset + 0x18]; \ +#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + ldd [%src + offset + 0x10], %t4; \ + ldd [%src + offset + 0x18], %t6; \ + st %t0, [%dst + offset + 0x00]; \ + st %t1, [%dst + offset + 0x04]; \ + st %t2, [%dst + offset + 0x08]; \ + st %t3, [%dst + offset + 0x0c]; \ + st %t4, [%dst + offset + 0x10]; \ + st %t5, [%dst + offset + 0x14]; \ + st %t6, [%dst + offset + 0x18]; \ st %t7, [%dst + offset + 0x1c]; -#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - std %t0, [%dst + offset + 0x00]; \ - std %t2, [%dst + offset + 0x08]; \ - std %t4, [%dst + offset + 0x10]; \ +#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + ldd [%src + offset + 0x10], %t4; \ + ldd [%src + offset + 0x18], %t6; \ + std %t0, [%dst + offset + 0x00]; \ + std %t2, [%dst + offset + 0x08]; \ + std %t4, [%dst + offset + 0x10]; \ std %t6, [%dst + offset + 0x18]; -#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ldd [%src - offset - 0x10], %t0; \ - ldd [%src - offset - 0x08], %t2; \ - st %t0, [%dst - offset - 0x10]; \ - st %t1, [%dst - offset - 0x0c]; \ - st %t2, [%dst - offset - 0x08]; \ +#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ + ldd [%src - offset - 0x10], %t0; \ + ldd [%src - offset - 0x08], %t2; \ + st %t0, [%dst - offset - 0x10]; \ + st %t1, [%dst - offset - 0x0c]; \ + st %t2, [%dst - offset - 0x08]; \ st %t3, [%dst - offset - 0x04]; -#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduh [%src + offset + 0x00], %t0; \ - lduh [%src + offset + 0x02], %t1; \ - lduh [%src + offset + 0x04], %t2; \ - lduh [%src + offset + 0x06], %t3; \ - sth %t0, [%dst + offset + 0x00]; \ - sth %t1, [%dst + offset + 0x02]; \ - sth %t2, [%dst + offset + 0x04]; \ - sth %t3, [%dst + offset + 0x06]; - -#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ - ldub [%src - offset - 0x02], %t0; \ - ldub [%src - offset - 0x01], %t1; \ - stb %t0, [%dst - offset - 0x02]; \ +#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \ + ldd [%src - offset - 0x10], %t0; \ + ldd [%src - offset - 0x08], %t2; \ + std %t0, [%dst - offset - 0x10]; \ + std %t2, [%dst - offset - 0x08]; + +#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ + ldub [%src - offset - 0x02], %t0; \ + ldub [%src - offset - 0x01], %t1; \ + stb %t0, [%dst - offset - 0x02]; \ stb %t1, [%dst - offset - 0x01]; +/* Both these macros have to start with exactly the same insn */ +#define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src - offset - 0x20], %t0; \ + ldd [%src - offset - 0x18], %t2; \ + ldd [%src - offset - 0x10], %t4; \ + ldd [%src - offset - 0x08], %t6; \ + st %t0, [%dst - offset - 0x20]; \ + st %t1, [%dst - offset - 0x1c]; \ + st %t2, [%dst - offset - 0x18]; \ + st %t3, [%dst - offset - 0x14]; \ + st %t4, [%dst - offset - 0x10]; \ + st %t5, [%dst - offset - 0x0c]; \ + st %t6, [%dst - offset - 0x08]; \ + st %t7, [%dst - offset - 0x04]; + +#define RMOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldd [%src - offset - 0x20], %t0; \ + ldd [%src - offset - 0x18], %t2; \ + ldd [%src - offset - 0x10], %t4; \ + ldd [%src - offset - 0x08], %t6; \ + std %t0, [%dst - offset - 0x20]; \ + std %t2, [%dst - offset - 0x18]; \ + std %t4, [%dst - offset - 0x10]; \ + std %t6, [%dst - offset - 0x08]; + +#define RMOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + st %t0, [%dst + offset + 0x00]; \ + st %t1, [%dst + offset + 0x04]; \ + st %t2, [%dst + offset + 0x08]; \ + st %t3, [%dst + offset + 0x0c]; + +#define RMOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ + ldub [%src + offset + 0x00], %t0; \ + ldub [%src + offset + 0x01], %t1; \ + stb %t0, [%dst + offset + 0x00]; \ + stb %t1, [%dst + offset + 0x01]; + +#define SMOVE_CHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + srl %t0, shir, %t5; \ + srl %t1, shir, %t6; \ + sll %t0, shil, %t0; \ + or %t5, %prev, %t5; \ + sll %t1, shil, %prev; \ + or %t6, %t0, %t0; \ + srl %t2, shir, %t1; \ + srl %t3, shir, %t6; \ + sll %t2, shil, %t2; \ + or %t1, %prev, %t1; \ + std %t4, [%dst + offset + offset2 - 0x04]; \ + std %t0, [%dst + offset + offset2 + 0x04]; \ + sll %t3, shil, %prev; \ + or %t6, %t2, %t4; + +#define SMOVE_ALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \ + ldd [%src + offset + 0x00], %t0; \ + ldd [%src + offset + 0x08], %t2; \ + srl %t0, shir, %t4; \ + srl %t1, shir, %t5; \ + sll %t0, shil, %t6; \ + or %t4, %prev, %t0; \ + sll %t1, shil, %prev; \ + or %t5, %t6, %t1; \ + srl %t2, shir, %t4; \ + srl %t3, shir, %t5; \ + sll %t2, shil, %t6; \ + or %t4, %prev, %t2; \ + sll %t3, shil, %prev; \ + or %t5, %t6, %t3; \ + std %t0, [%dst + offset + offset2 + 0x00]; \ + std %t2, [%dst + offset + offset2 + 0x08]; + .text .align 4 - .globl C_LABEL(__memcpy), C_LABEL(memcpy), C_LABEL(bcopy) - .globl C_LABEL(amemmove), C_LABEL(memmove) -C_LABEL(bcopy): - mov %o0, %o3 - mov %o1, %o0 - mov %o3, %o1 -C_LABEL(amemmove): -C_LABEL(memmove): -/* This should be kept as optimized as possible */ - cmp %o0, %o1 - bleu 1f - xor %o0, %o1, %o4 - - add %o1, %o2, %o3 - cmp %o3, %o0 - bleu 2f - andcc %o4, 3, %g0 - -/* But I think from now on, we can hold on. Or tell me, is memmoving - * overlapping regions such a nice game? */ - - mov %o0, %g1 - add %o1, %o2, %o1 - add %o0, %o2, %o0 - sub %o1, 1, %o1 - sub %o0, 1, %o0 +#ifdef FASTER_REVERSE + +70: /* rdword_align */ + + andcc %o1, 1, %g0 + be 4f + andcc %o1, 2, %g0 + + ldub [%o1 - 1], %g2 + sub %o1, 1, %o1 + stb %g2, [%o0 - 1] + sub %o2, 1, %o2 + be 3f + sub %o0, 1, %o0 +4: + lduh [%o1 - 2], %g2 + sub %o1, 2, %o1 + sth %g2, [%o0 - 2] + sub %o2, 2, %o2 + b 3f + sub %o0, 2, %o0 + +#endif /* FASTER_REVERSE */ + +0: + retl + nop ! Only bcopy returns here and it retuns void... + +FUNC(bcopy) + mov %o0, %o3 + mov %o1, %o0 + mov %o3, %o1 + tst %o2 + bcs 0b + /* Do the cmp in the delay slot */ +#ifdef __KERNEL__ +FUNC(amemmove) +FUNC(__memmove) +#endif +FUNC(memmove) + cmp %o0, %o1 + SETUP_RETL + bleu 9f + sub %o0, %o1, %o4 + + add %o1, %o2, %o3 + cmp %o3, %o0 + bleu 0f + andcc %o4, 3, %o5 + +#ifndef FASTER_REVERSE + + add %o1, %o2, %o1 + add %o0, %o2, %o0 + sub %o1, 1, %o1 + sub %o0, 1, %o0 -reverse_bytes: - ldub [%o1], %o4 - subcc %o2, 1, %o2 - stb %o4, [%o0] - sub %o1, 1, %o1 - bne reverse_bytes - sub %o0, 1, %o0 +1: /* reverse_bytes */ + + ldub [%o1], %o4 + subcc %o2, 1, %o2 + stb %o4, [%o0] + sub %o1, 1, %o1 + bne 1b + sub %o0, 1, %o0 retl - mov %g1, %o0 - -/* And here start optimizing again... */ - -dword_align: - andcc %o1, 1, %g0 - be 4f - andcc %o1, 2, %g0 - - ldub [%o1], %g2 - add %o1, 1, %o1 - stb %g2, [%o0] - sub %o2, 1, %o2 - bne 3f - add %o0, 1, %o0 - - lduh [%o1], %g2 - add %o1, 2, %o1 - sth %g2, [%o0] - sub %o2, 2, %o2 - b 3f - add %o0, 2, %o0 -4: - lduh [%o1], %g2 - add %o1, 2, %o1 - sth %g2, [%o0] - sub %o2, 2, %o2 - b 3f - add %o0, 2, %o0 - -C_LABEL(__memcpy): -C_LABEL(memcpy): /* %o0=dst %o1=src %o2=len */ - xor %o0, %o1, %o4 + RETL_INSN + +#else /* FASTER_REVERSE */ + + add %o1, %o2, %o1 + add %o0, %o2, %o0 + bne 77f + cmp %o2, 15 + bleu 91f + andcc %o1, 3, %g0 + bne 70b +3: + andcc %o1, 4, %g0 + + be 2f + mov %o2, %g1 + + ld [%o1 - 4], %o4 + sub %g1, 4, %g1 + st %o4, [%o0 - 4] + sub %o1, 4, %o1 + sub %o0, 4, %o0 +2: + andcc %g1, 0xffffff80, %g7 + be 3f + andcc %o0, 4, %g0 + + be 74f + 4 +5: + RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) + subcc %g7, 128, %g7 + sub %o1, 128, %o1 + bne 5b + sub %o0, 128, %o0 +3: + andcc %g1, 0x70, %g7 + be 72f + andcc %g1, 8, %g0 + + sethi %hi(72f), %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + sub %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + %lo(72f), %g0 + sub %o0, %g7, %o0 + +71: /* rmemcpy_table */ + RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) + RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) + +72: /* rmemcpy_table_end */ + + be 73f + andcc %g1, 4, %g0 + + ldd [%o1 - 0x08], %g2 + sub %o0, 8, %o0 + sub %o1, 8, %o1 + st %g2, [%o0] + st %g3, [%o0 + 0x04] + +73: /* rmemcpy_last7 */ + + be 1f + andcc %g1, 2, %g0 + + ld [%o1 - 4], %g2 + sub %o1, 4, %o1 + st %g2, [%o0 - 4] + sub %o0, 4, %o0 +1: + be 1f + andcc %g1, 1, %g0 + + lduh [%o1 - 2], %g2 + sub %o1, 2, %o1 + sth %g2, [%o0 - 2] + sub %o0, 2, %o0 +1: + be 1f + nop + + ldub [%o1 - 1], %g2 + stb %g2, [%o0 - 1] +1: + retl + RETL_INSN + +74: /* rldd_std */ + RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) + RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) + subcc %g7, 128, %g7 + sub %o1, 128, %o1 + bne 74b + sub %o0, 128, %o0 + + andcc %g1, 0x70, %g7 + be 72b + andcc %g1, 8, %g0 + + sethi %hi(72b), %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + sub %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + %lo(72b), %g0 + sub %o0, %g7, %o0 + +75: /* rshort_end */ + + and %o2, 0xe, %o3 +2: + sethi %hi(76f), %o5 + sll %o3, 3, %o4 + sub %o0, %o3, %o0 + sub %o5, %o4, %o5 + sub %o1, %o3, %o1 + jmpl %o5 + %lo(76f), %g0 + andcc %o2, 1, %g0 + + RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) + RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) + +76: /* rshort_table_end */ + + be 1f + nop + ldub [%o1 - 1], %g2 + stb %g2, [%o0 - 1] +1: + retl + RETL_INSN + +91: /* rshort_aligned_end */ + + bne 75b + andcc %o2, 8, %g0 + + be 1f + andcc %o2, 4, %g0 + + ld [%o1 - 0x08], %g2 + ld [%o1 - 0x04], %g3 + sub %o1, 8, %o1 + st %g2, [%o0 - 0x08] + st %g3, [%o0 - 0x04] + sub %o0, 8, %o0 1: - andcc %o4, 3, %o5 + b 73b + mov %o2, %g1 + +77: /* rnon_aligned */ + cmp %o2, 15 + bleu 75b + andcc %o0, 3, %g0 + be 64f + andcc %o0, 1, %g0 + be 63f + andcc %o0, 2, %g0 + ldub [%o1 - 1], %g5 + sub %o1, 1, %o1 + stb %g5, [%o0 - 1] + sub %o0, 1, %o0 + be 64f + sub %o2, 1, %o2 +63: + ldub [%o1 - 1], %g5 + sub %o1, 2, %o1 + stb %g5, [%o0 - 1] + sub %o0, 2, %o0 + ldub [%o1], %g5 + sub %o2, 2, %o2 + stb %g5, [%o0] +64: + and %o1, 3, %g2 + and %o1, -4, %o1 + and %o2, 0xc, %g3 + add %o1, 4, %o1 + cmp %g3, 4 + sll %g2, 3, %g4 + mov 32, %g2 + be 4f + sub %g2, %g4, %g7 + + blu 3f + cmp %g3, 8 + + be 2f + srl %o2, 2, %g3 + + ld [%o1 - 4], %o3 + add %o0, -8, %o0 + ld [%o1 - 8], %o4 + add %o1, -16, %o1 + b 7f + add %g3, 1, %g3 2: - bne cannot_optimize - cmp %o2, 15 + ld [%o1 - 4], %o4 + add %o0, -4, %o0 + ld [%o1 - 8], %g1 + add %o1, -12, %o1 + b 8f + add %g3, 2, %g3 +3: + ld [%o1 - 4], %o5 + add %o0, -12, %o0 + ld [%o1 - 8], %o3 + add %o1, -20, %o1 + b 6f + srl %o2, 2, %g3 +4: + ld [%o1 - 4], %g1 + srl %o2, 2, %g3 + ld [%o1 - 8], %o5 + add %o1, -24, %o1 + add %o0, -16, %o0 + add %g3, -1, %g3 + + ld [%o1 + 12], %o3 +5: + sll %o5, %g4, %g2 + srl %g1, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0 + 12] +6: + ld [%o1 + 8], %o4 + sll %o3, %g4, %g2 + srl %o5, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0 + 8] +7: + ld [%o1 + 4], %g1 + sll %o4, %g4, %g2 + srl %o3, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0 + 4] +8: + ld [%o1], %o5 + sll %g1, %g4, %g2 + srl %o4, %g7, %g5 + addcc %g3, -4, %g3 + or %g2, %g5, %g2 + add %o1, -16, %o1 + st %g2, [%o0] + add %o0, -16, %o0 + bne,a 5b + ld [%o1 + 12], %o3 + sll %o5, %g4, %g2 + srl %g1, %g7, %g5 + srl %g4, 3, %g3 + or %g2, %g5, %g2 + add %o1, %g3, %o1 + andcc %o2, 2, %g0 + st %g2, [%o0 + 12] + be 1f + andcc %o2, 1, %g0 + + ldub [%o1 + 15], %g5 + add %o1, -2, %o1 + stb %g5, [%o0 + 11] + add %o0, -2, %o0 + ldub [%o1 + 16], %g5 + stb %g5, [%o0 + 12] +1: + be 1f + nop + ldub [%o1 + 15], %g5 + stb %g5, [%o0 + 11] +1: + retl + RETL_INSN + +#endif /* FASTER_REVERSE */ + +78: /* dword_align */ + + andcc %o1, 1, %g0 + be 4f + andcc %o1, 2, %g0 + + ldub [%o1], %g2 + add %o1, 1, %o1 + stb %g2, [%o0] + sub %o2, 1, %o2 + bne 3f + add %o0, 1, %o0 +4: + lduh [%o1], %g2 + add %o1, 2, %o1 + sth %g2, [%o0] + sub %o2, 2, %o2 + b 3f + add %o0, 2, %o0 + +#ifdef __KERNEL__ +FUNC(__memcpy) +#endif +FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ + + sub %o0, %o1, %o4 + SETUP_RETL +9: + andcc %o4, 3, %o5 +0: + bne 86f + cmp %o2, 15 - bleu short_aligned_end - andcc %o1, 3, %g0 + bleu 90f + andcc %o1, 3, %g0 - bne dword_align + bne 78b 3: - andcc %o1, 4, %g0 + andcc %o1, 4, %g0 - be 2f - mov %o2, %g1 + be 2f + mov %o2, %g1 - ld [%o1], %o4 - sub %g1, 4, %g1 - st %o4, [%o0] - add %o1, 4, %o1 - add %o0, 4, %o0 + ld [%o1], %o4 + sub %g1, 4, %g1 + st %o4, [%o0] + add %o1, 4, %o1 + add %o0, 4, %o0 2: - andcc %g1, 0xffffff80, %g7 - be 3f - andcc %o0, 4, %g0 + andcc %g1, 0xffffff80, %g7 + be 3f + andcc %o0, 4, %g0 - be ldd_std + 4 + be 82f + 4 5: MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 - add %o1, 128, %o1 - bne 5b - add %o0, 128, %o0 + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne 5b + add %o0, 128, %o0 3: - andcc %g1, 0x70, %g7 - be memcpy_table_end - andcc %g1, 8, %g0 - - sethi %hi(memcpy_table_end), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - add %o1, %g7, %o1 - sub %o5, %o4, %o5 - jmpl %o5 + %lo(memcpy_table_end), %g0 - add %o0, %g7, %o0 - -memcpy_table: + andcc %g1, 0x70, %g7 + be 80f + andcc %g1, 8, %g0 + + sethi %hi(80f), %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + %lo(80f), %g0 + add %o0, %g7, %o0 + +79: /* memcpy_table */ + MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) @@ -191,115 +609,509 @@ memcpy_table: MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) -memcpy_table_end: - be memcpy_last7 - andcc %g1, 4, %g0 - - ldd [%o1], %g2 - add %o0, 8, %o0 - add %o1, 8, %o1 - st %g2, [%o0 - 0x08] - st %g3, [%o0 - 0x04] -memcpy_last7: - be 1f - andcc %g1, 2, %g0 - - ld [%o1], %g2 - add %o1, 4, %o1 - st %g2, [%o0] - add %o0, 4, %o0 +80: /* memcpy_table_end */ + be 81f + andcc %g1, 4, %g0 + + ldd [%o1], %g2 + add %o0, 8, %o0 + st %g2, [%o0 - 0x08] + add %o1, 8, %o1 + st %g3, [%o0 - 0x04] + +81: /* memcpy_last7 */ + + be 1f + andcc %g1, 2, %g0 + + ld [%o1], %g2 + add %o1, 4, %o1 + st %g2, [%o0] + add %o0, 4, %o0 1: - be 1f - andcc %g1, 1, %g0 + be 1f + andcc %g1, 1, %g0 - lduh [%o1], %g2 - add %o1, 2, %o1 - sth %g2, [%o0] - add %o0, 2, %o0 + lduh [%o1], %g2 + add %o1, 2, %o1 + sth %g2, [%o0] + add %o0, 2, %o0 1: - be 1f + be 1f nop - ldub [%o1], %g2 - stb %g2, [%o0] + ldub [%o1], %g2 + stb %g2, [%o0] 1: retl - nop + RETL_INSN -ldd_std: +82: /* ldd_std */ MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 - add %o1, 128, %o1 - bne ldd_std - add %o0, 128, %o0 - - andcc %g1, 0x70, %g7 - be memcpy_table_end - andcc %g1, 8, %g0 - - sethi %hi(memcpy_table_end), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - add %o1, %g7, %o1 - sub %o5, %o4, %o5 - jmpl %o5 + %lo(memcpy_table_end), %g0 - add %o0, %g7, %o0 - -cannot_optimize: - bleu short_end - cmp %o5, 2 - - bne byte_chunk - and %o2, 0xfffffff0, %o3 - - andcc %o1, 1, %g0 - be 1f + subcc %g7, 128, %g7 + add %o1, 128, %o1 + bne 82b + add %o0, 128, %o0 + +#ifndef FASTER_ALIGNED + + andcc %g1, 0x70, %g7 + be 80b + andcc %g1, 8, %g0 + + sethi %hi(80b), %o5 + srl %g7, 1, %o4 + add %g7, %o4, %o4 + add %o1, %g7, %o1 + sub %o5, %o4, %o5 + jmpl %o5 + %lo(80b), %g0 + add %o0, %g7, %o0 + +#else /* FASTER_ALIGNED */ + + andcc %g1, 0x70, %g7 + be 84f + andcc %g1, 8, %g0 + + sethi %hi(84f), %o5 + add %o1, %g7, %o1 + sub %o5, %g7, %o5 + jmpl %o5 + %lo(84f), %g0 + add %o0, %g7, %o0 + +83: /* amemcpy_table */ + + MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5) + MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5) + +84: /* amemcpy_table_end */ + be 85f + andcc %g1, 4, %g0 + + ldd [%o1], %g2 + add %o0, 8, %o0 + std %g2, [%o0 - 0x08] + add %o1, 8, %o1 +85: /* amemcpy_last7 */ + be 1f + andcc %g1, 2, %g0 + + ld [%o1], %g2 + add %o1, 4, %o1 + st %g2, [%o0] + add %o0, 4, %o0 +1: + be 1f + andcc %g1, 1, %g0 + + lduh [%o1], %g2 + add %o1, 2, %o1 + sth %g2, [%o0] + add %o0, 2, %o0 +1: + be 1f nop - ldub [%o1], %g2 - add %o1, 1, %o1 - sub %o2, 1, %o2 - stb %g2, [%o0] - andcc %o2, 0xfffffff0, %o3 - be short_end - add %o0, 1, %o0 + ldub [%o1], %g2 + stb %g2, [%o0] 1: - MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5) - MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5) - subcc %o3, 0x10, %o3 - add %o1, 0x10, %o1 - bne 1b - add %o0, 0x10, %o0 - b 2f - and %o2, 0xe, %o3 + retl + RETL_INSN + +#endif /* FASTER_ALIGNED */ + +86: /* non_aligned */ + cmp %o2, 6 + bleu 88f + +#ifdef FASTER_NONALIGNED + + cmp %o2, 256 + bcc 87f + +#endif /* FASTER_NONALIGNED */ + + andcc %o0, 3, %g0 + be 61f + andcc %o0, 1, %g0 + be 60f + andcc %o0, 2, %g0 + + ldub [%o1], %g5 + add %o1, 1, %o1 + stb %g5, [%o0] + sub %o2, 1, %o2 + bne 61f + add %o0, 1, %o0 +60: + ldub [%o1], %g3 + add %o1, 2, %o1 + stb %g3, [%o0] + sub %o2, 2, %o2 + ldub [%o1 - 1], %g3 + add %o0, 2, %o0 + stb %g3, [%o0 - 1] +61: + and %o1, 3, %g2 + and %o2, 0xc, %g3 + and %o1, -4, %o1 + cmp %g3, 4 + sll %g2, 3, %g4 + mov 32, %g2 + be 4f + sub %g2, %g4, %g7 -byte_chunk: - MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3) - MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3) - subcc %o3, 0x10, %o3 - add %o1, 0x10, %o1 - bne byte_chunk - add %o0, 0x10, %o0 - -short_end: - and %o2, 0xe, %o3 + blu 3f + cmp %g3, 0x8 + + be 2f + srl %o2, 2, %g3 + + ld [%o1], %o3 + add %o0, -8, %o0 + ld [%o1 + 4], %o4 + b 8f + add %g3, 1, %g3 2: - sethi %hi(short_table_end), %o5 - sll %o3, 3, %o4 - add %o0, %o3, %o0 - sub %o5, %o4, %o5 - add %o1, %o3, %o1 - jmpl %o5 + %lo(short_table_end), %g0 - andcc %o2, 1, %g0 + ld [%o1], %o4 + add %o0, -12, %o0 + ld [%o1 + 4], %o5 + add %g3, 2, %g3 + b 9f + add %o1, -4, %o1 +3: + ld [%o1], %g1 + add %o0, -4, %o0 + ld [%o1 + 4], %o3 + srl %o2, 2, %g3 + b 7f + add %o1, 4, %o1 +4: + ld [%o1], %o5 + cmp %o2, 7 + ld [%o1 + 4], %g1 + srl %o2, 2, %g3 + bleu 10f + add %o1, 8, %o1 + + ld [%o1], %o3 + add %g3, -1, %g3 +5: + sll %o5, %g4, %g2 + srl %g1, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0] +7: + ld [%o1 + 4], %o4 + sll %g1, %g4, %g2 + srl %o3, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0 + 4] +8: + ld [%o1 + 8], %o5 + sll %o3, %g4, %g2 + srl %o4, %g7, %g5 + or %g2, %g5, %g2 + st %g2, [%o0 + 8] +9: + ld [%o1 + 12], %g1 + sll %o4, %g4, %g2 + srl %o5, %g7, %g5 + addcc %g3, -4, %g3 + or %g2, %g5, %g2 + add %o1, 16, %o1 + st %g2, [%o0 + 12] + add %o0, 16, %o0 + bne,a 5b + ld [%o1], %o3 +10: + sll %o5, %g4, %g2 + srl %g1, %g7, %g5 + srl %g7, 3, %g3 + or %g2, %g5, %g2 + sub %o1, %g3, %o1 + andcc %o2, 2, %g0 + st %g2, [%o0] + be 1f + andcc %o2, 1, %g0 + + ldub [%o1], %g2 + add %o1, 2, %o1 + stb %g2, [%o0 + 4] + add %o0, 2, %o0 + ldub [%o1 - 1], %g2 + stb %g2, [%o0 + 3] +1: + be 1f + nop + ldub [%o1], %g2 + stb %g2, [%o0 + 4] +1: + retl + RETL_INSN + +#ifdef FASTER_NONALIGNED + +87: /* faster_nonaligned */ + + andcc %o1, 3, %g0 + be 3f + andcc %o1, 1, %g0 + + be 4f + andcc %o1, 2, %g0 + + ldub [%o1], %g2 + add %o1, 1, %o1 + stb %g2, [%o0] + sub %o2, 1, %o2 + bne 3f + add %o0, 1, %o0 +4: + lduh [%o1], %g2 + add %o1, 2, %o1 + srl %g2, 8, %g3 + sub %o2, 2, %o2 + stb %g3, [%o0] + add %o0, 2, %o0 + stb %g2, [%o0 - 1] +3: + andcc %o1, 4, %g0 + + bne 2f + cmp %o5, 1 + + ld [%o1], %o4 + srl %o4, 24, %g2 + stb %g2, [%o0] + srl %o4, 16, %g3 + stb %g3, [%o0 + 1] + srl %o4, 8, %g2 + stb %g2, [%o0 + 2] + sub %o2, 4, %o2 + stb %o4, [%o0 + 3] + add %o1, 4, %o1 + add %o0, 4, %o0 +2: + be 33f + cmp %o5, 2 + be 32f + sub %o2, 4, %o2 +31: + ld [%o1], %g2 + add %o1, 4, %o1 + srl %g2, 24, %g3 + and %o0, 7, %g5 + stb %g3, [%o0] + cmp %g5, 7 + sll %g2, 8, %g1 + add %o0, 4, %o0 + be 41f + and %o2, 0xffffffc0, %o3 + ld [%o0 - 7], %o4 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 4b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 16, %g2 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 16, %g2 +1: + st %o4, [%o0 - 7] + sth %g2, [%o0 - 3] + srl %g1, 8, %g4 + b 88f + stb %g4, [%o0 - 1] +32: + ld [%o1], %g2 + add %o1, 4, %o1 + srl %g2, 16, %g3 + and %o0, 7, %g5 + sth %g3, [%o0] + cmp %g5, 6 + sll %g2, 16, %g1 + add %o0, 4, %o0 + be 42f + and %o2, 0xffffffc0, %o3 + ld [%o0 - 6], %o4 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 4b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 16, %g2 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 16, %g2 +1: + st %o4, [%o0 - 6] + b 88f + sth %g2, [%o0 - 2] +33: + ld [%o1], %g2 + sub %o2, 4, %o2 + srl %g2, 24, %g3 + and %o0, 7, %g5 + stb %g3, [%o0] + cmp %g5, 5 + srl %g2, 8, %g4 + sll %g2, 24, %g1 + sth %g4, [%o0 + 1] + add %o1, 4, %o1 + be 43f + and %o2, 0xffffffc0, %o3 + + ld [%o0 - 1], %o4 + add %o0, 4, %o0 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) + SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) + SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) + SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 4b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 24, %g2 +4: + SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 24, %g2 +1: + st %o4, [%o0 - 5] + b 88f + stb %g2, [%o0 - 1] +41: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 41b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 16, %g2 +4: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 16, %g2 +1: + sth %g2, [%o0 - 3] + srl %g1, 8, %g4 + b 88f + stb %g4, [%o0 - 1] +43: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) + SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) + SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) + SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 43b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 24, %g2 +4: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 24, %g2 +1: + stb %g2, [%o0 + 3] + b 88f + add %o0, 4, %o0 +42: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + subcc %o3, 64, %o3 + add %o1, 64, %o1 + bne 42b + add %o0, 64, %o0 + + andcc %o2, 0x30, %o3 + be,a 1f + srl %g1, 16, %g2 +4: + SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) + subcc %o3, 16, %o3 + add %o1, 16, %o1 + bne 4b + add %o0, 16, %o0 + + srl %g1, 16, %g2 +1: + sth %g2, [%o0 - 2] + + /* Fall through */ + +#endif /* FASTER_NONALIGNED */ + +88: /* short_end */ + + and %o2, 0xe, %o3 +20: + sethi %hi(89f), %o5 + sll %o3, 3, %o4 + add %o0, %o3, %o0 + sub %o5, %o4, %o5 + add %o1, %o3, %o1 + jmpl %o5 + %lo(89f), %g0 + andcc %o2, 1, %g0 MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) @@ -308,28 +1120,31 @@ short_end: MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) -short_table_end: - be 1f + +89: /* short_table_end */ + + be 1f nop - ldub [%o1], %g2 - stb %g2, [%o0] + + ldub [%o1], %g2 + stb %g2, [%o0] 1: retl - nop + RETL_INSN -short_aligned_end: - bne short_end - andcc %o2, 8, %g0 +90: /* short_aligned_end */ + bne 88b + andcc %o2, 8, %g0 - be 1f - andcc %o2, 4, %g0 + be 1f + andcc %o2, 4, %g0 - ld [%o1 + 0x00], %g2 - ld [%o1 + 0x04], %g3 - add %o1, 8, %o1 - st %g2, [%o0 + 0x00] - st %g3, [%o0 + 0x04] - add %o0, 8, %o0 + ld [%o1 + 0x00], %g2 + ld [%o1 + 0x04], %g3 + add %o1, 8, %o1 + st %g2, [%o0 + 0x00] + st %g3, [%o0 + 0x04] + add %o0, 8, %o0 1: - b memcpy_last7 - mov %o2, %g1 + b 81b + mov %o2, %g1 diff --git a/arch/sparc/lib/memset.S b/arch/sparc/lib/memset.S index 5d022604c358..55b81de6ee1e 100644 --- a/arch/sparc/lib/memset.S +++ b/arch/sparc/lib/memset.S @@ -1,15 +1,13 @@ /* linux/arch/sparc/lib/memset.S: Sparc optimized memset and bzero code * Hand optimized from GNU libc's memset * Copyright (C) 1991,1996 Free Software Foundation - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ #include #include -#define HANDLE_UNALIGNED 1 - /* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ #define ZERO_BIG_BLOCK(base, offset, source) \ std source, [base + offset + 0x00]; \ @@ -44,13 +42,6 @@ C_LABEL(memset): or %g3, %g2, %g3 b 1f mov %o2, %o1 - -#if HANDLE_UNALIGNED -/* As this is highly unprobable, we optimize the other case (4 aligned) - * Define HANDLE_UNALIGNED to 0, if all the alignment work is done by - * the trap. Then we have to hope nobody will memset something unaligned - * with large counts, as this would lead to a lot of traps... - */ 3: cmp %o2, 3 be 2f @@ -66,19 +57,16 @@ C_LABEL(memset): add %o1, %o2, %o1 b 4f sub %o0, %o2, %o0 -#endif /* HANDLE_UNALIGNED */ C_LABEL(__bzero): mov %g0, %g3 1: + mov %o0, %g1 cmp %o1, 7 bleu 7f - mov %o0, %g1 + andcc %o0, 3, %o2 -#if HANDLE_UNALIGNED - andcc %o0, 3, %o2 bne 3b -#endif /* HANDLE_UNALIGNED */ 4: andcc %o0, 4, %g0 @@ -113,7 +101,6 @@ C_LABEL(__bzero): bzero_table: ZERO_LAST_BLOCKS(%o0, 0x48, %g2) ZERO_LAST_BLOCKS(%o0, 0x08, %g2) - 6: be 8f andcc %o1, 4, %g0 @@ -134,11 +121,17 @@ bzero_table: stb %g3, [%o0] 8: retl - mov %g1,%o0 - -/* Don't care about alignment here. It is highly - * unprobable and at most two traps may happen - */ + mov %g1, %o0 7: - b 6b + be 6b orcc %o1, 0, %g0 + + be 0f +8: + add %o0, 1, %o0 + subcc %o1, 1, %o1 + bne,a 8b + stb %g3, [%o0 - 1] +0: + retl + mov %g1, %o0 diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index b96615ea8b4d..e153164da794 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.85 1996/12/18 06:43:23 tridge Exp $ +/* $Id: fault.c,v 1.86 1997/01/06 06:52:52 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -143,7 +145,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, #if 0 static unsigned long last_one; #endif - + lock_kernel(); down(&mm->mmap_sem); if(text_fault) address = regs->pc; @@ -198,7 +200,7 @@ good_area: } handle_mm_fault(vma, address, write); up(&mm->mmap_sem); - return; + goto out; /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. @@ -215,7 +217,7 @@ bad_area: regs->pc = fixup; regs->npc = regs->pc + 4; regs->u_regs[UREG_G2] = g2; - return; + goto out; } /* Did we have an exception handler installed? */ if(current->tss.ex.count == 1) { @@ -235,7 +237,7 @@ bad_area: regs->u_regs[UREG_G1] = -EFAULT; regs->u_regs[UREG_G2] = address - current->tss.ex.address; regs->u_regs[UREG_G3] = current->tss.ex.pc; - return; + goto out; } } if(from_user) { @@ -246,7 +248,7 @@ bad_area: tsk->tss.sig_address = address; tsk->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); - return; + goto out; } if((unsigned long) address < PAGE_SIZE) { printk(KERN_ALERT "Unable to handle kernel NULL " @@ -260,6 +262,8 @@ bad_area: printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", (unsigned long) tsk->mm->pgd); die_if_kernel("Oops", regs); +out: + unlock_kernel(); } asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, @@ -372,25 +376,31 @@ void window_overflow_fault(void) { unsigned long sp; + lock_kernel(); sp = current->tss.rwbuf_stkptrs[0]; if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 1); force_user_fault(sp, 1); + unlock_kernel(); } void window_underflow_fault(unsigned long sp) { + lock_kernel(); if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); + unlock_kernel(); } void window_ret_fault(struct pt_regs *regs) { unsigned long sp; + lock_kernel(); sp = regs->u_regs[UREG_FP]; if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); + unlock_kernel(); } diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 263577d96f0c..57f4f17f8929 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.46 1996/12/18 06:43:24 tridge Exp $ +/* $Id: init.c,v 1.47 1997/01/02 14:14:28 jj Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -266,28 +266,16 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) void free_initmem (void) { - extern int text_init_begin, text_init_end, data_init_begin, data_init_end; - unsigned long addr, addrend; - int savec, saved; + extern char __init_begin, __init_end; + unsigned long addr; - addr = PAGE_ALIGN((unsigned long)(&text_init_begin)); - addrend = ((unsigned long)(&text_init_end)) & PAGE_MASK; - for (savec = addrend - addr; addr < addrend; addr += PAGE_SIZE) { + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); mem_map[MAP_NR(addr)].count = 1; free_page(addr); } - if (savec < 0) savec = 0; - addr = PAGE_ALIGN((unsigned long)(&data_init_begin)); - addrend = ((unsigned long)(&data_init_end)) & PAGE_MASK; - for (saved = addrend - addr; addr < addrend; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - mem_map[MAP_NR(addr)].count = 1; - free_page(addr); - } - if (saved < 0) saved = 0; - printk ("Freeing unused kernel memory: %dk code, %dk data\n", - savec >> 10, saved >> 10); + printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 5e3cdb723a6c..057c8236cf01 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.123 1996/12/31 09:53:00 davem Exp $ +/* $Id: srmmu.c,v 1.128 1997/01/12 12:07:00 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -45,14 +45,6 @@ int vac_badbits; extern unsigned long sparc_iobase_vaddr; -#ifdef __SMP__ -extern void smp_capture(void); -extern void smp_release(void); -#else -#define smp_capture() -#define smp_release() -#endif /* !(__SMP__) */ - #ifdef __SMP__ #define FLUSH_BEGIN(mm) #define FLUSH_END @@ -61,7 +53,7 @@ extern void smp_release(void); #define FLUSH_END } #endif -/* #define USE_CHUNK_ALLOC 1 */ +#define USE_CHUNK_ALLOC 1 static unsigned long (*mmu_getpage)(void); static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp); @@ -70,6 +62,7 @@ static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep); static void (*flush_page_for_dma)(unsigned long page); static void (*flush_cache_page_to_uncache)(unsigned long page); static void (*flush_tlb_page_for_cbit)(unsigned long page); +static void (*flush_chunk)(unsigned long chunk); #ifdef __SMP__ static void (*local_flush_page_for_dma)(unsigned long page); static void (*local_flush_cache_page_to_uncache)(unsigned long page); @@ -328,7 +321,7 @@ static int garbage_calls = 0; #define OTHER_PAGE(p,q) (((unsigned long)(p) ^ (unsigned long)(q)) & PAGE_MASK) -static inline int garbage_collect(unsigned long **cnks, int n, int cpp) +static int garbage_collect(unsigned long **cnks, int n, int cpp) { struct chunk *root = (struct chunk *)*cnks; struct chunk *p, *q, *curr, *next; @@ -424,8 +417,7 @@ static inline int garbage_collect(unsigned long **cnks, int n, int cpp) return water; } - -static inline unsigned long *get_small_chunk(void) +static unsigned long *get_small_chunk(void) { unsigned long *rval; unsigned long flags; @@ -467,6 +459,7 @@ static inline unsigned long *get_small_chunk(void) lcjiffies = jiffies; restore_flags(flags); memset(rval, 0, 256); + flush_chunk((unsigned long)rval); return rval; } @@ -486,7 +479,7 @@ static inline void free_small_chunk(unsigned long *it) restore_flags(flags); } -static inline unsigned long *get_big_chunk(void) +static unsigned long *get_big_chunk(void) { unsigned long *rval; unsigned long flags; @@ -516,6 +509,7 @@ static inline unsigned long *get_big_chunk(void) bcjiffies = jiffies; restore_flags(flags); memset(rval, 0, 1024); + flush_chunk((unsigned long)rval); return rval; } @@ -980,6 +974,10 @@ static void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_add tsunami_flush_icache(); } +static void tsunami_flush_chunk(unsigned long chunk) +{ +} + static void tsunami_flush_tlb_all(void) { srmmu_flush_whole_tlb(); @@ -1087,6 +1085,10 @@ static void swift_flush_cache_page_to_uncache(unsigned long page) swift_flush_dcache(); } +static void swift_flush_chunk(unsigned long chunk) +{ +} + static void swift_flush_tlb_all(void) { srmmu_flush_whole_tlb(); @@ -1160,6 +1162,10 @@ static void viking_flush_page_to_ram(unsigned long page) { } +static void viking_mxcc_flush_chunk(unsigned long chunk) +{ +} + /* All vikings have an icache which snoops the processor bus and is fully * coherent with the dcache, so no flush is necessary at all. */ @@ -1251,6 +1257,11 @@ static void viking_no_mxcc_flush_page(unsigned long page) } } +static void viking_nomxcc_flush_chunk(unsigned long chunk) +{ + viking_no_mxcc_flush_page(chunk); +} + /* Viking is IO cache coherent, but really only on MXCC. */ static void viking_flush_page_for_dma(unsigned long page) { @@ -1544,6 +1555,11 @@ static void cypress_flush_page_to_ram(unsigned long page) } while(line != page); } +static void cypress_flush_chunk(unsigned long chunk) +{ + cypress_flush_page_to_ram(chunk); +} + /* Cypress is also IO cache coherent. */ static void cypress_flush_page_for_dma(unsigned long page) { @@ -1711,7 +1727,6 @@ static void hypersparc_flush_cache_all(void) static void hypersparc_flush_cache_mm(struct mm_struct *mm) { register int ctr asm("g5"); - unsigned long tmp1; FLUSH_BEGIN(mm) ctr = 0; @@ -1728,66 +1743,135 @@ static void hypersparc_flush_cache_mm(struct mm_struct *mm) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); + /* Gcc can bite me... */ +#if !defined(__svr4__) && !defined(__ELF__) + __asm__ __volatile__(" + sethi %hi(_vac_line_size), %g1 + ld [%g1 + %lo(_vac_line_size)], %o1 + sethi %hi(_vac_cache_size), %g2 + ld [%g2 + %lo(_vac_cache_size)], %o0"); +#else __asm__ __volatile__(" - 1: subcc %0, %2, %0 ! hyper_flush_cache_user + sethi %hi(vac_line_size), %g1 + ld [%g1 + %lo(vac_line_size)], %o1 + sethi %hi(vac_cache_size), %g2 + ld [%g2 + %lo(vac_cache_size)], %o0"); +#endif + + __asm__ __volatile__(" + add %%o1, %%o1, %%g1 + add %%o1, %%g1, %%g2 + add %%o1, %%g2, %%g3 + add %%o1, %%g3, %%g4 + add %%o1, %%g4, %%g5 + add %%o1, %%g5, %%o4 + add %%o1, %%o4, %%o5 + 1: subcc %%o0, %%o5, %%o0 ! hyper_flush_cache_user + sta %%g0, [%%o0 + %%g0] %0 + sta %%g0, [%%o0 + %%o1] %0 + sta %%g0, [%%o0 + %%g1] %0 + sta %%g0, [%%o0 + %%g2] %0 + sta %%g0, [%%o0 + %%g3] %0 + sta %%g0, [%%o0 + %%g4] %0 + sta %%g0, [%%o0 + %%g5] %0 bne 1b - sta %%g0, [%0] %3 - sta %%g0, [%%g0] %4 ! hyper_flush_whole_icache" - : "=&r" (tmp1) - : "0" (vac_cache_size), "r" (vac_line_size), "i" (ASI_M_FLUSH_USER), - "i" (ASI_M_FLUSH_IWHOLE)); + sta %%g0, [%%o0 + %%o4] %0 + sta %%g0, [%%g0 + %%g0] %1 ! hyper_flush_whole_icache" + : : "i" (ASI_M_FLUSH_USER), "i" (ASI_M_FLUSH_IWHOLE)); FLUSH_END } /* The things we do for performance... */ static void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - register int ctr asm("g5"); - unsigned long tmp1; - FLUSH_BEGIN(mm) - ctr = 0; __asm__ __volatile__(" - 1: ld [%%g6 + %2], %%g4 ! flush user windows - orcc %%g0, %%g4, %%g0 - add %0, 1, %0 - bne 1b - save %%sp, -64, %%sp - 2: subcc %0, 1, %0 - bne 2b - restore %%g0, %%g0, %%g0" - : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); - tmp1 = vac_cache_size; start &= PAGE_MASK; end = PAGE_ALIGN(end); - if((end - start) >= (tmp1 << 2)) { - __asm__ __volatile__(" - 1: subcc %0, %2, %0 ! hyper_flush_cache_user - bne 1b - sta %%g0, [%0] %3 - sta %%g0, [%%g0] %4" - : "=&r" (tmp1) : "0" (tmp1), "r" (vac_line_size), - "i" (ASI_M_FLUSH_USER), "i" (ASI_M_FLUSH_IWHOLE)); - } else { - tmp1 = srmmu_get_context(); srmmu_set_context(mm->context); - __asm__ __volatile__(" - sub %0, %3, %0 - 1: or %0, 0x400, %%g4 - lda [%%g4] %4, %%g4 - orcc %%g4, 0x0, %%g0 - be 3f - sethi %%hi(0x1000), %%g5 - 2: subcc %%g5, %7, %%g5 ! hyper_flush_cache_page - bne 2b - sta %%g0, [%0 + %%g5] %5 - 3: cmp %0, %2 - bne 1b - sub %0, %3, %0 - sta %%g0, [%%g0] %6 ! hyper_flush_whole_icache" - : "=&r" (end) - : "0" (end), "r" (start), "r" (PAGE_SIZE), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "i" (ASI_M_FLUSH_IWHOLE), "r" (vac_line_size) - : "g4", "g5"); - (void) srmmu_get_fstatus(); srmmu_set_context(tmp1); - } + mov 0, %%g5 +1: ld [%%g6 + %0], %%g4 + orcc %%g0, %%g4, %%g0 + add %%g5, 1, %%g5 + bne 1b + save %%sp, -64, %%sp +2: subcc %%g5, 1, %%g5 + bne 2b + restore %%g0, %%g0, %%g0 + " : : "i" (UWINMASK_OFFSET)); +#if !defined(__svr4__) && !defined(__ELF__) + __asm__ __volatile__(" + sethi %hi(_vac_line_size), %g1 + ld [%g1 + %lo(_vac_line_size)], %o4 + sethi %hi(_vac_cache_size), %g2 + ld [%g2 + %lo(_vac_cache_size)], %o3"); +#else + __asm__ __volatile__(" + sethi %hi(vac_line_size), %g1 + ld [%g1 + %lo(vac_line_size)], %o4 + sethi %hi(vac_cache_size), %g2 + ld [%g2 + %lo(vac_cache_size)], %o3"); +#endif + /* Close your eyes... */ + __asm__ __volatile__(" + add %%o2, (%0 - 1), %%o2 + andn %%o1, (%0 - 1), %%o1 + add %%o4, %%o4, %%o5 + andn %%o2, (%0 - 1), %%o2 + add %%o4, %%o5, %%g1 + sub %%o2, %%o1, %%g4 + add %%o4, %%g1, %%g2 + sll %%o3, 2, %%g5 + add %%o4, %%g2, %%g3 + cmp %%g4, %%g5 + add %%o4, %%g3, %%g4 + blu 0f + add %%o4, %%g4, %%g5 + add %%o4, %%g5, %%g7 +1: subcc %%o3, %%g7, %%o3 + sta %%g0, [%%o3 + %%g0] %1 + sta %%g0, [%%o3 + %%o4] %1 + sta %%g0, [%%o3 + %%o5] %1 + sta %%g0, [%%o3 + %%g1] %1 + sta %%g0, [%%o3 + %%g2] %1 + sta %%g0, [%%o3 + %%g3] %1 + sta %%g0, [%%o3 + %%g4] %1 + bne 1b + sta %%g0, [%%o3 + %%g5] %1 + b,a 9f +0: ld [%%o0 + %3], %%o0 + mov %2, %%g7 + lda [%%g7] %4, %%o3 + sta %%o0, [%%g7] %4 + sethi %%hi(%0), %%g7 + sub %%o2, %%g7, %%o0 +1: or %%o0, 0x400, %%g7 + lda [%%g7] %5, %%g7 + orcc %%g7, 0x0, %%g0 + be,a 3f + mov %%o0, %%o2 + add %%o4, %%g5, %%g7 +2: sub %%o2, %%g7, %%o2 + sta %%g0, [%%o2 + %%g0] %6 + sta %%g0, [%%o2 + %%o4] %6 + sta %%g0, [%%o2 + %%o5] %6 + sta %%g0, [%%o2 + %%g1] %6 + sta %%g0, [%%o2 + %%g2] %6 + sta %%g0, [%%o2 + %%g3] %6 + andcc %%o2, 0xffc, %%g0 + sta %%g0, [%%o2 + %%g4] %6 + bne 2b + sta %%g0, [%%o2 + %%g5] %6 +3: sethi %%hi(%0), %%g7 + cmp %%o2, %%o1 + bne 1b + sub %%o2, %%g7, %%o0 + mov %8, %%g5 + lda [%%g5] %4, %%g0 + mov %2, %%g7 + sta %%o3, [%%g7] %4 +9: sta %%g0, [%%g0 + %%g0] %7 +" : : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_USER), "i" (SRMMU_CTX_REG), + "i" ((const unsigned long)(&(((struct mm_struct *)0)->context))), + "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE), "i" (ASI_M_FLUSH_PAGE), + "i" (ASI_M_FLUSH_IWHOLE), "i" (SRMMU_FAULT_STATUS)); FLUSH_END } @@ -1796,65 +1880,127 @@ static void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long sta */ static void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page) { - struct mm_struct *mm = vma->vm_mm; - register int ctr asm("g5"); - unsigned long tmp1; - - FLUSH_BEGIN(mm) - ctr = 0; __asm__ __volatile__(" - 1: ld [%%g6 + %2], %%g4 ! flush user windows - orcc %%g0, %%g4, %%g0 - add %0, 1, %0 - bne 1b - save %%sp, -64, %%sp - 2: subcc %0, 1, %0 - bne 2b - restore %%g0, %%g0, %%g0" - : "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4"); + ld [%%o0 + %0], %%g4 + ld [%%g4 + %1], %%o0 +" : : "i" ((const unsigned long)(&(((struct vm_area_struct *)0)->vm_mm))), + "i" ((const unsigned long)(&(((struct mm_struct *)0)->context)))); +#ifndef __SMP__ __asm__ __volatile__(" - mov 0x200, %%g4 - lda [%%g4] %6, %1 - sta %0, [%%g4] %6 - or %3, 0x400, %0 - lda [%0] %9, %0 - orcc %0, 0x0, %%g0 - be 2f - sethi %%hi(0x1000), %0 - 1: subcc %0, %5, %0 ! hyper_flush_cache_page - bne 1b - sta %%g0, [%3 + %0] %7 - 2: andcc %4, 0x4, %%g0 - sta %1, [%%g4] %6 - bne,a 1f - sta %%g0, [%%g0] %8 -1:" : "=&r" (tmp1), "=&r" (ctr) - : "0" (mm->context), "r" (page & PAGE_MASK), "r" (vma->vm_flags), - "r" (vac_line_size), "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PAGE), - "i" (ASI_M_FLUSH_IWHOLE), "i" (ASI_M_FLUSH_PROBE) - : "g4"); - (void) srmmu_get_fstatus(); - FLUSH_END + cmp %o0, -1 + bne 1f + mov 0, %g5 + retl"); +#else + __asm__ __volatile__("mov 0, %g5"); /* else we die a horrible death */ +#endif + __asm__ __volatile__(" +1: ld [%%g6 + %0], %%g4 ! flush user windows + orcc %%g0, %%g4, %%g0 + add %%g5, 1, %%g5 + bne 1b + save %%sp, -64, %%sp +2: subcc %%g5, 1, %%g5 + bne 2b + restore %%g0, %%g0, %%g0" + : : "i" (UWINMASK_OFFSET)); +#if !defined(__svr4__) && !defined(__ELF__) + __asm__ __volatile__(" + sethi %hi(_vac_line_size), %g1 + ld [%g1 + %lo(_vac_line_size)], %o4"); +#else + __asm__ __volatile__(" + sethi %hi(vac_line_size), %g1 + ld [%g1 + %lo(vac_line_size)], %o4"); +#endif + __asm__ __volatile__(" + mov %0, %%o3 + andn %%o1, (%4 - 1), %%o1 + lda [%%o3] %1, %%o2 + sta %%o0, [%%o3] %1 + or %%o1, 0x400, %%o5 + lda [%%o5] %3, %%o5 + orcc %%o5, 0x0, %%g0 + be 2f + sethi %%hi(%4), %%g7 + add %%o4, %%o4, %%o5 + add %%o1, %%g7, %%o1 + add %%o4, %%o5, %%g1 + add %%o4, %%g1, %%g2 + add %%o4, %%g2, %%g3 + add %%o4, %%g3, %%g4 + add %%o4, %%g4, %%g5 + add %%o4, %%g5, %%g7 +1: sub %%o1, %%g7, %%o1 ! hyper_flush_cache_page + sta %%g0, [%%o1 + %%g0] %5 + sta %%g0, [%%o1 + %%o4] %5 + sta %%g0, [%%o1 + %%o5] %5 + sta %%g0, [%%o1 + %%g1] %5 + sta %%g0, [%%o1 + %%g2] %5 + sta %%g0, [%%o1 + %%g3] %5 + andcc %%o1, 0xffc, %%g0 + sta %%g0, [%%o1 + %%g4] %5 + bne 1b + sta %%g0, [%%o1 + %%g5] %5 + sta %%g0, [%%g0 + %%g0] %6 +2: mov %0, %%g4 + sta %%o2, [%%g4] %1 + mov %2, %%g7 + retl + lda [%%g7] %1, %%g0 +" : : "i" (SRMMU_CTX_REG), "i" (ASI_M_MMUREGS), "i" (SRMMU_FAULT_STATUS), + "i" (ASI_M_FLUSH_PROBE), "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE), + "i" (ASI_M_FLUSH_IWHOLE)); } /* HyperSparc is copy-back. */ static void hypersparc_flush_page_to_ram(unsigned long page) { - page &= PAGE_MASK; +#if !defined(__svr4__) && !defined(__ELF__) __asm__ __volatile__(" - lda [%0] %2, %%g4 - orcc %%g4, 0x0, %%g0 + sethi %hi(_vac_line_size), %g1 + ld [%g1 + %lo(_vac_line_size)], %o4"); +#else + __asm__ __volatile__(" + sethi %hi(vac_line_size), %g1 + ld [%g1 + %lo(vac_line_size)], %o4"); +#endif + __asm__ __volatile__(" + andn %%o0, (%0 - 1), %%o0 + add %%o4, %%o4, %%o5 + or %%o0, 0x400, %%g7 + lda [%%g7] %2, %%g5 + add %%o4, %%o5, %%g1 + orcc %%g5, 0x0, %%g0 be 2f - sethi %%hi(%7), %%g5 -1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page + add %%o4, %%g1, %%g2 + sethi %%hi(%0), %%g5 + add %%o4, %%g2, %%g3 + add %%o0, %%g5, %%o0 + add %%o4, %%g3, %%g4 + add %%o4, %%g4, %%g5 + add %%o4, %%g5, %%g7 +1: sub %%o0, %%g7, %%o0 + sta %%g0, [%%o0 + %%g0] %1 + sta %%g0, [%%o0 + %%o4] %1 + sta %%g0, [%%o0 + %%o5] %1 + sta %%g0, [%%o0 + %%g1] %1 + sta %%g0, [%%o0 + %%g2] %1 + sta %%g0, [%%o0 + %%g3] %1 + andcc %%o0, 0xffc, %%g0 + sta %%g0, [%%o0 + %%g4] %1 bne 1b - sta %%g0, [%1 + %%g5] %3 -2: lda [%4] %5, %%g0" + sta %%g0, [%%o0 + %%g5] %1 +2: mov %3, %%g1 + lda [%%g1] %4, %%g0" : /* no outputs */ - : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), - "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5"); + : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE), "i" (ASI_M_FLUSH_PROBE), + "i" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS)); +} + +static void hypersparc_flush_chunk(unsigned long chunk) +{ + hypersparc_flush_page_to_ram(chunk); } /* HyperSparc is IO cache coherent. */ @@ -1891,23 +2037,41 @@ static void hypersparc_flush_cache_page_to_uncache(unsigned long page) static unsigned long hypersparc_getpage(void) { - unsigned long page = get_free_page(GFP_KERNEL); + register unsigned long page asm("i0"); + page = get_free_page(GFP_KERNEL); +#if !defined(__svr4__) && !defined(__ELF__) __asm__ __volatile__(" - lda [%0] %2, %%g4 - orcc %%g4, 0x0, %%g0 - be 2f - sethi %%hi(%7), %%g5 -1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page + sethi %hi(_vac_line_size), %g1 + ld [%g1 + %lo(_vac_line_size)], %o4"); +#else + __asm__ __volatile__(" + sethi %hi(vac_line_size), %g1 + ld [%g1 + %lo(vac_line_size)], %o4"); +#endif + __asm__ __volatile__(" + sethi %%hi(%0), %%g5 + add %%o4, %%o4, %%o5 + add %%o4, %%o5, %%g1 + add %%o4, %%g1, %%g2 + add %%o4, %%g2, %%g3 + add %%i0, %%g5, %%o0 + add %%o4, %%g3, %%g4 + add %%o4, %%g4, %%g5 + add %%o4, %%g5, %%g7 +1: sub %%o0, %%g7, %%o0 + sta %%g0, [%%o0 + %%g0] %1 + sta %%g0, [%%o0 + %%o4] %1 + sta %%g0, [%%o0 + %%o5] %1 + sta %%g0, [%%o0 + %%g1] %1 + sta %%g0, [%%o0 + %%g2] %1 + sta %%g0, [%%o0 + %%g3] %1 + andcc %%o0, 0xffc, %%g0 + sta %%g0, [%%o0 + %%g4] %1 bne 1b - sta %%g0, [%1 + %%g5] %3 -2: lda [%4] %5, %%g0" + sta %%g0, [%%o0 + %%g5] %1" : /* no outputs */ - : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), - "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5"); - + : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE)); return page; } @@ -1989,21 +2153,7 @@ static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; - __asm__ __volatile__(" - lda [%0] %2, %%g4 - orcc %%g4, 0x0, %%g0 - be 2f - sethi %%hi(%7), %%g5 -1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page - bne 1b - sta %%g0, [%1 + %%g5] %3 -2: lda [%4] %5, %%g0" - : /* no outputs */ - : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), - "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5"); - + hypersparc_flush_page_to_ram(page); if(tsk->mm->context != NO_CONTEXT) { flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); @@ -3101,6 +3251,8 @@ __initfunc(static void init_hypersparc(void)) flush_cache_page_to_uncache = hypersparc_flush_cache_page_to_uncache; flush_tlb_page_for_cbit = hypersparc_flush_tlb_page_for_cbit; + flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */ + ctxd_set = hypersparc_ctxd_set; switch_to_context = hypersparc_switch_to_context; init_new_context = hypersparc_init_new_context; @@ -3165,6 +3317,8 @@ __initfunc(static void init_cypress_common(void)) flush_tlb_page = cypress_flush_tlb_page; flush_tlb_range = cypress_flush_tlb_range; + flush_chunk = cypress_flush_chunk; /* local flush _only_ */ + 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; @@ -3273,6 +3427,8 @@ __initfunc(static void init_swift(void)) flush_cache_page = swift_flush_cache_page; flush_cache_range = swift_flush_cache_range; + flush_chunk = swift_flush_chunk; /* local flush _only_ */ + flush_tlb_all = swift_flush_tlb_all; flush_tlb_mm = swift_flush_tlb_mm; flush_tlb_page = swift_flush_tlb_page; @@ -3319,6 +3475,8 @@ __initfunc(static void init_tsunami(void)) flush_cache_page = tsunami_flush_cache_page; flush_cache_range = tsunami_flush_cache_range; + flush_chunk = tsunami_flush_chunk; /* local flush _only_ */ + flush_tlb_all = tsunami_flush_tlb_all; flush_tlb_mm = tsunami_flush_tlb_mm; flush_tlb_page = tsunami_flush_tlb_page; @@ -3410,6 +3568,8 @@ __initfunc(static void init_viking(void)) flush_cache_page_to_uncache = viking_no_mxcc_flush_page; + flush_chunk = viking_nomxcc_flush_chunk; /* local flush _only_ */ + /* We need this to make sure old viking takes no hits * on it's cache for dma snoops to workaround the * "load from non-cacheable memory" interrupt bug. @@ -3422,6 +3582,8 @@ __initfunc(static void init_viking(void)) viking_mxcc_present = 1; flush_cache_page_to_uncache = viking_mxcc_flush_page; + 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; } @@ -3518,10 +3680,6 @@ extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk, tsetup_srmmu_stackchk, srmmu_rett_stackchk; -#ifdef __SMP__ -extern unsigned long rirq_mmu_patchme, srmmu_reti_stackchk; -#endif - extern unsigned long srmmu_fault; #define PATCH_BRANCH(insn, dest) do { \ @@ -3538,9 +3696,6 @@ __initfunc(static void patch_window_trap_handlers(void)) PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk); PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk); PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk); -#ifdef __SMP__ - PATCH_BRANCH(rirq_mmu_patchme, srmmu_reti_stackchk); -#endif PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault); PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault); PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault); diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds new file mode 100644 index 000000000000..8141f5755f8c --- /dev/null +++ b/arch/sparc/vmlinux.lds @@ -0,0 +1,62 @@ +/* ld script to make SparcLinux kernel */ +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc") +OUTPUT_ARCH(sparc) +ENTRY(_start) +SECTIONS +{ + . = 0x10000 + SIZEOF_HEADERS; + .text 0xf0004000 : + { + *(.text) + *(.gnu.warning) + } =0 + _etext = .; + PROVIDE (etext = .); + .rodata : { *(.rodata) } + .rodata1 : { *(.rodata1) } + .data : + { + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + .fixup : { *(.fixup) } + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + __start___ksymtab = .; + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } +} diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index c1ef8621b1cd..75d3afff5dde 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.2 1996/12/27 17:28:20 davem Exp $ +# $Id: Makefile,v 1.3 1997/01/02 14:14:35 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -25,9 +25,9 @@ RANLIB = sparc64-linux-ranlib #CFLAGS := $(CFLAGS) -g -pipe CFLAGS := $(CFLAGS) -pipe -LINKFLAGS = -N -Ttext 0xFFFFF80000008000 +LINKFLAGS = -T arch/sparc64/vmlinux.lds -HEAD := arch/sparc/kernel/head.o +HEAD := arch/sparc64/kernel/head.o SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \ arch/sparc64/prom @@ -37,9 +37,6 @@ ARCHIVES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(ARCHIVES) LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a -INITOBJ = $(TOPDIR)/arch/sparc64/kernel/initobj.o -FINITOBJ = $(TOPDIR)/arch/sparc64/kernel/finitobj.o - archclean: archdep: diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index d3b047002c49..6998745c1599 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -165,7 +165,9 @@ CONFIG_MYRI_SBUS=y # CONFIG_QUOTA=y CONFIG_MINIX_FS=y +CONFIG_EXT_FS=y CONFIG_EXT2_FS=y +CONFIG_XIA_FS=y CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y diff --git a/arch/sparc64/kernel/finitobj.S b/arch/sparc64/kernel/finitobj.S deleted file mode 100644 index 0c05d3eb33d2..000000000000 --- a/arch/sparc64/kernel/finitobj.S +++ /dev/null @@ -1,6 +0,0 @@ - .section ".text.init",#alloc,#execinstr - .globl text_init_end -text_init_end: - .section ".data.init",#alloc,#write - .globl data_init_end -data_init_end: diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 819721597db4..3856e8496070 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.4 1996/12/28 18:39:42 davem Exp $ +/* $Id: head.S,v 1.6 1997/01/06 20:32:44 jj Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ #include #include #include +#include .text @@ -14,7 +15,6 @@ sparc64_boot: rdpr %ver, %g1 /* Get VERSION register. */ - mov %o4, %g2 /* Get OpenPROM vector. */ /* We must be careful, 32-bit OpenBOOT will get confused if it * tries to save away a register window to a 64-bit kernel @@ -76,10 +76,7 @@ execute_in_high_mem: stx %g4, [%g7] set nwindowsm1, %g6 stx %g5, [%g6] - set romvec, %g7 - stx %g2, [%g7] - set prom_sp, %g7 - stx %sp, [%g7] + mov %sp, %o1 ! second argument to prom_init set swapper_pg_dir, %g6 set PAGE_OFFSET, %g4 ! this stays here for a long time sub %g6, %g4, %g5 @@ -97,7 +94,7 @@ execute_in_high_mem: /* XXX Map in PROM 32-bit trampoline code. */ call prom_init - mov %o4, %o0 + mov %o4, %o0 ! OpenPROM cif handler /* Off we go.... */ call start_kernel @@ -106,9 +103,13 @@ execute_in_high_mem: /* Not reached... */ .data - .align 4 - .globl nwindows, nwindowsm1, romvec, prom_sp + .align 8 + .globl nwindows, nwindowsm1 nwindows: .xword 0 nwindowsm1: .xword 0 -romvec: .xword 0 -prom_sp: .xword 0 + + .section ".fixup",#alloc,#execinstr + .globl __ret_efault +__ret_efault: + ret + restore %g0, -EFAULT, %o0 diff --git a/arch/sparc64/kernel/initobj.S b/arch/sparc64/kernel/initobj.S deleted file mode 100644 index 4f4f692b1881..000000000000 --- a/arch/sparc64/kernel/initobj.S +++ /dev/null @@ -1,15 +0,0 @@ -#include - - .section ".text.init",#alloc,#execinstr - .globl text_init_begin -text_init_begin: - .section ".data.init",#alloc,#write - .globl data_init_begin -data_init_begin: - - .section ".fixup",#alloc,#execinstr - .globl __ret_efault -__ret_efault: - ret - restore %g0, -EFAULT, %o0 - diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 2cfd8ab01bab..457766024ec8 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,9 +1,10 @@ -/* $Id: signal32.c,v 1.1 1996/12/26 10:16:41 davem Exp $ +/* $Id: signal32.c,v 1.3 1997/01/19 22:32:30 ecd Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ #include @@ -67,10 +68,11 @@ struct signal_sframe32 { */ struct new_signal_frame32 { - struct sparc_stackf_32 ss; - __siginfo32_t info; - unsigned int __pad; - unsigned int insns [2]; + struct sparc_stackf_32 ss; + __siginfo32_t info; + __siginfo_fpu32_t *fpu_save; + unsigned int insns [2]; + __siginfo_fpu32_t fpu_state; }; /* Align macros */ @@ -119,6 +121,34 @@ asmlinkage void do_sigsuspend32(struct pt_regs *regs) _sigpause32_common(regs->u_regs[UREG_I0], regs); } + +static inline void +restore_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) + regs->psr &= ~(TSTATE_PEF); +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->psr &= ~(TSTATE_PEF); + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; + + copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0], + &sf->info.si_float_regs[0], + (sizeof(unsigned int) * 64)); + __get_user(current->tss.fsr, &fpu->si_fsr); + __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); + if (current->tss.fpqdepth != 0) + copy_from_user(¤t->tss.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); +} + void do_new_sigreturn32(struct pt_regs *regs) { struct new_signal_frame32 *sf; @@ -138,33 +168,19 @@ void do_new_sigreturn32(struct pt_regs *regs) do_exit (SIGSEGV); return; } - + /* 2. Restore the state */ - copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs, sizeof (struct pt_regs)); + copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs, + sizeof (struct pt_regs)); - /* User can only change condition codes and FPU enabling in the %tstate. */ + /* User can only change condition codes and FPU enabling in %tstate. */ regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF); regs->tstate |= psr_to_tstate_icc(sf->info.si_regs.psr); regs->tstate |= (sf->info.si_regs.psr & PSR_EF); - if (regs->tstate & TSTATE_PEF) { - regs->psr &= ~(TSTATE_PEF); -#ifndef __SMP__ - if(current == last_task_used_math) - last_task_used_math = 0; -#endif - current->used_math = 1; - current->flags &= ~(PF_USEDFPU); + if (sf->fpu_save) + restore_fpu_state(regs, sf->fpu_state); - /* Copy signal FPU state into thread struct FPU state. */ - copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0], - &sf->info.si_float_regs[0], - (sizeof(unsigned int) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned int) + (sizeof(unsigned int *))) * 16)); - } current->blocked = sf->info.si_mask & _BLOCKABLE; } @@ -284,77 +300,80 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, regs->npc = (regs->pc + 4); } -/* To align the structure properly. */ + +static inline void +save_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +{ +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + last_task_used_math = 0; + regs->psr &= ~(PSR_EF); + } +#endif + copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + (sizeof(unsigned long) * 64)); + __put_user(current->tss.fsr, &fpu->si_fsr); + __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); + if (current->tss.fpqdepth != 0) + copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); + current->used_math = 0; +} static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned long oldmask) { struct new_signal_frame32 *sf; + int sigframe_size; /* 1. Make sure everything is clean */ synchronize_user_stack(); - sf = (struct new_signal_frame *) regs->u_regs[UREG_FP]; - sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ); + sigframe_size = NF_ALIGNEDSZ; + if (!current->used_math) + sigframe_size -= sizeof(__siginfo_fpu32_t); + + sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size); - if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){ + if (invalid_frame_pointer (sf, sigframe_size)){ do_exit(SIGILL); return; } if (current->tss.w_saved != 0){ - printk ("%s[%d]: Invalid user stack frame for signal delivery.\n", - current->comm, current->pid); + printk ("%s[%d]: Invalid user stack frame for " + "signal delivery.\n", current->comm, current->pid); do_exit (SIGILL); return; } /* 2. Save the current process state */ memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs)); -#ifdef __SMP__ - if(current->flags & PF_USEDFPU) { - put_psr(get_psr() | PSR_EF); - fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr, - &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth); - /* Save a copy into thread struct as well. */ - memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0], - (sizeof(unsigned long) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16)); - - regs->psr &= ~(PSR_EF); - current->flags &= ~(PF_USEDFPU); - } -#else - if(current == last_task_used_math) { - put_psr(get_psr() | PSR_EF); - fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr, - &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth); - - /* Save a copy into thread struct as well. */ - memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0], - (sizeof(unsigned long) * 64)); - current->tss.fsr = sf->info.si_fsr; - if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0) - memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0], - ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16)); - - last_task_used_math = NULL; - regs->psr &= ~(PSR_EF); + if (current->used_math) { + save_fpu_state(regs, &sf->fpu_state); + sf->fpu_save = &sf->fpu_state; + } else { + sf->fpu_save = NULL; } -#endif - - /* This new thread of control has not used the FPU. */ - current->used_math = 0; sf->info.si_mask = oldmask; - memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window)); + memcpy (sf, (char *)regs->u_regs [UREG_FP], sizeof(struct reg_window)); /* 3. return to kernel instructions */ - sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */ + sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn, %g1 */ sf->insns [1] = 0x91d02010; /* t 0x10 */ /* 4. signal handler back-trampoline and parameters */ @@ -503,7 +522,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) gr = &mc->greg; /* We only have < 32 signals, fill the first slot only */ - __put_user(current->sig->action->sa_mask, &uc->sigmask.sigbits [0]); + __put_user(current->blocked, &uc->sigmask.sigbits [0]); /* Store registers */ __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 72b712cfef11..549ad09a82c4 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.3 1996/12/28 18:39:43 davem Exp $ +/* $Id: ttable.S,v 1.4 1997/01/16 13:43:24 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -216,6 +216,11 @@ tl1_f4o: FILL_4_OTHER_TL1 tl1_f5o: FILL_5_OTHER_TL1 tl1_f6o: FILL_6_OTHER_TL1 tl1_f7o: FILL_7_OTHER_TL1 + +#if 0 +/* Unless we are going to have software trap insns in the kernel code, we + * don't need this. For now we just save 8KB. + */ tl1_sunos: BTRAPTL1(0x100) tl1_bkpt: BREAKPOINT_TRAP tl1_resv102: BTRAPTL1(0x102) @@ -252,3 +257,4 @@ tl1_resv173: BTRAPTL1(0x173) BTRAPTL1(0x174) BTRAPTL1(0x175) BTRAPTL1(0x176) tl1_resv177: BTRAPTL1(0x177) BTRAPTL1(0x178) BTRAPTL1(0x179) BTRAPTL1(0x17a) tl1_resv17b: BTRAPTL1(0x17b) BTRAPTL1(0x17c) BTRAPTL1(0x17d) BTRAPTL1(0x17e) tl1_resv17f: BTRAPTL1(0x17f) +#endif diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 0f92ef5d4592..16852cb2d314 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.1 1996/12/26 10:24:23 davem Exp $ +/* $Id: init.c,v 1.2 1997/01/02 14:14:42 jj Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -173,28 +173,16 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) void free_initmem (void) { - extern int text_init_begin, text_init_end, data_init_begin, data_init_end; - unsigned long addr, addrend; - int savec, saved; + extern char __init_begin, __init_end; + unsigned long addr; - addr = PAGE_ALIGN((unsigned long)(&text_init_begin)); - addrend = ((unsigned long)(&text_init_end)) & PAGE_MASK; - for (savec = addrend - addr; addr < addrend; addr += PAGE_SIZE) { + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); mem_map[MAP_NR(addr)].count = 1; free_page(addr); } - if (savec < 0) savec = 0; - addr = PAGE_ALIGN((unsigned long)(&data_init_begin)); - addrend = ((unsigned long)(&data_init_end)) & PAGE_MASK; - for (saved = addrend - addr; addr < addrend; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - mem_map[MAP_NR(addr)].count = 1; - free_page(addr); - } - if (saved < 0) saved = 0; - printk ("Freeing unused kernel memory: %dk code, %dk data\n", - savec >> 10, saved >> 10); + printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) diff --git a/arch/sparc64/prom/k1275d.c b/arch/sparc64/prom/k1275d.c index 744b979b570b..b8ab9cf18971 100644 --- a/arch/sparc64/prom/k1275d.c +++ b/arch/sparc64/prom/k1275d.c @@ -1,4 +1,4 @@ -/* $Id: k1275d.c,v 1.1 1996/12/27 08:49:12 jj Exp $ +/* $Id: k1275d.c,v 1.2 1997/01/02 14:14:44 jj Exp $ * k1275d.c: Sun IEEE 1275 PROM kernel daemon * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -13,6 +13,12 @@ #define p1275sect __attribute__ ((__section__ (".p1275"))) +static void (*prom_cif_handler)(long *) p1275sect; +static long prom_cif_stack; +static void (*prom_do_it)(void); +static long prom_args [23] p1275sect; +static char prom_buffer [4096] p1275sect; + static void prom_doit (void) p1275sect; static void prom_doit (void) @@ -34,12 +40,6 @@ static void prom_doit (void) " : : "r" (prom_cif_stack), "r" (prom_cif_handler)); } -static void (*prom_cif_handler)(long *) p1275sect; -static void prom_cif_stack; -static void (*prom_do_it)(void); -static long prom_args [23] p1275sect; -static char prom_buffer [4096] p1275sect; - long prom_handle_command(char *service, long fmt, ...) { char *p = prom_buffer; diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds new file mode 100644 index 000000000000..aff9c1908c7d --- /dev/null +++ b/arch/sparc64/vmlinux.lds @@ -0,0 +1,68 @@ +/* ld script to make UltraLinux kernel */ +OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc") +OUTPUT_ARCH(sparc:v9) +ENTRY(_start) +SECTIONS +{ + . = 0x100200 + SIZEOF_HEADERS; + .text 0xfffff80000008000 : + { + *(.text) + *(.gnu.warning) + } =0 + _etext = .; + PROVIDE (etext = .); + .rodata : { *(.rodata) } + .rodata1 : { *(.rodata1) } + .data : + { + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + .fixup : { *(.fixup) } + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + __start___ksymtab = .; + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + . = ALIGN(8192); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(8192); + __init_end = .; + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + __p1275_loc = .; + .p1275 0x0000000000008000 : + { + *(.p1275) + } + __p1275_end = .; + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } +} diff --git a/drivers/ap1000/Makefile b/drivers/ap1000/Makefile new file mode 100644 index 000000000000..47f37720a36f --- /dev/null +++ b/drivers/ap1000/Makefile @@ -0,0 +1,29 @@ +# File: drivers/ap1000/Makefile +# +# Makefile for the AP1000 drivers +# + +L_TARGET := ap1000.a +L_OBJS := bif.o apfddi.o mac.o plc.o ringbuf.o + +ifeq ($(CONFIG_APBLOCK),y) +L_OBJS += ap.o +else + ifeq ($(CONFIG_APBLOCK),m) + M_OBJS += ap.o + endif +endif + +ifeq ($(CONFIG_DDV),y) +L_OBJS += ddv.o ddv_util.o +else + ifeq ($(CONFIG_DDV),m) + M_OBJS += ddv.o ddv_util.o + endif +endif + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + diff --git a/drivers/ap1000/am79c830.h b/drivers/ap1000/am79c830.h new file mode 100644 index 000000000000..f9ba50910fa5 --- /dev/null +++ b/drivers/ap1000/am79c830.h @@ -0,0 +1,276 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Definitions for the AM79C830 FORMAC (Fiber Optic Ring MAC) chip. + */ + +typedef int formac_reg; + +struct formac { + formac_reg cmdreg1; /* command register 1 */ + formac_reg cmdreg2; /* command register 2 */ +#define st1u cmdreg1 /* status reg 1, upper */ +#define st1l cmdreg2 /* status reg 1, lower */ + formac_reg st2u; /* status reg 2, upper */ + formac_reg st2l; /* status reg 2, lower */ + formac_reg imsk1u; /* interrupt mask 1, upper */ + formac_reg imsk1l; /* interrupt mask 1, lower */ + formac_reg imsk2u; /* interrupt mask 2, upper */ + formac_reg imsk2l; /* interrupt mask 2, lower */ + formac_reg said; /* short address, individual */ + formac_reg laim; /* long adrs, indiv, MS word */ + formac_reg laic; /* long adrs, indiv, middle word */ + formac_reg lail; /* long adrs, indiv, LS word */ + formac_reg sagp; /* short address, group */ + formac_reg lagm; /* short adrs, group, MS word */ + formac_reg lagc; /* short adrs, group, middle word */ + formac_reg lagl; /* short adrs, group, LS word */ + formac_reg mdreg1; /* mode reg 1 */ + formac_reg stmchn; /* state machine reg */ + formac_reg mir1; /* MAC information reg, upper */ + formac_reg mir0; /* MAC information reg, lower */ + formac_reg tmax; /* TMax value (2's-comp) */ + formac_reg tvx; /* TVX value (2's-comp) */ + formac_reg trt; /* TRT timer value */ + formac_reg tht; /* THT timer value */ + formac_reg tneg; /* current TNeg (2's-comp) */ + formac_reg tmrs; /* extra bits of tneg, trt, tht; late count */ + formac_reg treq0; /* our TReq (2's-comp), lower */ + formac_reg treq1; /* our TReq (2's-comp), upper */ + formac_reg pri0; /* priority reg for async queue 0 */ + formac_reg pri1; /* priority reg for async queue 1 */ + formac_reg pri2; /* priority reg for async queue 2 */ + formac_reg tsync; /* TSync value (2's-comp) */ + formac_reg mdreg2; /* mode reg 2 */ + formac_reg frmthr; /* frame threshold reg */ + formac_reg eacb; /* end address of claim/beacon area */ + formac_reg earv; /* end address of receive area */ + formac_reg eas; /* end address of sync queue */ + formac_reg eaa0; /* end address of async queue 0 */ + formac_reg eaa1; /* end address of async queue 1 */ + formac_reg eaa2; /* end address of async queue 2 */ + formac_reg sacl; /* start address of claim frame */ + formac_reg sabc; /* start address of beacon frame */ + formac_reg wpxsf; /* write pointer, special frames */ + formac_reg rpxsf; /* read pointer, special frames */ + formac_reg dummy1; /* not used */ + formac_reg rpr; /* read pointer, receive */ + formac_reg wpr; /* write pointer, receive */ + formac_reg swpr; /* shadow write pointer, receive */ + formac_reg wpxs; /* write pointer, sync queue */ + formac_reg wpxa0; /* write pointer, async queue 0 */ + formac_reg wpxa1; /* write pointer, async queue 1 */ + formac_reg wpxa2; /* write pointer, async queue 2 */ + formac_reg swpxs; /* shadow write pointer, sync queue */ + formac_reg swpxa0; /* shadow write pointer, async queue 0 */ + formac_reg swpxa1; /* shadow write pointer, async queue 1 */ + formac_reg swpxa2; /* shadow write pointer, async queue 2 */ + formac_reg rpxs; /* read pointer, sync queue */ + formac_reg rpxa0; /* read pointer, async queue 0 */ + formac_reg rpxa1; /* read pointer, async queue 1 */ + formac_reg rpxa2; /* read pointer, async queue 2 */ + formac_reg marr; /* memory address for random reads */ + formac_reg marw; /* memory address for random writes */ + formac_reg mdru; /* memory data register, upper */ + formac_reg mdrl; /* memory data register, lower */ + formac_reg tmsync; /* TSync timer value */ + formac_reg fcntr; /* frame counter */ + formac_reg lcntr; /* lost counter */ + formac_reg ecntr; /* error counter */ +}; + +/* Values for cmdreg1 */ +#define C1_SOFTWARE_RESET 1 +#define C1_IRMEMWI 2 +#define C1_IRMEMWO 3 +#define C1_IDLE_LISTEN 4 +#define C1_CLAIM_LISTEN 5 +#define C1_BEACON_LISTEN 6 +#define C1_LOAD_TVX 7 +#define C1_SEND_NR_TOKEN 0x0c +#define C1_SEND_R_TOKEN 0x0d +#define C1_ENTER_SI_MODE 0x0e +#define C1_EXIT_SI_MODE 0x0f +#define C1_CLR_SYNCQ_LOCK 0x11 +#define C1_CLR_ASYNCQ0_LOCK 0x12 +#define C1_CLR_ASYNCQ1_LOCK 0x14 +#define C1_CLR_ASYNCQ2_LOCK 0x18 +#define C1_CLR_RECVQ_LOCK 0x20 +#define C1_CLR_ALL_LOCKS 0x3f + +/* Values for cmdreg2 */ +#define C2_XMIT_SYNCQ 1 +#define C2_XMIT_ASYNCQ0 2 +#define C2_XMIT_ASYNCQ1 4 +#define C2_XMIT_ASYNCQ2 8 +#define C2_ABORT_XMIT 0x10 +#define C2_RESET_XMITQS 0x20 +#define C2_SET_TAG 0x30 +#define C2_EN_RECV_FRAME 0x40 + +/* Bits in (st1u << 16) + st1l (and (imsk1u << 16) + imsk1l) */ +#define S1_XMIT_ABORT 0x80000000 +#define S1_XABORT_ASYNC2 0x40000000 +#define S1_XABORT_ASYNC1 0x20000000 +#define S1_XABORT_ASYNC0 0x10000000 +#define S1_XABORT_SYNC 0x08000000 +#define S1_XBUF_FULL_SYNC 0x04000000 +#define S1_XBUF_FULL_ASYNC 0x02000000 +#define S1_XDONE_SYNC 0x01000000 +#define S1_END_CHAIN_ASYNC2 0x00800000 +#define S1_END_CHAIN_ASYNC1 0x00400000 +#define S1_END_CHAIN_ASYNC0 0x00200000 +#define S1_END_CHAIN_SYNC 0x00100000 +#define S1_END_FRAME_ASYNC2 0x00080000 +#define S1_END_FRAME_ASYNC1 0x00040000 +#define S1_END_FRAME_ASYNC0 0x00020000 +#define S1_END_FRAME_SYNC 0x00010000 +#define S1_BUF_UNDERRUN_ASYNC2 0x00008000 +#define S1_BUF_UNDERRUN_ASYNC1 0x00004000 +#define S1_BUF_UNDERRUN_ASYNC0 0x00002000 +#define S1_BUF_UNDERRUN_SYNC 0x00001000 +#define S1_PAR_ERROR_ASYNC2 0x00000800 +#define S1_PAR_ERROR_ASYNC1 0x00000400 +#define S1_PAR_ERROR_ASYNC0 0x00000200 +#define S1_PAR_ERROR_SYNC 0x00000100 +#define S1_XINSTR_FULL_ASYNC2 0x00000080 +#define S1_XINSTR_FULL_ASYNC1 0x00000040 +#define S1_XINSTR_FULL_ASYNC0 0x00000020 +#define S1_XINSTR_FULL_SYNC 0x00000010 +#define S1_QUEUE_LOCK_ASYNC2 0x00000008 +#define S1_QUEUE_LOCK_ASYNC1 0x00000004 +#define S1_QUEUE_LOCK_ASYNC0 0x00000002 +#define S1_QUEUE_LOCK_SYNC 0x00000001 + +/* Bits in (st2u << 16) + st2l (and (imsk2u << 16) + imsk2l) */ +#define S2_RECV_COMPLETE 0x80000000 +#define S2_RECV_BUF_EMPTY 0x40000000 +#define S2_RECV_ABORT 0x20000000 +#define S2_RECV_BUF_FULL 0x10000000 +#define S2_RECV_FIFO_OVF 0x08000000 +#define S2_RECV_FRAME 0x04000000 +#define S2_RECV_FRCT_OVF 0x02000000 +#define S2_NP_SIMULT_LOAD 0x01000000 +#define S2_ERR_SPECIAL_FR 0x00800000 +#define S2_CLAIM_STATE 0x00400000 +#define S2_MY_CLAIM 0x00200000 +#define S2_HIGHER_CLAIM 0x00100000 +#define S2_LOWER_CLAIM 0x00080000 +#define S2_BEACON_STATE 0x00040000 +#define S2_MY_BEACON 0x00020000 +#define S2_OTHER_BEACON 0x00010000 +#define S2_RING_OP 0x00008000 +#define S2_MULTIPLE_DA 0x00004000 +#define S2_TOKEN_ERR 0x00002000 +#define S2_TOKEN_ISSUED 0x00001000 +#define S2_TVX_EXP 0x00000800 +#define S2_TRT_EXP 0x00000400 +#define S2_MISSED_FRAME 0x00000200 +#define S2_ADDRESS_DET 0x00000100 +#define S2_PHY_INVALID 0x00000080 +#define S2_LOST_CTR_OVF 0x00000040 +#define S2_ERR_CTR_OVF 0x00000020 +#define S2_FRAME_CTR_OVF 0x00000010 +#define S2_SHORT_IFG 0x00000008 +#define S2_DUPL_CLAIM 0x00000004 +#define S2_TRT_EXP_RECOV 0x00000002 + +/* Bits in mdreg1 */ +#define M1_SINGLE_FRAME 0x8000 +#define M1_MODE 0x7000 +#define M1_MODE_INITIALIZE 0x0000 +#define M1_MODE_MEMORY 0x1000 +#define M1_MODE_ONLINE_SP 0x2000 +#define M1_MODE_ONLINE 0x3000 +#define M1_MODE_INT_LOOP 0x4000 +#define M1_MODE_EXT_LOOP 0x7000 +#define M1_SHORT_ADRS 0x0800 +#define M1_ADDET 0x0700 +#define M1_ADDET_NORM 0x0000 +#define M1_ADDET_METOO 0x0100 +#define M1_ADDET_NSA_NOTME 0x0200 +#define M1_ADDET_NSA 0x0300 +#define M1_ADDET_DISABLE_RECV 0x0400 +#define M1_ADDET_LIM_PROMISC 0x0600 +#define M1_ADDET_PROMISC 0x0700 +#define M1_SELECT_RA 0x0080 +#define M1_DISABLE_CARRY 0x0040 +#define M1_EXT_GRP 0x0030 +#define M1_EXT_GRP_MYGRP 0x0000 +#define M1_EXT_GRP_SOFT 0x0010 +#define M1_EXT_GRP_UPPER24 0x0020 +#define M1_EXT_GRP_UPPER16 0x0030 +#define M1_LOCK_XMIT_QS 0x0008 +#define M1_FULL_DUPLEX 0x0004 +#define M1_XMTINH_PIN 0x0002 + +/* Bits in mdreg2 */ +#define M2_TAGMODE 0x8000 +#define M2_STRIP_FCS 0x4000 +#define M2_CHECK_PARITY 0x2000 +#define M2_EVEN_PARITY 0x1000 +#define M2_LSB_FIRST 0x0800 +#define M2_RCV_BYTE_BDRY_MASK 0x0600 +#define M2_RCV_BYTE_BDRY 0x0200 +#define M2_ENABLE_HSREQ 0x0100 +#define M2_ENABLE_NPDMA 0x0080 +#define M2_SYNC_NPDMA 0x0040 +#define M2_SYMBOL_CTRL 0x0020 +#define M2_RECV_BAD_FRAMES 0x0010 +#define M2_AFULL_MASK 0x000f +#define M2_AFULL 0x0001 + +/* Bits in stmchn */ +#define SM_REV_MASK 0xe000 +#define SM_REV 0x2000 +#define SM_SEND_IMM_MODE 0x1000 +#define SM_TOKEN_MODE 0x0c00 +#define SM_TOKEN_MODE_NR 0x0000 +#define SM_TOKEN_MODE_ENTER_R 0x0400 +#define SM_TOKEN_MODE_ENTER_NR 0x0800 +#define SM_TOKEN_MODE_R 0x0c00 +#define SM_RCV_STATE 0x0380 +#define SM_XMIT_STATE 0x0070 +#define SM_MDR_PENDING 0x0008 +#define SM_MDR_TAG 0x0004 + +/* Bits in transmit descriptor */ +#define TD_MORE 0x80000000 +#define TD_MAGIC 0x40000000 +#define TD_BYTE_BDRY_MASK 0x18000000 +#define TD_BYTE_BDRY_1 0x08000000 +#define TD_XMIT_DONE 0x04000000 +#define TD_NO_FCS 0x02000000 +#define TD_XMIT_ABORT 0x01000000 +#define TD_BYTE_BDRY_LG 27 + +/* Bits in pointer in buffer memory (nontag mode) */ +#define PT_MAGIC 0xa0000000 + +/* Bits in receive status word */ +#define RS_VALID 0x80000000 +#define RS_ABORTED 0x40000000 +#define RS_SRC_ROUTE 0x10000000 +#define RS_E_INDIC 0x08000000 +#define RS_A_INDIC 0x04000000 +#define RS_C_INDIC 0x02000000 +#define RS_ERROR 0x01000000 +#define RS_ADDR_MATCH 0x00800000 +#define RS_FRAME_TYPE 0x00700000 +#define RS_FT_SMT 0x00000000 +#define RS_FT_LLC 0x00100000 +#define RS_FT_IMPL 0x00200000 +#define RS_FT_MAC 0x00400000 +#define RS_FT_LLC_SYNC 0x00500000 +#define RS_FT_IMPL_SYNC 0x00600000 +#define RS_BYTE_BDRY_MASK 0x00030000 +#define RS_BYTE_BDRY 0x00010000 +#define RS_BYTE_BDRY_LG 16 + +#define RS_LENGTH 0x0000ffff + diff --git a/drivers/ap1000/am79c864.h b/drivers/ap1000/am79c864.h new file mode 100644 index 000000000000..0fef9579119f --- /dev/null +++ b/drivers/ap1000/am79c864.h @@ -0,0 +1,162 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Definitions for Am79c864 PLC (Physical Layer Controller) + */ + +typedef int plc_reg; + +struct plc { + plc_reg ctrl_a; + plc_reg ctrl_b; + plc_reg intr_mask; + plc_reg xmit_vector; + plc_reg vec_length; + plc_reg le_threshold; + plc_reg c_min; + plc_reg tl_min; + plc_reg tb_min; + plc_reg t_out; + plc_reg dummy1; + plc_reg lc_length; + plc_reg t_scrub; + plc_reg ns_max; + plc_reg tpc_load; + plc_reg tne_load; + plc_reg status_a; + plc_reg status_b; + plc_reg tpc; + plc_reg tne; + plc_reg clk_div; + plc_reg bist_sig; + plc_reg rcv_vector; + plc_reg intr_event; + plc_reg viol_sym_ct; + plc_reg min_idle_ct; + plc_reg link_err_ct; +}; + +/* Bits in ctrl_a */ +#define CA_NOISE_TIMER 0x4000 +#define CA_TNE_16BIT 0x2000 +#define CA_TPC_16BIT 0x1000 +#define CA_REQ_SCRUB 0x0800 +#define CA_VSYM_INTR_MODE 0x0200 +#define CA_MINI_INTR_MODE 0x0100 +#define CA_LOOPBACK 0x0080 +#define CA_FOT_OFF 0x0040 +#define CA_EB_LOOP 0x0020 +#define CA_LM_LOOP 0x0010 +#define CA_BYPASS 0x0008 +#define CA_REM_LOOP 0x0004 +#define CA_RF_DISABLE 0x0002 +#define CA_RUN_BIST 0x0001 + +/* Bits in ctrl_b */ +#define CB_CONFIG_CTRL 0x8000 +#define CB_MATCH_LS 0x7800 +#define CB_MATCH_LS_ANY 0x0000 +#define CB_MATCH_LS_QLS 0x4000 +#define CB_MATCH_LS_MLS 0x2000 +#define CB_MATCH_LS_HLS 0x1000 +#define CB_MATCH_LS_ILS 0x0800 +#define CB_MAINT_LS 0x0700 +#define CB_MAINT_LS_QLS 0x0000 +#define CB_MAINT_LS_ILS 0x0100 +#define CB_MAINT_LS_HLS 0x0200 +#define CB_MAINT_LS_MLS 0x0300 +#define CB_MAINT_LS_PDR 0x0600 +#define CB_CLASS_S 0x0080 +#define CB_PC_LCT 0x0060 +#define CB_PC_LCT_NONE 0x0000 +#define CB_PC_LCT_PDR 0x0020 +#define CB_PC_LCT_IDLE 0x0040 +#define CB_PC_LCT_LOOP 0x0060 +#define CB_PC_JOIN 0x0010 +#define CB_LONG_LCT 0x0008 +#define CB_PC_MAINT 0x0004 +#define CB_PCM_CTRL 0x0003 +#define CB_PC_START 0x0001 +#define CB_PC_TRACE 0x0002 +#define CB_PC_STOP 0x0003 + +/* Bits in status_a */ +#define SA_SIG_DETECT 0x0400 +#define SA_PREV_LS 0x0300 +#define SA_PREV_LS_QLS 0x0000 +#define SA_PREV_LS_MLS 0x0100 +#define SA_PREV_LS_HLS 0x0200 +#define SA_PREV_LS_ILS 0x0300 +#define SA_LINE_ST 0x00e0 +#define SA_LINE_ST_NLS 0x0000 +#define SA_LINE_ST_ALS 0x0020 +#define SA_LINE_ST_ILS4 0x0060 +#define SA_LINE_ST_QLS 0x0080 +#define SA_LINE_ST_MLS 0x00a0 +#define SA_LINE_ST_HLS 0x00c0 +#define SA_LINE_ST_ILS 0x00e0 +#define SA_LSM_STATE 0x0010 +#define SA_UNKN_LINE_ST 0x0008 +#define SA_SYM_PAIR_CTR 0x0007 + +/* Bits in status_b */ +#define SB_RF_STATE 0xc000 +#define SB_RF_STATE_REPEAT 0x0000 +#define SB_RF_STATE_IDLE 0x4000 +#define SB_RF_STATE_HALT1 0x8000 +#define SB_RF_STATE_HALT2 0xc000 +#define SB_PCI_STATE 0x3000 +#define SB_PCI_STATE_REMOVED 0x0000 +#define SB_PCI_STATE_INS_SCR 0x1000 +#define SB_PCI_STATE_REM_SCR 0x2000 +#define SB_PCI_STATE_INSERTED 0x3000 +#define SB_PCI_SCRUB 0x0800 +#define SB_PCM_STATE 0x0780 +#define SB_PCM_STATE_OFF 0x0000 +#define SB_PCM_STATE_BREAK 0x0080 +#define SB_PCM_STATE_TRACE 0x0100 +#define SB_PCM_STATE_CONNECT 0x0180 +#define SB_PCM_STATE_NEXT 0x0200 +#define SB_PCM_STATE_SIGNAL 0x0280 +#define SB_PCM_STATE_JOIN 0x0300 +#define SB_PCM_STATE_VERIFY 0x0380 +#define SB_PCM_STATE_ACTIVE 0x0400 +#define SB_PCM_STATE_MAIN 0x0480 +#define SB_PCM_SIGNALING 0x0040 +#define SB_LSF 0x0020 +#define SB_RCF 0x0010 +#define SB_TCF 0x0008 +#define SB_BREAK_REASON 0x0007 +#define SB_BREAK_REASON_NONE 0x0000 +#define SB_BREAK_REASON_START 0x0001 +#define SB_BREAK_REASON_T_OUT 0x0002 +#define SB_BREAK_REASON_NS_MAX 0x0003 +#define SB_BREAK_REASON_QLS 0x0004 +#define SB_BREAK_REASON_ILS 0x0005 +#define SB_BREAK_REASON_HLS 0x0006 + +/* Bits in intr_event and intr_mask */ +#define IE_NP_ERROR 0x8000 +#define IE_SIGNAL_OFF 0x4000 +#define IE_LE_CTR 0x2000 +#define IE_MINI_CTR 0x1000 +#define IE_VSYM_CTR 0x0800 +#define IE_PHY_INVALID 0x0400 +#define IE_EBUF_ERR 0x0200 +#define IE_TNE_EXP 0x0100 +#define IE_TPC_EXP 0x0080 +#define IE_PCM_ENABLED 0x0040 +#define IE_PCM_BREAK 0x0020 +#define IE_SELF_TEST 0x0010 +#define IE_TRACE_PROP 0x0008 +#define IE_PCM_CODE 0x0004 +#define IE_LS_MATCH 0x0002 +#define IE_PARITY_ERR 0x0001 + +/* Correct value for BIST signature */ +#define BIST_CORRECT 0x6ecd diff --git a/drivers/ap1000/ap.c b/drivers/ap1000/ap.c new file mode 100644 index 000000000000..ae2071cf9124 --- /dev/null +++ b/drivers/ap1000/ap.c @@ -0,0 +1,318 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * ap.c - Single AP1000 block driver. + * + * (C) dwalsh, Pious project, DCS, ANU 1996 + * + * This block driver is designed to simply to perform + * io operations to the hosts file system. + * + * Heavily modified by tridge + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AP_DEBUG 0 + +#define MAJOR_NR APBLOCK_MAJOR +#define AP_DRIVER 1 +#include + +#define NUM_APDEVS 8 +#define MAX_REQUESTS 1 + +static struct wait_queue * busy_wait = NULL; + +static int ap_blocksizes[NUM_APDEVS]; +static int ap_length[NUM_APDEVS]; +static int ap_fds[NUM_APDEVS]; + +#define SECTOR_BLOCK_SHIFT 9 +#define AP_BLOCK_SHIFT 12 /* 4k blocks */ +#define AP_BLOCK_SIZE (1<= MAX_REQUESTS) return; + +repeat: + + if (!CURRENT) { + return; + } + + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) { + panic(DEVICE_NAME ": request list destroyed"); + } + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) { + panic(DEVICE_NAME ": block not locked"); + } + } + + req = CURRENT; + + minor = MINOR(req->rq_dev); + + if (minor >= NUM_APDEVS) { + printk("apblock: request for invalid minor %d\n",minor); + end_request(0); + goto repeat; + } + + offset = req->sector; + len = req->current_nr_sectors; + + if ((offset + len) > ap_length[minor]) { + printk("apblock: request for invalid sectors %d -> %d\n", + offset,offset+len); + end_request(0); + goto repeat; + } + + if (ap_fds[minor] == -1) { + printk("apblock: minor %d not open\n",minor); + end_request(0); + goto repeat; + } + + /* convert to our units */ + offset <<= SECTOR_BLOCK_SHIFT; + len <<= SECTOR_BLOCK_SHIFT; + + /* setup a request for the host */ + creq.cid = mpp_cid(); + creq.size = sizeof(creq); + creq.header = 0; + creq.data[0] = (int)(req); + creq.data[1] = ap_fds[minor]; + creq.data[2] = offset; + creq.data[3] = len; + + switch (req->cmd) { + case READ: +#if AP_DEBUG + printk("apblock: read req=0x%x len=%d offset=%d\n", + req,len,offset); +#endif + creq.type = REQ_BREAD; + if (bif_queue(&creq,0,0)) { + return; + } + break; + + case WRITE: +#if AP_DEBUG + printk("apblock: write req=0x%x len=%d offset=%d\n", + req,len,offset); +#endif + creq.type = REQ_BWRITE; + creq.size += len; + if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) { + return; + } + break; + + default: + printk("apblock: unknown ap op %d\n",req->cmd); + end_request(0); + return; + } + + if (++request_count < MAX_REQUESTS) + goto repeat; +} + +/* this is called by ap1000/bif.c when a read/write has completed */ +void ap_complete(struct cap_request *creq) +{ +#if AP_DEBUG + struct request *req = (struct request *)(creq->data[0]); + + printk("request 0x%x complete\n",req); +#endif + end_request(1); + request_count--; + ap_request(); +} + + +/* this is called by ap1000/bif.c to find a buffer to put a BREAD into + using DMA */ +char *ap_buffer(struct cap_request *creq) +{ + struct request *req = (struct request *)(creq->data[0]); + + return(req->buffer); +} + + +static int ap_open(struct inode * inode, struct file * filp) +{ + struct cap_request creq; + int minor; + minor = DEVICE_NR(inode->i_rdev); + +#if AP_DEBUG + printk("ap_open: minor=%x\n", minor); +#endif + + if (minor >= NUM_APDEVS) + return -ENODEV; + + /* if its already open then don't do anything */ + if (ap_fds[minor] != -1) + return 0; + + /* send the open request to the front end */ + creq.cid = mpp_cid(); + creq.type = REQ_BOPEN; + creq.header = 0; + creq.size = sizeof(creq); + creq.data[0] = minor; + + bif_queue(&creq,0,0); + + /* wait for the reply */ + while (ap_fds[minor] == -1) + sleep_on(&busy_wait); + + return 0; +} + + +static int ap_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if (!inode || !inode->i_rdev) + return -EINVAL; + + switch (cmd) { + case BLKGETSIZE: /* Return device size */ + if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg)) + return -EFAULT; + return 0; + + default: + break; + }; + + return 0; +} + + +/* this is called by ap1000/bif.c when a open reply comes in */ +void ap_open_reply(struct cap_request *creq) +{ + int minor = creq->data[0]; + + ap_fds[minor] = creq->data[1]; + ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT; + +#if AP_DEBUG + printk("ap opened minor %d length=%d fd=%d\n", + minor,ap_length[minor],ap_fds[minor]); +#endif + + wake_up(&busy_wait); +} + +static struct file_operations ap_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + ap_ioctl, /* ioctl */ + NULL, /* mmap */ + ap_open, /* open */ +#ifndef MODULE + NULL, /* no special release code... */ +#else + ap_release, /* module needs to decrement use count */ +#endif + block_fsync, /* fsync */ +}; + + +int ap_init(void) +{ + int i; + static int done = 0; + + if (done) return(1); + + if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) { + printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR); + return -1; + } + printk("ap_init: register dev %d\n", MAJOR_NR); + blk_dev[MAJOR_NR].request_fn = &ap_request; + + for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "apfddi.h" +#include "smt-types.h" +#include "mac.h" +#include "plc.h" +#include "am79c830.h" +#include "apfddi-reg.h" + +volatile struct formac *mac; +volatile struct plc *plc; +volatile int *csr0; +volatile int *csr1; +volatile int *buffer_mem; +volatile int *fifo; + +#define APFDDI_DEBUG 0 + +#define APFDDI_IRQ 7 + +#define T(x) (-SECS_TO_FDDI_TIME(x)) + +struct plc_info plc_info = { + pt_s, /* port_type */ + T(1.6e-3), /* c_min */ + T(50e-6), /* tl_min */ + T(5e-3), /* tb_min */ + T(100e-3), /* t_out */ + T(50e-3), /* lc_short */ + T(500e-3), /* lc_medium */ + T(5.0), /* lc_long */ + T(50.0), /* lc_extended */ + T(3.5e-3), /* t_scrub */ + T(1.3e-3), /* ns_max */ +}; + +struct mac_info mac_info = { + T(165e-3), /* tmax */ + T(3.5e-3), /* tvx */ + T(20e-3), /* treq */ + { 0x42, 0x59 }, /* s_address */ + { 0x42, 0x59, 0x10, 0x76, 0x88, 0x82 }, /* l_address */ + { 0 }, /* s_group_adrs */ + { 0 }, /* l_group_adrs */ + 0, /* rcv_own_frames */ + 1, /* only_good_frames */ +}; + +u_char fddi_bitrev[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +/* XXX our hardware address, canonical bit order */ +static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 }; + +struct device *apfddi_device = NULL; +struct enet_statistics *apfddi_stats = NULL; + +volatile struct apfddi_queue *apfddi_queue_top = NULL; + +void map_regs(void) +{ + unsigned long reg_base_addr = 0xfbf00000; + + mac = (volatile struct formac *) (reg_base_addr + FORMAC); + plc = (volatile struct plc *) (reg_base_addr + PLC); + csr0 = (volatile int *) (reg_base_addr + CSR0); + csr1 = (volatile int *) (reg_base_addr + CSR1); + buffer_mem = (volatile int *) (reg_base_addr + BUFFER_MEM); + fifo = (volatile int *) (reg_base_addr + FIFO); +} + +int ring_op; + +void apfddi_startup(void) +{ + int reason; + +#if APFDDI_DEBUG + printk("In apfddi_startup\n"); +#endif + + *csr0 = CS0_LED0; + ring_op = 0; + if (*csr1 & 0xf078) { + *csr1 = CS1_RESET_MAC | CS1_RESET_FIFO; + *csr1 = 0; + reason = 1; + printk("resetting after power-on\n"); + } else { + *csr1 = CS1_RESET_FIFO; + *csr1 = 0; + reason = plc_inited(&plc_info); + if (reason) + printk("resetting: plc reason %d\n", reason); + } + if (reason) { +#if APFDDI_DEBUG + printk("Calling plc_init\n"); +#endif + plc_init(&plc_info); +#if APFDDI_DEBUG + printk("Calling mac_init\n"); +#endif + mac_init(&mac_info); + *csr0 |= CS0_LED1; + pc_start(loop_none); + + } else { + *csr0 |= CS0_LED2 | CS0_LED1; + reason = mac_inited(&mac_info); + if (reason) { + printk("resetting mac: reason %d\n", reason); + mac_init(&mac_info); + mac_reset(loop_none); + mac_claim(); + } else { + ring_op = 1; + *csr0 &= ~(CS0_LED0 | CS0_LED1 | CS0_LED2); + } + } +} + +void apfddi_off(void) +{ + *csr0 &= ~CS0_LED1; + pc_stop(); +} + +void apfddi_sleep(void) +{ + mac_sleep(); + plc_sleep(); +} + +void apfddi_poll(void) +{ + if (*csr0 & CS0_PHY_IRQ) + plc_poll(); + if (*csr0 & CS0_MAC_IRQ) + mac_poll(); +} + +void set_cf_join(int on) +{ + if (on) { +#if APFDDI_DEBUG + printk("apfddi: joined the ring!\n"); +#endif + mac_reset(loop_none); + *csr0 |= CS0_LED2; + mac_claim(); + } else { + mac_disable(); + ring_op = 0; + *csr0 = (*csr0 & ~CS0_LED2) | CS0_LED1 | CS0_LED0; + } +} + +void set_ring_op(int up) +{ + ring_op = up; + if (up) { +#if APFDDI_DEBUG + printk("apfddi: ring operational!\n"); +#endif + *csr0 &= ~(CS0_LED2 | CS0_LED1 | CS0_LED0); + } else + *csr0 |= CS0_LED2 | CS0_LED1 | CS0_LED0; +} + +void rmt_event(int st) +{ + if (st & (S2_BEACON_STATE|S2_MULTIPLE_DA|S2_TOKEN_ERR + |S2_DUPL_CLAIM|S2_TRT_EXP_RECOV)) { + printk("st2 = %x\n", st); + } +} + + +int apfddi_init(struct device *dev); +static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int apfddi_xmit(struct sk_buff *skb, struct device *dev); +int apfddi_rx(struct mac_buf *mbuf); +static struct enet_statistics *apfddi_get_stats(struct device *dev); +#if APFDDI_DEBUG +void dump_packet(char *action, char *buf, int len, int seq); +#endif + +/* + * Create FDDI header for an arbitrary protocol layer + * + * saddr=NULL means use device source address (always will anyway) + * daddr=NULL means leave destination address (eg unresolved arp) + */ +static int apfddi_hard_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len) +{ + struct fddi_header *fh; + struct llc_header *lh; + u_char *base_header; + u_char *fd_daddr = (u_char *)daddr; + int i; + +#if APFDDI_DEBUG + printk("In apfddi_hard_header\n"); +#endif + + if (skb == NULL) { + printk("Null skb in apfddi_hard_header... returning...\n"); + return 0; + } + + switch(type) { + case ETH_P_IP: +#if APFDDI_DEBUG + printk("apfddi_hard_header: Processing IP packet\n"); +#endif + break; + case ETH_P_ARP: +#if APFDDI_DEBUG + printk("apfddi_hard_header: Processing ARP packet\n"); +#endif + break; + case ETH_P_RARP: +#if APFDDI_DEBUG + printk("apfddi_hard_header: Processing RARP packet\n"); +#endif + break; + default: + printk("apfddi_hard_header: I don't understand protocol %d (0x%x)\n", + type, type); + apfddi_stats->tx_errors++; + return 0; + } + + base_header = (u_char *)skb_push(skb, FDDI_HARDHDR_LEN-4); + if (base_header == NULL) { + printk("apfddi_hard_header: Memory squeeze, dropping packet.\n"); + apfddi_stats->tx_dropped++; + return 0; + } + fh = (struct fddi_header *)(base_header + 3); + lh = (struct llc_header *)((char *)fh + FDDI_HDRLEN); + + lh->llc_dsap = lh->llc_ssap = LLC_SNAP_LSAP; + lh->snap_control = LLC_UI; + lh->snap_org_code[0] = 0; + lh->snap_org_code[1] = 0; + lh->snap_org_code[2] = 0; + lh->snap_ether_type = htons(type); + +#if APFDDI_DEBUG + printk("snap_ether_type is %d (0x%x)\n", lh->snap_ether_type, + lh->snap_ether_type); +#endif + + fh->fddi_fc = FDDI_FC_LLC; + + /* + * Fill in the source address. + */ + for (i = 0; i < 6; i++) + fh->fddi_shost[i] = fddi_bitrev[apfddi_saddr[i]]; + + /* + * Fill in the destination address. + */ + if (daddr) { +#if APFDDI_DEBUG + printk("daddr is: "); +#endif + for (i = 0; i < 6; i++) { + fh->fddi_dhost[i] = fddi_bitrev[fd_daddr[i]]; +#if APFDDI_DEBUG + printk("%x(%x):",fh->fddi_dhost[i], fd_daddr[i]); +#endif + } +#if APFDDI_DEBUG + printk("\n"); +#endif + return(FDDI_HARDHDR_LEN-4); + } + else { +#if APFDDI_DEBUG + printk("apfddi_hard_header, daddr was NULL\n"); +#endif + return -(FDDI_HARDHDR_LEN-4); + } +} + +/* + * Rebuild the FDDI header. This is called after an ARP (or in future + * other address resolution) has completed on this sk_buff. We now let + * ARP fill in the other fields. + */ +static int apfddi_rebuild_header(void *buff, struct device *dev, + unsigned long raddr, struct sk_buff *skb) +{ + int i, status; + struct fddi_header *fh = (struct fddi_header *)(buff+3); + +#if APFDDI_DEBUG + printk("In apfddi_rebuild_header, dev is %x apfddi_device is %x\n", dev, + apfddi_device); + printk("rebuild header for fc 0x%x\n", fh->fddi_fc); + printk("dest address is:\n"); + for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]); +#endif + status = arp_find(raddr, skb) ? 1 : 0; + + if (!status) { +#if APFDDI_DEBUG + printk("dest address is now:\n"); + for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]); + printk("status is %d\n", status); +#endif + /* + * Bit reverse the dest_address. + */ + for (i = 0; i < 6; i++) + fh->fddi_dhost[i] = fddi_bitrev[fh->fddi_dhost[i]]; + } +#if APFDDI_DEBUG + printk("\n"); +#endif + return(status); +} + +static int apfddi_set_mac_address(struct device *dev, void *addr) +{ +#if APFDDI_DEBUG + printk("In apfddi_set_mac_address\n"); +#endif + return (0); +} + +static void apfddi_set_multicast_list(struct device *dev) +{ +#if APFDDI_DEBUG + printk("In apfddi_set_multicast_list\n"); +#endif +} + +static int apfddi_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ +#if APFDDI_DEBUG + printk("In apfddi_do_ioctl\n"); +#endif + return (0); +} + +static int apfddi_set_config(struct device *dev, struct ifmap *map) +{ +#if APFDDI_DEBUG + printk("In apfddi_set_config\n"); +#endif + return (0); +} + +/* + * Opening the fddi device through ifconfig. + */ +int apfddi_open(struct device *dev) +{ + static int already_run = 0; + unsigned flags; + int res; + + if (already_run) { + apfddi_startup(); + *csr0 |= CS0_INT_ENABLE; + return 0; + } + already_run = 1; + + map_regs(); + apfddi_startup(); + + save_flags(flags); cli(); + if ((res = request_irq(APFDDI_IRQ, apfddi_interrupt, SA_INTERRUPT, + "apfddi", dev))) { + printk("Failed to install apfddi handler error=%d\n", res); + restore_flags(flags); + return(0); + } + enable_irq(APFDDI_IRQ); + restore_flags(flags); + +#if APFDDI_DEBUG + printk("Installed apfddi interrupt handler\n"); +#endif + *csr0 |= CS0_INT_ENABLE; +#if APFDDI_DEBUG + printk("Enabled fddi interrupts\n"); +#endif + + return 0; +} + +/* + * Stop the fddi device through ifconfig. + */ +int apfddi_stop(struct device *dev) +{ + *csr0 &= ~CS0_INT_ENABLE; + apfddi_sleep(); + return 0; +} + + +/* + * Initialise fddi network interface. + */ +int apfddi_init(struct device *dev) +{ + int i; + printk("apfddi_init(): Initialising fddi interface\n"); + + apfddi_device = dev; + + dev->open = apfddi_open; + dev->stop = apfddi_stop; + dev->hard_start_xmit = apfddi_xmit; + dev->get_stats = apfddi_get_stats; + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_ATOMIC); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct enet_statistics)); + apfddi_stats = (struct enet_statistics *)apfddi_device->priv; + + /* Initialise the fddi device structure */ + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->hard_header = apfddi_hard_header; + dev->rebuild_header = apfddi_rebuild_header; + dev->set_mac_address = apfddi_set_mac_address; + dev->header_cache_update = NULL; + dev->do_ioctl = apfddi_do_ioctl; + dev->set_config = apfddi_set_config; + dev->set_multicast_list = apfddi_set_multicast_list; + dev->type = ARPHRD_ETHER; + dev->hard_header_len = FDDI_HARDHDR_LEN; + dev->mtu = FDDIMTU; + dev->addr_len = 6; + memcpy(dev->dev_addr, apfddi_saddr, sizeof(apfddi_saddr)); + dev->tx_queue_len = 100; /* XXX What should this be? */ + dev->irq = APFDDI_IRQ; + + memset(dev->broadcast, 0xFF, ETH_ALEN); + + dev->family = AF_INET; + dev->pa_addr = in_aton("150.203.142.28"); /* hibana-f */ + dev->pa_mask = in_aton("255.255.255.0"); + dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; + dev->pa_alen = 4; + + return(0); +} + +static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ +#if APFDDI_DEBUG + static int times = 0; +#endif + unsigned flags; + save_flags(flags); cli(); + +#if APFDDI_DEBUG + printk("In apfddi_interrupt irq %d dev_id %p times %d\n", + irq, dev_id, ++times); +#endif + + apfddi_poll(); + restore_flags(flags); +} + +#if APFDDI_DEBUG +static char *flagbits[8] = { + "fin", "syn", "rst", "push", "ack", "urg", "6", "7" +}; + +void dump_packet(action, buf, len, seq) + char *action, *buf; + int len, seq; +{ + int i, flags; + char *sep; + + printk("%s packet %d of %d bytes at %d:\n", action, seq, + len, jiffies); + printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n", + *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4), + *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2)); + if( buf[9] == 6 || buf[9] == 17 ){ + /* TCP or UDP */ + printk(" sport=%d dport=%d", + *(u_short *)(buf+20), *(u_short *)(buf+22)); + if( buf[9] == 6 ){ + printk(" seq=%d ack=%d win=%d flags=<", + *(long *)(buf+24), *(long *)(buf+28), + *(unsigned short *)(buf+34)); + flags = buf[33]; + sep = ""; + for (i = 7; i >= 0; --i) { + if (flags & (1 << i)) { + printk("%s%s", sep, flagbits[i]); + sep = "+"; + } + } + printk(">"); + } + printk("\n"); + } +} +#endif + +#if APFDDI_DEBUG +static void apfddi_print_frame(struct sk_buff *skb) +{ + int i; + struct llc_header *lh; + static int seq = 0; + +#if 0 + printk("skb->len is %d\n", skb->len); + printk("fc is 0x%x\n", *(u_char *)(skb->data+3)); + printk("dest address is:\n"); + for (i = 0; i < 6; i++) { + printk("%x:", fddi_bitrev[*(u_char *)(skb->data+4+i)]); + } + printk("\n"); + printk("source address is:\n"); + for (i = 0; i < 6; i++) { + printk("%x:", fddi_bitrev[*(u_char *)(skb->data+10+i)]); + } + printk("\n"); +#endif + lh = (struct llc_header *)(skb->data+16); +#if 0 + printk("llc_dsp %d llc_ssap %d snap_control %d org_code [0]=%d [1]=%d [2]=%d ether_type=%d\n", + lh->llc_dsap, lh->llc_ssap, lh->snap_control, + lh->snap_org_code[0], lh->snap_org_code[1], lh->snap_org_code[2], + lh->snap_ether_type); +#endif + if (lh->snap_ether_type == ETH_P_IP) + dump_packet("apfddi_xmit:", skb->data+24, skb->len-24, seq++); +} +#endif + +/* + * Transmitting packet over FDDI. + */ +static int apfddi_xmit(struct sk_buff *skb, struct device *dev) +{ + unsigned long flags; + +#if APFDDI_DEBUG + printk("In apfddi_xmit\n"); +#endif + + /* + * Check there is some work to do. + */ + if (skb == NULL || dev == NULL) + return(0); + +#if APFDDI_DEBUG + printk("skb address is for apfddi 0x%x\n", skb); +#endif + + /* + * Check lock variable. + */ + save_flags(flags); cli(); + if (dev->tbusy != 0) { + restore_flags(flags); + printk("apfddi_xmit: device busy\n"); + apfddi_stats->tx_errors++; + return 1; + } + restore_flags(flags); + dev->tbusy = 1; + + dev->trans_start = jiffies; + + skb->mac.raw = skb->data; + + /* + * Append packet onto send queue. + */ + if (mac_queue_append(skb)) { + /* + * No memory. + */ + return 1; + } + + /* + * Process packet queue. + */ + mac_process(); + + apfddi_stats->tx_packets++; + dev->tbusy = 0; + return 0; +} + +#if APFDDI_DEBUG +void print_mbuf(struct mac_buf *mbuf) +{ + printk("mac %p length=%d ptr=%p wraplen=%d wrapptr=%x fr_start=%d fr_end=%d\n", + mbuf, mbuf->length, mbuf->ptr, mbuf->wraplen, mbuf->wrapptr, + mbuf->fr_start, mbuf->fr_end); +} +#endif + +/* + * Return statistics of fddi driver. + */ +static struct enet_statistics *apfddi_get_stats(struct device *dev) +{ + return((struct enet_statistics *)dev->priv); +} + + + + diff --git a/drivers/ap1000/apfddi.h b/drivers/ap1000/apfddi.h new file mode 100644 index 000000000000..021bd00ace2f --- /dev/null +++ b/drivers/ap1000/apfddi.h @@ -0,0 +1,142 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +#define BUFFER_MEM 0x40000 +#define CSR0 0x60000 +#define CSR1 0x60004 +#define PLC 0x60080 +#define FORMAC 0x60200 +#define FIFO 0x68000 + +/* Size of buffer memory */ +#define BUFFER_SIZE 32768 /* words; 128kB */ + +/* Bits in CSR0 */ +#define CS0_INT_REQ 0x8000 /* board interrupt request asserted */ +#define CS0_MAC_IRQ 0x4000 /* FORMAC is requesting interrupt */ +#define CS0_PHY_IRQ 0x2000 /* PLC is requesting interrupt */ +#define CS0_LED2 0x1000 /* turn on led 2 */ +#define CS0_DO_IRQ 0x0200 /* request interrupt */ +#define CS0_INT_ENABLE 0x0100 /* enable interrupt requests */ +#define CS0_DMA_ENABLE 0x0080 /* enable DMA requests */ +#define CS0_DMA_RECV 0x0040 /* DMA requests are in receive dirn. */ +#define CS0_LED1 0x0010 /* turn on led 1 */ +#define CS0_LED0 0x0008 /* turn on led 0 (red) */ +#define CS0_HREQ 0x0007 /* host request to FORMAC */ +#define CS0_HREQ_WSPEC 0x0002 /* write special frames */ +#define CS0_HREQ_RECV 0x0003 /* read receive queue */ +#define CS0_HREQ_WS 0x0004 /* write synchronous queue */ +#define CS0_HREQ_WA0 0x0005 /* write async queue 0 */ +#define CS0_HREQ_WA1 0x0006 /* write async queue 1 */ +#define CS0_HREQ_WA2 0x0007 /* write async queue 2 */ + +/* Bits in CSR1 */ +#define CS1_THIS_QAF 0x0800 /* this queue almost full */ +#define CS1_FIFO_TAG 0x0400 /* tag of word at head of fifo */ +#define CS1_BUF_RD_TAG 0x0200 /* tag of last word read from buffer */ +#define CS1_BUF_WR_TAG 0x0100 /* tag to write to buffer */ +#define CS1_TAGMODE 0x0080 /* enable tag mode */ +#define CS1_RESET_MAC 0x0040 /* reset FORMAC and PLC */ +#define CS1_RESET_FIFO 0x0020 /* reset FIFO */ +#define CS1_CLEAR_QAF 0x0010 /* clear queue-almost-full bits */ +#define CS1_FIFO_LEVEL 0x0007 /* # words in FIFO (0 - 4) */ + +/* + * FDDI Frame Control values. + */ +#define FDDI_SMT 0x41 +#define FDDI_SMT_NSA 0x4f +#define FDDI_FC_LLC 0x50 +#define FDDI_FC_LLC_MASK 0xf0 + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +/* + * Structure of the FDDI MAC header. + */ +struct fddi_header { + u_char fddi_fc; /* frame control field */ + u_char fddi_dhost[6]; /* destination address */ + u_char fddi_shost[6]; /* source address */ +}; + +/* + * Structure of LLC/SNAP header. + */ +struct llc_header { + u_char llc_dsap; + u_char llc_ssap; + u_char snap_control; + u_char snap_org_code[3]; + u_short snap_ether_type; +}; + +#define FDDI_HDRLEN 13 /* sizeof(struct fddi_header) */ +#define LLC_SNAPLEN 8 /* bytes for LLC/SNAP header */ +#define FDDI_HARDHDR_LEN 28 /* Hard header size */ + +#define FDDIMTU 4352 + + +/* Types of loopback we can do. */ +typedef enum { + loop_none, + loop_formac, + loop_plc_lm, + loop_plc_eb, + loop_pdx +} LoopbackType; + +/* Offset from fifo for writing word with tag. */ +#define FIFO_TAG 0x80 + +#define MAX_FRAME_LEN 4500 + +void set_ring_op(int up); +void rmt_event(int st); +void set_cf_join(int on); + +extern struct device *apfddi_device; +extern struct enet_statistics *apfddi_stats; + diff --git a/drivers/ap1000/bif.c b/drivers/ap1000/bif.c new file mode 100644 index 000000000000..52ea4a82d2d7 --- /dev/null +++ b/drivers/ap1000/bif.c @@ -0,0 +1,289 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * $Id: bif.c,v 1.13 1996/12/18 01:45:52 tridge Exp $ + * + * Network interface definitions for bif device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include +#include /* For ARPHRD_BIF */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define BIF_DEBUG 0 +#if BIF_DEBUG +static int seq = 0; +#endif + +#define BIF_MTU 10240 + +static struct device *bif_device = 0; +static struct enet_statistics *bif_stats = 0; + +int bif_init(struct device *dev); +int bif_open(struct device *dev); +static int bif_xmit(struct sk_buff *skb, struct device *dev); +int bif_rx(struct sk_buff *skb); +int bif_stop(struct device *dev); +static struct enet_statistics *bif_get_stats(struct device *dev); + +static int bif_hard_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, + void *saddr, unsigned len) +{ +#if BIF_DEBUG + printk("bif_hard_header()\n"); +#endif + + skb_push(skb,dev->hard_header_len); + + if (daddr) skb->arp = 1; + + /* tell IP how much space we took */ + return (dev->hard_header_len); +} + +static int bif_rebuild_header(void *buff, struct device *dev, + unsigned long raddr, struct sk_buff *skb) +{ + /* this would normally be used to fill in hardware addresses after + an ARP */ +#if BIF_DEBUG + printk("bif_rebuild_header()\n"); +#endif + if (skb) skb->arp = 1; + return(0); +} + +static int bif_set_mac_address(struct device *dev, void *addr) +{ + printk("BIF: set_mac_address called\n"); + return (0); +} + +static void bif_set_multicast_list(struct device *dev) +{ + return; +} + +static int bif_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + printk("BIF: Called do_ioctl\n"); + return (0); +} + +static int bif_set_config(struct device *dev, struct ifmap *map) +{ + printk("BIF: Called bif_set_config\n"); + return (0); +} + +/* + * Initialise bif network interface. + */ +int bif_init(struct device *dev) +{ + int i; + + printk("bif_init(): Initialising bif interface\n"); + bif_device = dev; + + dev->mtu = BIF_MTU; + dev->tbusy = 0; + dev->hard_start_xmit = bif_xmit; + dev->hard_header = bif_hard_header; + dev->hard_header_len = sizeof(struct cap_request); + dev->addr_len = 0; + dev->tx_queue_len = 50000; /* no limit (almost!) */ + dev->type = ARPHRD_BIF; + dev->rebuild_header = bif_rebuild_header; + dev->open = bif_open; + dev->flags = IFF_NOARP; /* Don't use ARP on this device */ + dev->family = AF_INET; + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct enet_statistics)); + bif_stats = (struct enet_statistics *)bif_device->priv; + + + dev->stop = bif_stop; + dev->get_stats = bif_get_stats; + + /* Initialise the bif device structure */ + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->set_mac_address = bif_set_mac_address; + dev->header_cache_update = NULL; + dev->do_ioctl = bif_do_ioctl; + dev->set_config = bif_set_config; + dev->set_multicast_list = bif_set_multicast_list; + + memset(dev->broadcast, 0xFF, ETH_ALEN); + + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; + + return(0); +} + +int bif_open(struct device *dev) +{ + printk("In bif_open\n"); + dev->tbusy = 0; + dev->start = 1; + return 0; +} + +#if BIF_DEBUG +static void dump_packet(char *action, char *buf, int len, int seq) +{ + int flags; + char *sep; + + printk("%s packet %d of %d bytes at %d:\n", action, seq, + len, (int)jiffies); + printk(" from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n", + *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4), + *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2)); + if( buf[9] == 6 || buf[9] == 17 ){ + /* TCP or UDP */ + printk(" sport=%d dport=%d", + *(u_short *)(buf+20), *(u_short *)(buf+22)); + if( buf[9] == 6 ){ + printk(" seq=%d ack=%d win=%d flags=<", + *(long *)(buf+24), *(long *)(buf+28), + *(unsigned short *)(buf+34)); + flags = buf[33]; + sep = ""; + printk(">"); + } + printk("\n"); + } + else { + printk(" protocol = %d\n", buf[9]); + } +} +#endif + + +static int bif_xmit(struct sk_buff *skb, struct device *dev) +{ + extern int bif_send_ip(int cid,struct sk_buff *skb); + extern int tnet_send_ip(int cid,struct sk_buff *skb); + extern int msc_blocked, tnet_ip_enabled; + u_long destip; + int cid; + + if (skb == NULL || dev == NULL) + return(0); + + destip = *(u_long *)(skb->data+sizeof(struct cap_request)+16); + cid = ap_ip_to_cid(destip); + + skb->dev = dev; + skb->mac.raw = skb->data; + + if (cid != -1 && tnet_ip_enabled && !msc_blocked) { + tnet_send_ip(cid,skb); + } else { + bif_send_ip(cid, skb); + } + + dev->tbusy = 0; + + bif_stats->tx_packets++; + + mark_bh(NET_BH); + + return 0; +} + + +/* + * Receive a packet from the BIF - called from interrupt handler. + */ +int bif_rx(struct sk_buff *skb) +{ +#if BIF_DEBUG + dump_packet("bif_rx:", skb->data, skb->len, seq++); +#endif + + if (bif_device == NULL) { + printk("bif: bif_device is NULL in bif_rx\n"); + dev_kfree_skb(skb, FREE_WRITE); + return 0; + } + skb->dev = bif_device; + skb->protocol = ETH_P_IP; + +#if 1 + /* try disabling checksums on receive */ + if (ap_ip_to_cid(*(u_long *)(((char *)skb->data)+12)) != -1) + skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + + /* + * Inform the network layer of the new packet. + */ + skb->mac.raw = skb->data; + netif_rx(skb); + + if (bif_stats == NULL) { + printk("bif: bif_stats is NULL is bif_rx\n"); + return 0; + } + bif_stats->rx_packets++; + + return 0; +} + +int bif_stop(struct device *dev) +{ + printk("in bif_close\n"); + + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +/* + * Return statistics of bif driver. + */ +static struct enet_statistics *bif_get_stats(struct device *dev) +{ + return((struct enet_statistics *)dev->priv); +} + diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c new file mode 100644 index 000000000000..7cfdafdc93cf --- /dev/null +++ b/drivers/ap1000/ddv.c @@ -0,0 +1,1008 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * ddv.c - Single AP1000 block driver. + * + * This block driver performs io operations to the ddv option + * board. (Hopefully:) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR DDV_MAJOR + +#include +#include +#include + +#define DDV_DEBUG 0 +#define AIR_DISK 1 + +#define SECTOR_SIZE 512 + +/* we can have lots of partitions */ +#define PARTN_BITS 6 +#define NUM_DDVDEVS (1<>16) | + ((OPTION_BASE & 0xf0000000)>>24) | + ((OPTION_BASE + 0x10000000)>>28); + OPT_IO(PRST) = 0; +} + +extern struct RequestTable *RTable; +extern struct OPrintBufArray *PrintBufs; +extern struct OAlignBufArray *AlignBufs; +extern struct DiskInfo *DiskInfo; + +static void ddv_release(struct inode * inode, struct file * filp) +{ +#if DEBUG + printk("ddv_release started\n"); +#endif + sync_dev(inode->i_rdev); +#if DEBUG + printk("ddv_release done\n"); +#endif +} + + +static unsigned in_request = 0; +static unsigned req_queued = 0; + +static void ddv_end_request(int uptodate,struct request *req) +{ + struct buffer_head * bh; + + ddv_stats.rq_finished++; + +/* printk("ddv_end_request(%d,%p)\n",uptodate,req); */ + + req->errors = 0; + if (!uptodate) { + printk("end_request: I/O error, dev %s, sector %lu\n", + kdevname(req->rq_dev), req->sector); + req->nr_sectors--; + req->nr_sectors &= ~SECTOR_MASK; + req->sector += (BLOCK_SIZE / SECTOR_SIZE); + req->sector &= ~SECTOR_MASK; + ddv_stats.errors++; + } + + if ((bh = req->bh) != NULL) { + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + if ((bh = req->bh) != NULL) { + req->current_nr_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("end_request: buffer-list destroyed\n"); + } + req->buffer = bh->b_data; + printk("WARNING: ddv: more sectors!\n"); + ddv_stats.errors++; + return; + } + } + if (req->sem != NULL) + up(req->sem); + req->rq_status = RQ_INACTIVE; + wake_up(&wait_for_request); +} + + +/* check that a request is all OK to process */ +static int request_ok(struct request *req) +{ + int minor; + if (!req) return 0; + + if (MAJOR(req->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": bad major number\n"); + if (!buffer_locked(req->bh)) + panic(DEVICE_NAME ": block not locked"); + + minor = MINOR(req->rq_dev); + if (minor >= NUM_DDVDEVS) { + printk("ddv_request: Invalid minor (%d)\n", minor); + return 0; + } + + if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) { + printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n", + minor,(int)req->sector,(int)req->current_nr_sectors, + ddv_sect_length[minor]); + return 0; + } + + if (req->cmd != READ && req->cmd != WRITE) { + printk("unknown request type %d\n",req->cmd); + return 0; + } + + /* it seems to be OK */ + return 1; +} + + +static void complete_request(struct request *req,int bnum) +{ + while (bnum--) { + ddv_end_request(1,req); + req = req->next; + } +} + + +static int completion_pointer = 0; + +static void check_completion(void) +{ + int i,bnum; + struct request *req; + + if (!RTable) return; + + for (; + (i=completion_pointer) != RTable->ddv_pointer && + RTable->async_info[i].status == DDV_REQ_FREE; + completion_pointer = INC_T(completion_pointer)) + { + req = (struct request *)RTable->async_info[i].argv[7]; + bnum = RTable->async_info[i].bnum; + if (!req || !bnum) { + printk("%s(%d)\n",__FILE__,__LINE__); + ddv_stats.errors++; + continue; + } + + RTable->async_info[i].status = 0; + RTable->async_info[i].argv[7] = 0; + + complete_request(req,bnum); + in_request--; + } +} + + +static struct request *get_request_queue(struct request *oldq) +{ + struct request *req,*req2; + + /* skip any non-active or bad requests */ + skip1: + if (!(req = CURRENT)) + return oldq; + + if (req->rq_status != RQ_ACTIVE) { + CURRENT = req->next; + goto skip1; + } + + if (!request_ok(req)) { + ddv_end_request(0,req); + CURRENT = req->next; + goto skip1; + } + + /* now grab as many as we can */ + req_queued++; + + for (req2 = req; + req2->next && + req2->next->rq_status == RQ_ACTIVE && + request_ok(req2->next); + req2 = req2->next) + req_queued++; + + /* leave CURRENT pointing at the bad ones */ + CURRENT = req2->next; + + /* chop our list at that point */ + req2->next = NULL; + + if (!oldq) + return req; + + for (req2=oldq;req2->next;req2=req2->next) ; + + req2->next = req; + + return oldq; +} + + +static void ddv_rem_complete(struct remote_request *rem) +{ + unsigned flags; + int bnum = rem->bnum; + struct request *req = rem->reqp; + + complete_request(req,bnum); + in_request--; + + save_flags(flags); cli(); + ddv_request1(); + restore_flags(flags); +} + + +/* + * The background ddv daemon. This receives remote disk requests + * and processes them via the normal block operations + */ +static int ddv_daemon(void *unused) +{ + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "ddv_daemon"); + current->blocked = ~0UL; /* block all signals */ + + /* Give it a realtime priority. */ + current->policy = SCHED_FIFO; + current->priority = 32; /* Fixme --- we need to standardise our + namings for POSIX.4 realtime scheduling + priorities. */ + + printk("Started ddv_daemon\n"); + + while (1) { + struct remote_request *rem; + unsigned flags; + struct buffer_head *bhlist[MAX_BNUM*4]; + int i,j,minor,len,shift,offset; + + save_flags(flags); cli(); + + while (!rem_queue) { + current->signal = 0; + interruptible_sleep_on(&ddv_daemon_wait); + } + + rem = rem_queue; + rem_queue = rem->u.next; + restore_flags(flags); + + + minor = MINOR(rem->req.rq_dev); + len = rem->req.current_nr_sectors; + offset = rem->req.sector; + + /* work out the conversion to the local block size from + sectors */ + for (shift=0; + (SECTOR_SIZE<req.rq_dev, + offset >> shift, + ddv_blocksizes[minor]); + if (!buffer_uptodate(bhlist[i])) + ll_rw_block(READ,1,&bhlist[i]); + offset += 1<u.fn = ddv_rem_complete; + tnet_rpc(rem->cell,rem,sizeof(int)*3,1); + } +} + + +/* receive a remote disk request */ +static void ddv_rem_queue(char *data,unsigned size) +{ + unsigned flags; + struct remote_request *rem = (struct remote_request *) + kmalloc(size,GFP_ATOMIC); + + if (!rem) { + /* oh bugger! */ + ddv_stats.errors++; + return; + } + + memcpy(rem,data,size); + rem->u.next = NULL; + + save_flags(flags); cli(); + + /* add it to our remote request queue */ + if (!rem_queue) + rem_queue = rem; + else + rem_queue_end->u.next = rem; + rem_queue_end = rem; + + restore_flags(flags); + + wake_up(&ddv_daemon_wait); +} + + +/* which disk should this request go to */ +static inline unsigned pardisk_num(struct request *req) +{ + int minor = MINOR(req->rq_dev); + unsigned stripe; + unsigned cell; + + if (minor < PARDISK_BASE) + return this_option; + + stripe = req->sector >> STRIPE_SHIFT; + cell = stripe % num_options; + + return cell; +} + + +/* check if a 2nd request can be tacked onto the first */ +static inline int contiguous(struct request *req1,struct request *req2) +{ + if (req2->cmd != req1->cmd || + req2->rq_dev != req1->rq_dev || + req2->sector != req1->sector + req1->current_nr_sectors || + req2->current_nr_sectors != req1->current_nr_sectors) + return 0; + if (pardisk_num(req1) != pardisk_num(req2)) + return 0; + return 1; +} + +static void ddv_request1(void) +{ + struct request *req,*req1,*req2; + unsigned offset,len,req_num,mlist,bnum,available=0; + static unsigned mptrs[MAX_BNUM]; + unsigned cell; + + if (in_request > REQUEST_HIGH) + return; + + next_request = get_request_queue(next_request); + + while ((req = next_request)) { + int minor; + + if (in_request >= MAX_REQUEST) + return; + + if (in_request>1 && req_queued MAX_BNUM) + available = MAX_BNUM; + + offset = req->sector; + len = req->current_nr_sectors; + minor = MINOR(req->rq_dev); + + mptrs[0] = (int)req->buffer; + + for (bnum=1,req1=req,req2=req->next; + req2 && bnumnext) { + mptrs[bnum++] = (int)req2->buffer; + } + + next_request = req2; + + + req_queued -= bnum; + ddv_stats.blocks += bnum; + ddv_stats.rq_started += bnum; + + if (req->cmd == READ) { + ddv_stats.reads++; + ddv_stats.sectors_read += len*bnum; + } else { + ddv_stats.writes++; + ddv_stats.sectors_written += len*bnum; + } + + if (minor >= PARDISK_BASE) { + /* translate the request to the normal partition */ + unsigned stripe; + minor -= PARDISK_BASE; + + stripe = offset >> STRIPE_SHIFT; + stripe /= num_options; + offset = (stripe << STRIPE_SHIFT) + + (offset & ((1<u.fn = ddv_rem_queue; + rem->cell = this_option; + rem->bnum = bnum; + rem->req = *req; + rem->reqp = req; + rem->req.rq_dev = MKDEV(MAJOR_NR,minor); + rem->req.sector = offset; + memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum); + + if (tnet_rpc(cell,rem,size,1) != 0) { + kfree_s(rem,size); + return; + } + } else { + /* its a local request */ + if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) { + ddv_stats.errors++; + panic("ddv: mlist corrupted"); + } + + req_num = RTable->cell_pointer; + RTable->async_info[req_num].status = + req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ; + RTable->async_info[req_num].bnum = bnum; + RTable->async_info[req_num].argv[0] = mlist; + RTable->async_info[req_num].argv[1] = len; + RTable->async_info[req_num].argv[2] = offset + + partition_tables[minor].start_sect; + RTable->async_info[req_num].argv[3] = bnum; + RTable->async_info[req_num].argv[7] = (unsigned)req; + RTable->cell_pointer = INC_T(RTable->cell_pointer); + + } + + in_request++; + } +} + + +static void ddv_request(void) +{ + cli(); + ddv_request1(); + sti(); +} + + +static void check_printbufs(void) +{ + int i; + + if (!PrintBufs) return; + + while (PrintBufs->option_counter != PrintBufs->cell_counter) { + i = PrintBufs->cell_counter; + printk("opiu (%d): ",i); + if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000) + printk("Error: bad format in printk at %p\n", + PrintBufs->bufs[i].fmt); + else + printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE, + PrintBufs->bufs[i].args[0], + PrintBufs->bufs[i].args[1], + PrintBufs->bufs[i].args[2], + PrintBufs->bufs[i].args[3], + PrintBufs->bufs[i].args[4], + PrintBufs->bufs[i].args[5]); + if (++PrintBufs->cell_counter == PRINT_BUFS) + PrintBufs->cell_counter = 0; + } +} + +static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + save_flags(flags); cli(); + OPT_IO(IRC1) = 0x80000000; + + check_printbufs(); + check_completion(); + + ddv_request1(); + restore_flags(flags); +} + +static int ddv_open(struct inode * inode, struct file * filp) +{ + int minor = MINOR(inode->i_rdev); + + if (!have_ddv_board || minor >= NUM_DDVDEVS) + return -ENODEV; + + if (minor >= PARDISK_BASE) { + ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE]; + ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE]; + } + + return 0; +} + + +static void ddv_open_reply(struct cap_request *creq) +{ + int size = creq->size - sizeof(*creq); + ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC); + read_bif(ddv_opcodep, size); +#if DEBUG + printk("received opiu kernel of size %d\n",size); +#endif + if (size == 0) + have_ddv_board = 0; + wake_up(&busy_wait); +} + + +static void ddv_load_opiu(void) +{ + int i; + struct cap_request creq; + + /* if the opiu kernel is already loaded then we don't do anything */ + if (!have_ddv_board || opiu_kernel_loaded) + return; + + bif_register_request(REQ_DDVOPEN,ddv_open_reply); + + /* send the open request to the front end */ + creq.cid = mpp_cid(); + creq.type = REQ_DDVOPEN; + creq.header = 0; + creq.size = sizeof(creq); + + bif_queue(&creq,0,0); + + ddv_set_optadr(); + + while (!ddv_opcodep) + sleep_on(&busy_wait); + + if (!have_ddv_board) + return; + + ddv_load_kernel(ddv_opcodep); + + kfree(ddv_opcodep); + ddv_opcodep = NULL; + + if (ddv_restart_cpu()) + return; + + ddv_sect_length[0] = DiskInfo->blocks; + ddv_blk_length[0] = DiskInfo->blocks >> 1; + ddv_blocksizes[0] = BLOCK_SIZE; + + ddv_geometry.cylinders = ddv_sect_length[0] / + (ddv_geometry.heads*ddv_geometry.sectors); + + ddv_gendisk.part[0].start_sect = 0; + ddv_gendisk.part[0].nr_sects = ddv_sect_length[0]; + + resetup_one_dev(&ddv_gendisk, 0); + + for (i=0;i> 1; + } + + /* setup the parallel partitions by multiplying the normal + partition by the number of options */ + for (;imax_p; + start = target << gdev->minor_shift; + + printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n", + dev,target,max_p,start); + + for (i=max_p - 1; i >=0 ; i--) { + int minor = start + i; + kdev_t devi = MKDEV(gdev->major, minor); + sync_dev(devi); + invalidate_inodes(devi); + invalidate_buffers(devi); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + }; + + ddv_sect_length[start] = DiskInfo->blocks; + ddv_blk_length[start] = DiskInfo->blocks >> 1; + + gdev->part[start].nr_sects = ddv_sect_length[start]; + resetup_one_dev(gdev, target); + + printk("sect_length[%d]=%d blk_length[%d]=%d\n", + start,ddv_sect_length[start], + start,ddv_blk_length[start]); + + for (i=0;ipart[start+i].nr_sects; + ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1; + if (gdev->part[start+i].nr_sects) + printk("partition[%d] start=%d length=%d\n",i, + (int)gdev->part[start+i].start_sect, + (int)gdev->part[start+i].nr_sects); + } + + return 0; +} + + + + +static int ddv_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int err; + struct ddv_geometry *loc = (struct ddv_geometry *) arg; + int dev; + int minor = MINOR(inode->i_rdev); + + if ((!inode) || !(inode->i_rdev)) + return -EINVAL; + dev = DEVICE_NR(inode->i_rdev); +#if DEBUG + printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor); +#endif + switch (cmd) { + case HDIO_GETGEO: + printk("\tHDIO_GETGEO\n"); + if (!loc) return -EINVAL; + if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT; + if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT; + if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT; + if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT; + return 0; + + case HDIO_GET_MULTCOUNT : + printk("\tHDIO_GET_MULTCOUNT\n"); + return -EINVAL; + + case HDIO_GET_IDENTITY : + printk("\tHDIO_GET_IDENTITY\n"); + return -EINVAL; + + case HDIO_GET_NOWERR : + printk("\tHDIO_GET_NOWERR\n"); + return -EINVAL; + + case HDIO_SET_NOWERR : + printk("\tHDIO_SET_NOWERR\n"); + return -EINVAL; + + case BLKRRPART: + printk("\tBLKRRPART\n"); + return ddv_revalidate(inode->i_rdev,&ddv_gendisk); + + case BLKGETSIZE: /* Return device size */ + if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT; +#if DEBUG + printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]); +#endif + return 0; + + default: + printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd); + return -EINVAL; + }; +} + +static struct file_operations ddv_fops = { + NULL, /* lseek - default */ + block_read, /* read */ + block_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + ddv_ioctl, /* ioctl */ + NULL, /* mmap */ + ddv_open, /* open */ + ddv_release, + block_fsync /* fsync */ +}; + + +static void ddv_status(void) +{ + if (!have_ddv_board) { + printk("no ddv board\n"); + return; + } + + printk(" +in_request %u req_queued %u +MTable: start=%u end=%u +Requests: started=%u finished=%u +Requests: completion_pointer=%u ddv_pointer=%u cell_pointer=%u +PrintBufs: option_counter=%u cell_counter=%u +ddv_stats: reads=%u writes=%u blocks=%u +ddv_stats: sectors_read=%u sectors_written=%u +CURRENT=%p next_request=%p errors=%u +", + in_request,req_queued, + RTable->start_mtable,RTable->end_mtable, + ddv_stats.rq_started,ddv_stats.rq_finished, + completion_pointer,RTable->ddv_pointer,RTable->cell_pointer, + PrintBufs->option_counter,PrintBufs->cell_counter, + ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks, + ddv_stats.sectors_read,ddv_stats.sectors_written, + CURRENT,next_request, + ddv_stats.errors); +} + + +int ddv_init(void) +{ + int cid; + + cid = mpp_cid(); + + if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) { + printk("ap: unable to get major %d for ap block dev\n", + MAJOR_NR); + return -1; + } + + printk("ddv_init: register dev %d\n", MAJOR_NR); + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = DDV_READ_AHEAD; + + bif_add_debug_key('d',ddv_status,"DDV status"); + ddv_gendisk.next = gendisk_head; + gendisk_head = &ddv_gendisk; + + num_options = mpp_num_cells(); + this_option = mpp_cid(); + + kernel_thread(ddv_daemon, NULL, 0); + + return(0); +} + + +static void ddv_geninit(struct gendisk *ignored) +{ + int i; + static int done = 0; + + if (done) + printk("ddv_geninit already done!\n"); + + done = 1; + + printk("ddv_geninit\n"); + + /* request interrupt line 2 */ + if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) { + printk("Failed to install ddv interrupt handler\n"); + } + + for (i=0;i +#include +#include +#include +#include +#include + + +#define GENDISK_STRUCT ddv_gendisk + +struct RequestTable *RTable=NULL; +struct OPrintBufArray *PrintBufs=NULL; +struct OAlignBufArray *AlignBufs=NULL; +struct DiskInfo *DiskInfo=NULL; + +extern int ddv_length[]; + +int ddv_mlist_available(void) +{ + int start = RTable->start_mtable; + int end = RTable->end_mtable; + + if (start >= end) + return (MTABLE_SIZE - start); + return (end+1) - start; +} + + +int ddv_get_mlist(unsigned mptr[],int bnum) +{ + int available = ddv_mlist_available(); + int i; + int start = RTable->start_mtable; + + if (available < bnum) { + return -1; + } + + for (i = 0; i < bnum; i++) { + unsigned phys = (unsigned)mmu_v2p((unsigned)mptr[i]); + if (phys == -1) + panic("bad address %x in ddv_get_mlist\n",mptr[i]); + RTable->mtable[RTable->start_mtable] = phys; + RTable->start_mtable = INC_ML(RTable->start_mtable); + } + + return start; +} + + + +void ddv_load_kernel(char *opcodep) +{ + int tsize; + char *p; + struct exec *mhead; + + mhead = (struct exec *)opcodep; + p = opcodep + sizeof(*mhead); + + tsize = (mhead->a_text + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); + memcpy((char *)OPIBUS_BASE+mhead->a_entry,p,mhead->a_text); + memcpy((char *)OPIBUS_BASE+mhead->a_entry+tsize, + p+mhead->a_text,mhead->a_data); + memset((char *)OPIBUS_BASE+mhead->a_entry+tsize+mhead->a_data,0, + mhead->a_bss+PAGE_SIZE); + +#ifdef DDV_DEBUG + printk("CELL(%d) loaded opiu kernel of size %ld %ld %ld (%ld)\n", + ap_getcid(), + mhead->a_text,mhead->a_data,mhead->a_bss,mhead->a_entry); +#endif +} + + +int ddv_restart_cpu(void) +{ + unsigned long timeout; + + OPT_IO(OPIU_OP) = OPIU_RESET; + OPT_IO(PRST) = PRST_IRST; + if (OPT_IO(PRST) != PRST_IRST) { + printk("_iu_load reset release error.\n"); + return(-1); + } + for (timeout=jiffies + 10; + (jiffies < timeout) || (OPT_IO(PBUF0) == 0); + ) /* wait */ ; + if (OPT_IO(PBUF0) == 0) { + printk("WARNING: option kernel didn't startup\n"); + return(-1); + } else { + printk("option kernel IU running\n"); + DiskInfo = (struct DiskInfo *)(OPT_IO(PBUF0) + OPIBUS_BASE); + RTable = (struct RequestTable *)(DiskInfo->ptrs[0]+OPIBUS_BASE); + PrintBufs = (struct OPrintBufArray *)(DiskInfo->ptrs[1]+OPIBUS_BASE); + AlignBufs = (struct OAlignBufArray *)(DiskInfo->ptrs[2]+OPIBUS_BASE); + + printk("Disk capacity: %d blocks of size %d\n", + (int)DiskInfo->blocks,(int)DiskInfo->blk_size); + + OPT_IO(PBUF0) = 0; + } + return(0); +} + + + diff --git a/drivers/ap1000/mac.c b/drivers/ap1000/mac.c new file mode 100644 index 000000000000..c17b4eec74fc --- /dev/null +++ b/drivers/ap1000/mac.c @@ -0,0 +1,1177 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Routines for controlling the FORMAC+ + */ +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include +#include +#include +#include + +#include +#include +#include + +#include "apfddi.h" +#include "smt-types.h" +#include "am79c830.h" +#include "mac.h" +#include "plc.h" +#include "apfddi-reg.h" + +#define MAC_DEBUG 0 + +/* Values for dma_state */ +#define IDLE 0 +#define XMITTING 1 +#define RECVING 2 + +/* + * Messages greater than this value are transferred to the FDDI send buffer + * using DMA. + */ +#define DMA_XMIT_THRESHOLD 64 +#define DMA_RECV_THRESHOLD 64 + +/* + * If the FDDI receive buffer is occupied by less than this value, then + * sending has priority. + */ +#define RECV_THRESHOLD (20*1024) + +#define DMA_RESET_MASKS ((AP_CLR_INTR_MASK<cmdreg1 = C1_SOFTWARE_RESET; + mac->said = (mip->s_address[0] << 8) + mip->s_address[1]; + mac->laim = (mip->l_address[0] << 8) + mip->l_address[1]; + mac->laic = (mip->l_address[2] << 8) + mip->l_address[3]; + mac->lail = (mip->l_address[4] << 8) + mip->l_address[5]; + mac->sagp = (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1]; + mac->lagm = (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1]; + mac->lagc = (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3]; + mac->lagl = (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5]; + mac->tmax = mip->tmax >> 5; + mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */ + mac->treq0 = mip->treq; + mac->treq1 = mip->treq >> 16; + mac->pri0 = ~0; + mac->pri1 = ~0; + mac->pri2 = ~0; + mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY + + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ + + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES; + mac->eacb = RECV_BUF_START - 1; + mac->earv = XMIT_BUF_START - 1; + mac->eas = mac->earv; + mac->eaa0 = BUFFER_SIZE - 1; + mac->eaa1 = mac->eaa0; + mac->eaa2 = mac->eaa1; + mac->wpxsf = 0; + mac->rpr = RECV_BUF_START; + mac->wpr = RECV_BUF_START + 1; + mac->swpr = RECV_BUF_START; + mac->wpxs = mac->eas; + mac->swpxs = mac->eas; + mac->rpxs = mac->eas; + mac->wpxa0 = XMIT_BUF_START; + mac->rpxa0 = XMIT_BUF_START; + + memset(msp, 0, sizeof(*msp)); + msp->recv_ptr = RECV_BUF_START; + msp->recv_empty = 1; + msp->xmit_ptr = XMIT_BUF_START; + msp->xmit_free = XMIT_BUF_START + 1; + msp->xmit_start = XMIT_BUF_START; + msp->xmit_chains = 0; + msp->frames_xmitted = 0; + msp->frames_recvd = 0; + msp->recv_aborted = 0; + + mac->mdreg1 = M1_MODE_MEMORY; + + mac_make_spframes(); + + return 0; +} + +int +mac_inited(struct mac_info *mip) +{ + struct formac_state *msp = &this_mac_state; + mac_status_t st1, st2; + + if (mac->said != (mip->s_address[0] << 8) + mip->s_address[1] + || mac->laim != (mip->l_address[0] << 8) + mip->l_address[1] + || mac->laic != (mip->l_address[2] << 8) + mip->l_address[3] + || mac->lail != (mip->l_address[4] << 8) + mip->l_address[5] + || mac->sagp != (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1] + || mac->lagm != (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1] + || mac->lagc != (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3] + || mac->lagl != (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5]) + return 1; + if ((mac->mdreg1 & ~M1_ADDET) != (M1_MODE_ONLINE | M1_SELECT_RA + | M1_FULL_DUPLEX)) + return 3; + if (mac->treq0 != (mip->treq & 0xffff) + || mac->treq1 != ((unsigned)mip->treq >> 16)) + return 4; + + st1 = (mac->st1u << 16) + mac->st1l; + st2 = (mac->st2u << 16) + mac->st2l; + if ((st2 & S2_RING_OP) == 0) + return 5; + + /* It's probably OK, reset some things to be safe. */ + this_mac_info = mip; + *csr0 &= ~CS0_HREQ; + mac->tmax = mip->tmax >> 5; + mac->tvx = (mip->tvx - 254) / 255; /* it's -ve, round downwards */ + mac->pri0 = ~0; + mac->pri1 = ~0; + mac->pri2 = ~0; + mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY + + 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ + + M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES; + + /* clear out the receive queue */ + mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV; + mac->rpr = RECV_BUF_START; + mac->wpr = RECV_BUF_START + 1; + mac->swpr = RECV_BUF_START; + + memset(msp, 0, sizeof(*msp)); + msp->recv_ptr = RECV_BUF_START; + msp->recv_empty = 1; + + /* XXX reset transmit pointers */ + mac->cmdreg2 = C2_ABORT_XMIT; + mac->cmdreg2 = C2_RESET_XMITQS; + mac->wpxa0 = XMIT_BUF_START; + mac->rpxa0 = XMIT_BUF_START; + msp->xmit_ptr = XMIT_BUF_START; + msp->xmit_free = XMIT_BUF_START + 1; + msp->xmit_start = XMIT_BUF_START; + msp->xmit_chains = 0; + + mac_make_spframes(); + mac->cmdreg1 = C1_CLR_ALL_LOCKS; + + msp->frames_xmitted = 0; + msp->frames_recvd = 0; + msp->recv_aborted = 0; + msp->ring_op = 1; + + mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_NSA; + mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16; + mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0); + mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF + | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS + | S2_NP_SIMULT_LOAD) >> 16; + mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME); + + return 0; +} + +void mac_make_spframes(void) +{ + volatile int *bp; + struct mac_info *mip = this_mac_info; + int sa; + struct formac_state *msp = &this_mac_state; + + /* initialize memory to avoid parity errors */ + *csr0 &= ~CS0_HREQ; + *csr1 &= ~CS1_BUF_WR_TAG; + for (bp = &buffer_mem[BUFFER_SIZE]; bp > &buffer_mem[XMIT_BUF_START];) + *--bp = 0xdeadbeef; + for (; bp > buffer_mem;) + *--bp = 0xfeedf00d; + buffer_mem[msp->recv_ptr] = 0; + + bp = buffer_mem; + *bp++ = 0; /* auto-void frame pointer (not used) */ + + /* make claim frame */ + sa = bp - buffer_mem; + *bp++ = 0xd8000011; /* claim frame descr. + length */ + *bp++ = 0xc3; /* FC value for claim frame, long addr */ + *bp++ = (mip->l_address[0] << 24) + (mip->l_address[1] << 16) + + (mip->l_address[2] << 8) + mip->l_address[3]; + *bp++ = (mip->l_address[4] << 24) + (mip->l_address[5] << 16) + + (mip->l_address[0] << 8) + mip->l_address[1]; + *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16) + + (mip->l_address[4] << 8) + mip->l_address[5]; + *bp++ = mip->treq; + mac->sacl = bp - buffer_mem; /* points to pointer to claim frame */ + *bp++ = 0xa0000000 + sa; /* pointer to start of claim frame */ + + /* make beacon frame */ + sa = bp - buffer_mem; + *bp++ = 0xd8000011; /* beacon frame descr. + length */ + *bp++ = 0xc2; /* FC value for beacon frame, long addr */ + *bp++ = 0; /* DA = 0 */ + *bp++ = (mip->l_address[0] << 8) + mip->l_address[1]; + *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16) + + (mip->l_address[4] << 8) + mip->l_address[5]; + *bp++ = 0; /* beacon reason = failed claim */ + mac->sabc = bp - buffer_mem; + *bp++ = 0xa0000000 + sa; /* pointer to start of beacon frame */ +} + +void mac_reset(LoopbackType loopback) +{ + int mode; + struct formac_state *msp = &this_mac_state; + + msp->loopback = loopback; + switch (loopback) { + case loop_none: + mode = M1_MODE_ONLINE; + break; + case loop_formac: + mode = M1_MODE_INT_LOOP; + break; + default: + mode = M1_MODE_EXT_LOOP; + break; + } + mac->mdreg1 = mode | M1_ADDET_NSA | M1_SELECT_RA | M1_FULL_DUPLEX; + mac->cmdreg1 = C1_IDLE_LISTEN; + mac->cmdreg1 = C1_CLR_ALL_LOCKS; + mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16; + mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0); + mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF + | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS + | S2_NP_SIMULT_LOAD) >> 16; + mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME); +} + +void mac_claim(void) +{ + mac->cmdreg1 = C1_CLAIM_LISTEN; +} + +void mac_disable(void) +{ + mac->mdreg1 = M1_MODE_MEMORY; + mac->imsk1u = ~0; + mac->imsk1l = ~0; + mac->imsk2u = ~0; + mac->imsk2l = ~0; + mac->wpr = mac->swpr + 1; + if (mac->wpr > mac->earv) + mac->wpr = mac->eacb + 1; + buffer_mem[mac->swpr] = 0; +} + +void mac_stats(void) +{ + struct formac_state *msp = &this_mac_state; + + if (msp->recv_ovf) + printk("%d receive buffer overflows\n", msp->recv_ovf); + if (msp->wrong_bb) + printk("%d frames on wrong byte bdry\n", msp->wrong_bb); + printk("%d frames transmitted, %d aborted\n", msp->frames_xmitted, + msp->xmit_aborted); + printk("%d frames received, %d aborted\n", msp->frames_recvd, + msp->recv_aborted); + printk("%d frames received with errors\n", msp->recv_error); +} + +void mac_sleep(void) +{ + /* disable the receiver */ + mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV; +} + +void mac_poll(void) +{ + mac_status_t st1, st2; + struct formac_state *msp = &this_mac_state; + int up, f, d, l, r, e, i; + + st1 = (mac->st1u << 16) + mac->st1l; + st2 = (mac->st2u << 16) + mac->st2l; + + if (st2 & S2_NP_SIMULT_LOAD) + panic("NP/formac simultaneous load!!!"); + + up = (st2 & S2_RING_OP) != 0; + if (up != msp->ring_op) { + /* ring has come up or down */ + msp->ring_op = up; + printk("mac: ring %s\n", up? "up": "down"); + set_ring_op(up); + } + + if (up) { + if (st1 & S1_XMIT_ABORT) { + ++msp->xmit_aborted; + if (st1 & S1_QUEUE_LOCK_ASYNC0) { + printk("mac: xmit queue locked, resetting xmit buffer\n"); + mac->cmdreg2 = C2_RESET_XMITQS; /* XXX bit gross */ + mac->rpxa0 = XMIT_BUF_START; + buffer_mem[XMIT_BUF_START] = 0; + msp->xmit_ptr = XMIT_BUF_START; + msp->xmit_start = XMIT_BUF_START; + msp->xmit_chains = 0; + mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK; + st1 &= ~(S1_END_CHAIN_ASYNC0 | S1_END_FRAME_ASYNC0 + | S1_XINSTR_FULL_ASYNC0); + } else + st1 |= S1_END_FRAME_ASYNC0; + } else if (st1 & S1_QUEUE_LOCK_ASYNC0) { + printk("mac: xmit queue locked, why?\n"); + mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK; + } + + if (st1 & S1_END_FRAME_ASYNC0) { + /* advance xmit_start */ + e = msp->xmit_start; + while (e != msp->xmit_ptr) { + /* find the end of the current frame */ + f = buffer_mem[e]; /* read pointer */ + if (f == 0) + break; /* huh?? */ + f &= 0xffff; + d = buffer_mem[f]; /* read descriptor */ + l = ((d & 0xffff) + ((d >> TD_BYTE_BDRY_LG) & 3) + 3) >> 2; + e = f + 1 + l; /* index of ptr at end of frame */ + r = mac->rpxa0; + if ((r <= msp->xmit_ptr && r < e && e <= msp->xmit_ptr) + || (r > msp->xmit_ptr && (r < e || e <= msp->xmit_ptr))) + break; /* up to current frame */ + /* printk("frame @ %x done\n", msp->xmit_start); */ + msp->xmit_start = e; + if ((st1 & S1_XMIT_ABORT) == 0) + ++msp->frames_xmitted; + if ((msp->xmit_chains == 1 && e == msp->xmit_ptr) || + (msp->xmit_chains > 1 && e == msp->xmit_chain_start[1])) { + /* we've finished chain 0 */ + --msp->xmit_chains; + for (i = 0; i < msp->xmit_chains; ++i) + msp->xmit_chain_start[i] = msp->xmit_chain_start[i+1]; + if (msp->xmit_chains >= 2) { + mac->cmdreg2 = C2_XMIT_ASYNCQ0; + /* printk("mac_poll: xmit chain\n"); */ + } + if (msp->xmit_chains == 0) + *csr0 &= ~CS0_LED1; + } + } + /* + * Now that we have a bit more space in the transmit buffer, + * see if we want to put another frame in. + */ +#if MAC_DEBUG + printk("Removed space in transmit buffer.\n"); +#endif + mac_process(); + } + } + + if (st2 & S2_RMT_EVENTS) { + rmt_event(st2); + } + + if (st2 & S2_RECV_COMPLETE) { + /* + * A frame has just finished arriving in the receive buffer. + */ + *csr0 |= CS0_LED2; + msp->recv_empty = 0; +#if MAC_DEBUG + printk("Frame has just trickled in...\n"); +#endif + mac_process(); + } + + if (st2 & S2_RECV_BUF_FULL) { + /* + * receive buffer overflow: reset and unlock the receive buffer. + */ +/* printk("mac: receive buffer full\n"); */ + mac->rpr = RECV_BUF_START; + mac->wpr = RECV_BUF_START + 1; + mac->swpr = RECV_BUF_START; + msp->recv_ptr = RECV_BUF_START; + msp->recv_empty = 1; + buffer_mem[RECV_BUF_START] = 0; + mac->cmdreg1 = C1_CLR_RECVQ_LOCK; + ++msp->recv_ovf; + +#if 0 + } else if (st2 & S2_RECV_FIFO_OVF) { + printk("mac: receive FIFO overflow\n"); + /* any further action required here? */ + + } else if (st2 & S2_MISSED_FRAME) { + printk("mac: missed frame\n"); +#endif + } + + if (st2 & S2_ERR_SPECIAL_FR) { + printk("mac: bug: error in special frame\n"); + mac_disable(); + } +} + +void +mac_xmit_alloc(sp, bb) + struct mac_buf *sp; + int bb; +{ + int nwords; + + nwords = (sp->length + bb + 3) >> 2; + sp->fr_start = mac_xalloc(nwords + 2); + sp->fr_end = sp->fr_start + nwords + 1; + sp->ptr = (char *) &buffer_mem[sp->fr_start + 1] + bb; + buffer_mem[sp->fr_start] = TD_MAGIC + (bb << TD_BYTE_BDRY_LG) + sp->length; +} + +void +mac_queue_frame(sp) + struct mac_buf *sp; +{ + struct formac_state *msp = &this_mac_state; + + buffer_mem[sp->fr_end] = 0; /* null pointer at end of frame */ + buffer_mem[msp->xmit_ptr] = PT_MAGIC + sp->fr_start; + if (msp->xmit_chains <= 2) { + msp->xmit_chain_start[msp->xmit_chains] = msp->xmit_ptr; + if (msp->xmit_chains < 2) + mac->cmdreg2 = C2_XMIT_ASYNCQ0; + ++msp->xmit_chains; + } else { + buffer_mem[msp->xmit_more_ptr] |= TD_MORE; + } + msp->xmit_ptr = sp->fr_end; + msp->xmit_more_ptr = sp->fr_start; + *csr0 |= CS0_LED1; +} + +int +mac_xalloc(int nwords) +{ + int fr_start; + struct formac_state *msp = &this_mac_state; + + /* + * Find some room in the transmit buffer. + */ + fr_start = msp->xmit_free; + if (fr_start > msp->xmit_start) { + if (fr_start + nwords > XMIT_BUF_END) { + /* no space at end - see if we can start again from the front */ + fr_start = XMIT_BUF_START; + if (fr_start + nwords > msp->xmit_start) + panic("no space in xmit buffer (1)"); + } + } else { + if (fr_start + nwords > msp->xmit_start) + panic("no space in xmit buffer (2)"); + } + + msp->xmit_free = fr_start + nwords; + + return fr_start; +} + +int +mac_recv_frame(sp) + struct mac_buf *sp; +{ + struct formac_state *msp = &this_mac_state; + int status, bb, orig_recv_ptr; + + orig_recv_ptr = msp->recv_ptr; + for (;;) { + status = buffer_mem[msp->recv_ptr]; + if ((status & RS_VALID) == 0) { + if (status != 0) { + printk("recv buf out of sync: recv_ptr=%x status=%x\n", + msp->recv_ptr, status); + printk(" rpr=%x swpr=%x, buf[rpr]=%x\n", mac->rpr, mac->swpr, + buffer_mem[mac->rpr]); + msp->recv_ptr = mac->swpr; + } + *csr0 &= ~CS0_LED2; + msp->recv_empty = 1; + if (mac->rpr == orig_recv_ptr) + mac->rpr = msp->recv_ptr; + return 0; + } + if (status & RS_ABORTED) + ++msp->recv_aborted; + else { + bb = (status >> RS_BYTE_BDRY_LG) & 3; + if (bb != 3) { + ++msp->wrong_bb; + bb = 3; + } + if ((status & RS_ERROR) == 0) + break; + ++msp->recv_error; + msp->recv_ptr += NWORDS((status & RS_LENGTH) + bb); + } + if (++msp->recv_ptr >= RECV_BUF_END) + msp->recv_ptr -= RECV_BUF_SIZE; + } + ++msp->frames_recvd; + if (mac->rpr == orig_recv_ptr) + mac->rpr = msp->recv_ptr; + + sp->fr_start = msp->recv_ptr; + sp->length = (status & RS_LENGTH) + bb; /* + 4 (status) - 4 (FCS) */ + sp->ptr = (void *) &buffer_mem[sp->fr_start]; + if ((msp->recv_ptr += NWORDS(sp->length) + 1) >= RECV_BUF_END) + msp->recv_ptr -= RECV_BUF_SIZE; + sp->fr_end = msp->recv_ptr; + sp->wraplen = (RECV_BUF_END - sp->fr_start) * 4; + sp->wrapptr = (void *) &buffer_mem[RECV_BUF_START]; + + return 1; +} + +void +mac_discard_frame(sp) + struct mac_buf *sp; +{ + mac->rpr = sp->fr_end; +} + +/* + * Return the number of bytes free in the async 0 transmit queue. + */ +int +mac_xmit_space(void) +{ + struct formac_state *msp = &this_mac_state; + int nw; + + if (msp->xmit_free > msp->xmit_start) { + nw = XMIT_BUF_END - msp->xmit_free; + if (nw < msp->xmit_start - XMIT_BUF_START) + nw = msp->xmit_start - XMIT_BUF_START; + } else + nw = msp->xmit_start - msp->xmit_free; + return nw <= 2? 0: (nw - 2) << 2; +} + +/* + * Return the number of bytes of frames available in the receive queue. + */ +int +mac_recv_level(void) +{ + int nw; + + nw = mac->swpr - mac->rpr; + if (nw < 0) + nw += mac->earv - mac->eacb; + return nw << 2; +} + +/* + * Return 1 iff all transmission has been completed, 0 otherwise. + */ +int mac_xmit_done(void) +{ + struct formac_state *msp = &this_mac_state; + + return msp->xmit_chains == 0; +} + +/* + * Append skbuff packet to queue. + */ +int mac_queue_append (struct sk_buff *skb) +{ + struct mac_queue *el; + unsigned flags; + save_flags(flags); cli(); + +#if MAC_DEBUG + printk("Appending queue element skb 0x%x\n", skb); +#endif + + if ((el = (struct mac_queue *)kmalloc(sizeof(*el), GFP_ATOMIC)) == NULL) { + restore_flags(flags); + return 1; + } + el->next = NULL; + el->skb = skb; + + if (mac_queue_top == NULL) { + mac_queue_top = mac_queue_bottom = el; + } + else { + mac_queue_bottom->next = el; + mac_queue_bottom = el; + } + restore_flags(flags); + return 0; +} + +/* + * If the packet originated from the same FDDI subnet as we are on, + * there is no need to perform checksumming as FDDI will does this + * us. + */ +#define CHECK_IF_CHECKSUM_REQUIRED(skb) \ + if ((skb)->protocol == ETH_P_IP) { \ + extern struct cap_init cap_init; \ + int *from_ip = (int *)((skb)->data+12); \ + int *to_ip = (int *)((skb)->data+16); \ + if ((*from_ip & cap_init.netmask) == (*to_ip & cap_init.netmask)) \ + (skb)->ip_summed = CHECKSUM_UNNECESSARY; \ + } + +/* + * Try to send and/or recv frames. + */ +void mac_process(void) +{ + volatile struct dma_chan *dma = (volatile struct dma_chan *) DMA3; + struct formac_state *msp = &this_mac_state; + struct mac_queue *el; + int nw=0, mrl = 0, fstart, send_buffer_full = 0; + unsigned flags; + + save_flags(flags); cli(); + +#if MAC_DEBUG + printk("In mac_process()\n"); +#endif + + /* + * Check if the DMA is being used. + */ + if (msp->dma_state != IDLE) { + restore_flags(flags); + return; + } + + while (mac_queue_top != NULL || /* Something to transmit */ + (mrl = mac_recv_level()) > 0) { /* Frames in receive buffer */ + send_buffer_full = 0; +#if MAC_DEBUG + printk("mac_process(): something to do... mqt %x mrl is %d\n", + mac_queue_top, mrl); +#endif + if (mac_queue_top != NULL && mrl < RECV_THRESHOLD) { + el = (struct mac_queue *)mac_queue_top; + + /* + * Check there is enough space in the FDDI send buffer. + */ + if (mac_xmit_space() < el->skb->len) { +#if MAC_DEBUG + printk("process_queue(): FDDI send buffer is full\n"); +#endif + send_buffer_full = 1; + } + else { +#if MAC_DEBUG + printk("mac_process(): sending a frame\n"); +#endif + /* + * Update mac_queue_top. + */ + mac_queue_top = mac_queue_top->next; + + /* + * Allocate space in the FDDI send buffer. + */ + msp->cur_mbuf.length = el->skb->len-3; + mac_xmit_alloc((struct mac_buf *)&msp->cur_mbuf, 3); + + /* + * If message size is greater than DMA_XMIT_THRESHOLD, send + * using DMA, otherwise use memcpy(). + */ + if (el->skb->len > DMA_XMIT_THRESHOLD) { + /* + * Start the DMA. + */ +#if MAC_DEBUG + printk("mac_process(): Starting send DMA...\n"); +#endif + nw = msp->cur_mbuf.fr_end - msp->cur_mbuf.fr_start + 1; + mac->wpxa0 = msp->cur_mbuf.fr_start + 1; + + *csr0 |= CS0_HREQ_WA0; + + msp->cur_macq = el; + msp->dma_state = XMITTING; + dma->st = DMA_DMST_RST; + dma->st = DMA_RESET_MASKS; + dma->hskip = 1; /* skip = 0, count = 1 */ + dma->vskip = 1; /* skip = 0, count = 1 */ + dma->maddr = (u_char *) + mmu_v2p((unsigned long)el->skb->data); + dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + + DMA_DCMD_TD_MD + nw; + *csr0 &= ~CS0_DMA_RECV; + *csr0 |= CS0_DMA_ENABLE; + + /* + * Don't process any more packets since the DMA is + * being used. + */ + break; + } + else { /* el->skb->len <= DMA_XMIT_THRESHOLD */ + /* + * Copy the data directly into the FDDI buffer. + */ +#if MAC_DEBUG + printk("mac_proces(): Copying send data...\n"); +#endif + memcpy(msp->cur_mbuf.ptr - 3, el->skb->data, + ROUND4(el->skb->len)); + mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); + dev_kfree_skb(el->skb, FREE_WRITE); + kfree_s(el, sizeof(*el)); + continue; + } + } + + /* + * We have reached here if there is not enough space in the + * send buffer. Try to receive some packets instead. + */ + } + + if (mac_recv_frame((struct mac_buf *)&msp->cur_mbuf)) { + volatile int fc, llc_header_word2; + int pkt_len = 0; + +#if MAC_DEBUG + printk("mac_process(): Receiving frames...\n"); +#endif + /* + * Get the fc, note only word accesses are allowed from the + * FDDI buffers. + */ + if (msp->cur_mbuf.wraplen > 4) { + fc = *(int *)(msp->cur_mbuf.ptr+4); + } + else { + /* + * fc_word must be at the start of the FDDI buffer. + */ +#if MAC_DEBUG + printk("Grabbed fc_word from wrapptr, wraplen %d\n", + msp->cur_mbuf.wraplen); +#endif + fc = *(int *)msp->cur_mbuf.wrapptr; + } + fc &= 0xff; + +#if MAC_DEBUG + printk("fc is 0x%x\n", fc); +#endif + if (fc < 0x50 || fc > 0x57) { + mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); + continue; + } + + /* + * Determine the size of the packet data and allocate a socket + * buffer. + */ + pkt_len = msp->cur_mbuf.length - FDDI_HARDHDR_LEN; +#if MAC_DEBUG + printk("Packet of length %d\n", pkt_len); +#endif + msp->cur_skb = dev_alloc_skb(ROUND4(pkt_len)); + + if (msp->cur_skb == NULL) { + printk("mac_process(): Memory squeeze, dropping packet.\n"); + apfddi_stats->rx_dropped++; + restore_flags(flags); + return; + } + msp->cur_skb->dev = apfddi_device; + + /* + * Hardware header isn't copied to skbuff. + */ + msp->cur_skb->mac.raw = msp->cur_skb->data; + apfddi_stats->rx_packets++; + + /* + * Determine protocol from llc header. + */ + if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) { + llc_header_word2 = *(int *)(msp->cur_mbuf.wrapptr + + (FDDI_HARDHDR_LEN - + msp->cur_mbuf.wraplen - 4)); + } + else { + llc_header_word2 = *(int *)(msp->cur_mbuf.ptr + + FDDI_HARDHDR_LEN - 4); + } + msp->cur_skb->protocol = llc_header_word2 & 0xFFFF; +#if MAC_DEBUG + printk("Got protocol 0x%x\n", msp->cur_skb->protocol); +#endif + + /* + * Copy data into socket buffer, which may be wrapped around the + * FDDI buffer. Use memcpy if the size of the data is less + * than DMA_RECV_THRESHOLD. Note if DMA is used, then wrap- + * arounds are handled automatically. + */ + if (pkt_len < DMA_RECV_THRESHOLD) { + if (msp->cur_mbuf.length < msp->cur_mbuf.wraplen) { + memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), + msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, + ROUND4(pkt_len)); + } + else if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) { +#if MAC_DEBUG + printk("Wrap case 2\n"); +#endif + memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), + msp->cur_mbuf.wrapptr + + (FDDI_HARDHDR_LEN - msp->cur_mbuf.wraplen), + ROUND4(pkt_len)); + } + else { +#if MAC_DEBUG + printk("wrap case 3\n"); +#endif + memcpy(skb_put(msp->cur_skb, + ROUND4(msp->cur_mbuf.wraplen- + FDDI_HARDHDR_LEN)), + msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, + ROUND4(msp->cur_mbuf.wraplen - FDDI_HARDHDR_LEN)); + memcpy(skb_put(msp->cur_skb, + ROUND4(msp->cur_mbuf.length - + msp->cur_mbuf.wraplen)), + msp->cur_mbuf.wrapptr, + ROUND4(msp->cur_mbuf.length - + msp->cur_mbuf.wraplen)); + } + +#if MAC_DEBUG + if (msp->cur_skb->protocol == ETH_P_IP) { + dump_packet("apfddi_rx:", msp->cur_skb->data, pkt_len, 0); + } + else if (msp->cur_skb->protocol == ETH_P_ARP) { + struct arphdr *arp = (struct arphdr *)msp->cur_skb->data; + printk("arp->ar_op is 0x%x ar_hrd %d ar_pro 0x%x ar_hln %d ar_ln %d\n", + arp->ar_op, arp->ar_hrd, arp->ar_pro, arp->ar_hln, + arp->ar_pln); + printk("sender hardware address: %x:%x:%x:%x:%x:%x\n", + *((u_char *)msp->cur_skb->data+8), + *((u_char *)msp->cur_skb->data+9), + *((u_char *)msp->cur_skb->data+10), + *((u_char *)msp->cur_skb->data+11), + *((u_char *)msp->cur_skb->data+12), + *((u_char *)msp->cur_skb->data+13)); + printk("sender IP number %d.%d.%d.%d\n", + *((u_char *)msp->cur_skb->data+14), + *((u_char *)msp->cur_skb->data+15), + *((u_char *)msp->cur_skb->data+16), + *((u_char *)msp->cur_skb->data+17)); + printk("receiver hardware address: %x:%x:%x:%x:%x:%x\n", + *((u_char *)msp->cur_skb->data+18), + *((u_char *)msp->cur_skb->data+19), + *((u_char *)msp->cur_skb->data+20), + *((u_char *)msp->cur_skb->data+21), + *((u_char *)msp->cur_skb->data+22), + *((u_char *)msp->cur_skb->data+23)); + printk("receiver IP number %d.%d.%d.%d\n", + *((u_char *)msp->cur_skb->data+24), + *((u_char *)msp->cur_skb->data+25), + *((u_char *)msp->cur_skb->data+26), + *((u_char *)msp->cur_skb->data+27)); + } +#endif + CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb); + + /* + * Inform the network layer of the new packet. + */ +#if MAC_DEBUG + printk("Calling netif_rx()\n"); +#endif + netif_rx(msp->cur_skb); + + /* + * Remove frame from FDDI buffer. + */ + mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); + continue; + } + else { + /* + * Set up dma and break. + */ +#if MAC_DEBUG + printk("mac_process(): Starting receive DMA...\n"); +#endif + nw = NWORDS(pkt_len); + msp->dma_state = RECVING; + *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE); +/* *csr1 |= CS1_RESET_FIFO; + *csr1 &= ~CS1_RESET_FIFO; */ + if ((*csr1 & CS1_FIFO_LEVEL) != 0) { + int x; + printk("fifo not empty! (csr1 = 0x%x) emptying...", *csr1); + do { + x = *fifo; + } while ((*csr1 & CS1_FIFO_LEVEL) != 0); + printk("done\n"); + } + fstart = msp->cur_mbuf.fr_start + NWORDS(FDDI_HARDHDR_LEN); + if (fstart >= RECV_BUF_END) + fstart -= RECV_BUF_SIZE; + mac->rpr = fstart; +#if MAC_DEBUG + printk("rpr=0x%x, nw=0x%x, stat=0x%x\n", + mac->rpr, nw, buffer_mem[msp->cur_mbuf.fr_start]); +#endif + dma->st = DMA_DMST_RST; + dma->st = DMA_RESET_MASKS; + dma->hskip = 1; /* skip = 0, count = 1 */ + dma->vskip = 1; /* skip = 0, count = 1 */ + dma->maddr = (u_char *) + mmu_v2p((unsigned long) + skb_put(msp->cur_skb, ROUND4(pkt_len))); + dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + DMA_DCMD_TD_DM + + nw - 4; + *csr0 |= CS0_HREQ_RECV | CS0_DMA_RECV; + *csr0 |= CS0_DMA_ENABLE; +#if MAC_DEBUG + printk("mac_process(): DMA is away!\n"); +#endif + break; + } + } + else { +#if MAC_DEBUG + printk("mac_recv_frame failed\n"); +#endif + if (msp->recv_empty && send_buffer_full) + break; + } + } + /* + * Update mac_queue_bottom. + */ + if (mac_queue_top == NULL) + mac_queue_bottom = NULL; + +#if MAC_DEBUG + printk("End of mac_process()\n"); +#endif + restore_flags(flags); +} + + +#define DMA_IN(reg) (*(volatile unsigned *)(reg)) +#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) + +/* + * DMA completion handler. + */ +void mac_dma_complete(void) +{ + volatile struct dma_chan *dma; + struct formac_state *msp = &this_mac_state; + unsigned a; + + a = DMA_IN(DMA3_DMST); + if (!(a & DMA_INTR_REQS)) { + if (msp->dma_state != IDLE && (a & DMA_DMST_AC) == 0) { + printk("dma completed but no interrupt!\n"); + msp->dma_state = IDLE; + } + return; + } + + DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<dma_state == XMITTING && ((dma->st & DMA_DMST_AC) == 0)) { + /* + * Transmit DMA finished. + */ + int i = 20; +#if MAC_DEBUG + printk("In mac_dma_complete for transmit complete\n"); +#endif + while (*csr1 & CS1_FIFO_LEVEL) { + if (--i <= 0) { + printk("csr0=0x%x csr1=0x%x: fifo not emptying\n", *csr0, + *csr1); + return; + } + } + *csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE); + msp->dma_state = IDLE; +#if MAC_DEBUG + printk("mac_dma_complete(): Calling mac_queue_frame\n"); +#endif + mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); + dev_kfree_skb(msp->cur_macq->skb, FREE_WRITE); + kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq))); + msp->cur_macq = NULL; +#if MAC_DEBUG + printk("mac_dma_complete(): Calling mac_process()\n"); +#endif + mac_process(); +#if MAC_DEBUG + printk("End of mac_dma_complete transmitting\n"); +#endif + } + else if (msp->dma_state == RECVING && ((dma->st & DMA_DMST_AC) == 0)) { + /* + * Receive DMA finished. Copy the last four words from the + * fifo into the buffer, after turning off the host requests. + * We do this to avoid reading past the end of frame. + */ + int *ip, i; + +#if MAC_DEBUG + printk("In mac_dma_complete for receive complete\n"); +#endif + msp->dma_state = IDLE; + ip = (int *)mmu_p2v((unsigned long)dma->cmaddr); + +#if MAC_DEBUG + printk("ip is 0x%x, skb->data is 0x%x\n", ip, msp->cur_skb->data); +#endif + + *csr0 &= ~(CS0_DMA_ENABLE | CS0_HREQ); + + for (i = 0; (*csr1 & CS1_FIFO_LEVEL); ++i) + ip[i] = *fifo; + if (i != 4) + printk("mac_dma_complete(): not four words remaining in fifo?\n"); +#if MAC_DEBUG + printk("Copied last four words out of fifo\n"); +#endif + + /* + * Remove the frame from the FDDI receive buffer. + */ + mac_discard_frame((struct mac_buf *)&msp->cur_mbuf); + + CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb); + + /* + * Now inject the packet into the network system. + */ + netif_rx(msp->cur_skb); + +#if MAC_DEBUG + dump_packet("mac_dma_complete:", msp->cur_skb->data, 0, 0); +#endif + + /* + * Check if any more frames can be processed. + */ + mac_process(); + +#if MAC_DEBUG + printk("End of mac_dma_complete receiving\n"); +#endif + } +#if MAC_DEBUG + printk("End of mac_dma_complete()\n"); +#endif +} + +static void mac_print_state(void) +{ + struct formac_state *msp = &this_mac_state; + + printk("DMA3_DMST is 0x%x dma_state is %d\n", DMA_IN(DMA3_DMST), + msp->dma_state); + printk("csr0 = 0x%x, csr1 = 0x%x\n", *csr0, *csr1); +} + + diff --git a/drivers/ap1000/mac.h b/drivers/ap1000/mac.h new file mode 100644 index 000000000000..85f02b4a3cd9 --- /dev/null +++ b/drivers/ap1000/mac.h @@ -0,0 +1,82 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Definitions of MAC state structures etc. + */ + +struct mac_info { + TimerTwosComplement tmax; + TimerTwosComplement tvx; + TimerTwosComplement treq; + ShortAddressType s_address; + LongAddressType l_address; + ShortAddressType s_group_adrs; + LongAddressType l_group_adrs; + int rcv_own_frames; + int only_good_frames; +}; + + +struct mac_buf { + struct mac_buf *next; + int ack; + int length; + void *ptr; + int wraplen; + void *wrapptr; + int fr_start; + int fr_end; +}; + +int mac_xmit_space(void); +void mac_xmit_alloc(struct mac_buf *, int); +void mac_queue_frame(struct mac_buf *); +int mac_recv_frame(struct mac_buf *); +void mac_discard_frame(struct mac_buf *); +int mac_init(struct mac_info *mip); +int mac_inited(struct mac_info *mip); +void mac_reset(LoopbackType loopback); +void mac_claim(void); +void mac_sleep(void); +void mac_poll(void); +void mac_disable(void); +void mac_make_spframes(void); +int mac_xalloc(int nwords); +int mac_xmit_dma(struct sk_buff *skb); +void mac_dma_complete(void); +void mac_process(void); +int mac_queue_append(struct sk_buff *skb); + +struct dma_chan { + int cmd; /* cmd << 16 + size */ + int st; /* status << 16 + current size */ + int hskip; /* hskip << 16 + hcnt */ + int vskip; /* vskip << 16 + vcnt */ + unsigned char *maddr; /* memory address */ + unsigned char *cmaddr; /* current memory address */ + int ccount; /* h_count << 16 + v_count */ + int *tblp; /* table pointer */ + int *ctblp; /* current table pointer */ + unsigned char *hdptr; /* header pointer */ +}; + +#define ROUND4(x) (((x) + 3) & -4) +#define ROUND8(x) (((x) + 7) & -8) +#define ROUND16(x) (((x) + 15) & -16) +#define ROUNDLINE(x) ROUND16(x) + +#define NWORDS(x) (((x) + 3) >> 2) +#define NLINES(x) (((x) + 15) >> 4) + +/* + * Queue element used to queue transmit requests on the FDDI. + */ +struct mac_queue { + volatile struct mac_queue *next; + struct sk_buff *skb; +}; diff --git a/drivers/ap1000/plc.c b/drivers/ap1000/plc.c new file mode 100644 index 000000000000..b29b1a4c2d7b --- /dev/null +++ b/drivers/ap1000/plc.c @@ -0,0 +1,393 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Routines for controlling the Am79c864 physical layer controller. + * + * This chip implements some parts of the FDDI SMT standard + * (PCM: physical connection management, LEM: link error monitor, etc.) + * as well as the FDDI PHY standard. + */ +#include +#include +#include +#include "apfddi.h" +#include "smt-types.h" +#include "am79c864.h" +#include "plc.h" +#include "apfddi-reg.h" + +typedef enum { + off, + signalling, + doing_lct, + joining, + active +} PlcPhase; + +struct plc_state { + LoopbackType loopback; + char t_val[16]; + char r_val[16]; + int n; + PortType peer_type; + PlcPhase phase; +}; + +struct plc_info *this_plc_info; +struct plc_state this_plc_state; + +void plc_init(struct plc_info *pip) +{ + int class, x; + struct plc_state *psp = &this_plc_state; + + this_plc_info = pip; + + /* first turn it off, clear registers */ + class = pip->port_type == pt_s? CB_CLASS_S: 0; + plc->ctrl_b = CB_PC_STOP + class; + plc->intr_mask = IE_NP_ERROR; + x = plc->intr_event; /* these register clear when read */ + x = plc->viol_sym_ct; + x = plc->min_idle_ct; + x = plc->link_err_ct; + + /* initialize registers */ + plc->ctrl_a = 0; + plc->ctrl_b = class; + plc->c_min = pip->c_min >> 8; + plc->tl_min = pip->tl_min >> 8; + plc->tb_min = pip->tb_min >> 8; + plc->t_out = pip->t_out >> 8; + plc->t_scrub = pip->t_scrub >> 8; + plc->ns_max = pip->ns_max >> 2; + + psp->phase = off; +} + +int +plc_inited(struct plc_info *pip) +{ + int class, x; + struct plc_state *psp = &this_plc_state; + + class = pip->port_type == pt_s? CB_CLASS_S: 0; + if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0) + return 1; + if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class) + return 2; + if (plc->status_a & SA_SIG_DETECT) + return 3; + if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE)) + != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE)) + return 4; + + /* all seems OK, reset the timers and counters just to be sure */ + plc->intr_mask = IE_NP_ERROR; + x = plc->intr_event; /* these register clear when read */ + x = plc->viol_sym_ct; + x = plc->min_idle_ct; + x = plc->link_err_ct; + + plc->c_min = pip->c_min >> 8; + plc->tl_min = pip->tl_min >> 8; + plc->tb_min = pip->tb_min >> 8; + plc->t_out = pip->t_out >> 8; + plc->t_scrub = pip->t_scrub >> 8; + plc->ns_max = pip->ns_max >> 2; + + psp->phase = active; + /* XXX should initialize other fields of this_plc_state */ + + return 0; +} + +void plc_sleep(void) +{ +} + +void pc_start(LoopbackType loopback) +{ + int x; + struct plc_info *pip = this_plc_info; + struct plc_state *psp = &this_plc_state; + + /* make sure it's off */ + plc->ctrl_b &= ~CB_PCM_CTRL; + plc->ctrl_b |= CB_PC_STOP; + + /* set up loopback required */ + psp->loopback = loopback; + x = 0; + switch (loopback) { + case loop_plc_lm: + x = CA_LM_LOOP; + break; + case loop_plc_eb: + x = CA_EB_LOOP; + break; + case loop_pdx: + x = CA_LOOPBACK; + break; + default: + x = 0; + } + plc->ctrl_a = x; + + /* set up bits to be exchanged */ + psp->t_val[0] = 0; + psp->t_val[1] = ((int) pip->port_type >> 1) & 1; + psp->t_val[2] = (int) pip->port_type & 1; + psp->t_val[4] = 0; /* XXX assume we want short LCT */ + psp->t_val[5] = 0; + psp->t_val[6] = 0; /* XXX too lazy to fire up my MAC for LCT */ + psp->t_val[8] = 0; /* XXX don't wanna local loop */ + psp->t_val[9] = 1; /* gotta MAC on port output */ + + pc_restart(); +} + +void pc_restart(void) +{ + struct plc_state *psp = &this_plc_state; + + if (psp->phase != off) + printk("restarting pcm\n"); + if (psp->phase == active) + set_cf_join(0); /* we're down :-( */ + + psp->n = 0; + plc->vec_length = 3 - 1; + plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1) + + (psp->t_val[2] << 2); + + plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE; + plc->ctrl_b &= ~CB_PCM_CTRL; + plc->ctrl_b |= CB_PC_START; /* light blue paper and stand clear */ + + psp->phase = signalling; +} + +void pc_stop(void) +{ + struct plc_state *psp = &this_plc_state; + + if (psp->phase == active) + set_cf_join(0); + plc->ctrl_b &= ~CB_PCM_CTRL; + plc->ctrl_b |= CB_PC_STOP; + plc->intr_mask = IE_NP_ERROR; + psp->phase = off; +} + +void plc_poll(void) +{ + struct plc_state *psp = &this_plc_state; + int events, i; + + if ((*csr0 & CS0_PHY_IRQ) == 0) + return; + events = plc->intr_event & plc->intr_mask; + if (events & IE_NP_ERROR) { + printk("plc: NP error!\n"); + } + if (events & IE_PCM_BREAK) { + i = plc->status_b & SB_BREAK_REASON; + if (i > SB_BREAK_REASON_START) { + if (psp->phase == signalling || psp->phase == doing_lct) + pcm_dump_rtcodes(); + printk("pcm: break reason %d\n", i); + if (psp->phase != off) + pc_restart(); + /* XXX need to check for trace? */ + } + } + if (events & IE_PCM_CODE) { + if (psp->phase == signalling) + pcm_pseudo_code(); + else if (psp->phase == doing_lct) + pcm_lct_done(); + else + printk("XXX pcm_code interrupt in phase %d?\n", psp->phase); + } + if (events & IE_PCM_ENABLED) { + if (psp->phase == joining) + pcm_enabled(); + else + printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase); + } + if (events & IE_TRACE_PROP) { + if (psp->phase == active) + pcm_trace_prop(); + else + printk("XXX trace_prop interrupt in phase %d\n", psp->phase); + } +} + +void pcm_pseudo_code(void) +{ + struct plc_info *pip = this_plc_info; + struct plc_state *psp = &this_plc_state; + int i, nb, lct, hislct; + + /* unpack the bits from the peer */ + nb = plc->vec_length + 1; + i = plc->rcv_vector; + do { + psp->r_val[psp->n++] = i & 1; + i >>= 1; + } while (--nb > 0); + + /* send some more, do LCT, whatever */ + switch (psp->n) { + case 3: + /* + * Got escape flag, port type; send compatibility, + * LCT duration, MAC for LCT flag. + */ + if (psp->r_val[0]) { + /* help! what do I do now? */ + pcm_dump_rtcodes(); + pc_restart(); + break; + } + psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]); + /* XXX we're type S, we talk to anybody */ + psp->t_val[3] = 1; + + plc->vec_length = 4 - 1; + plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1) + + (psp->t_val[5] << 2) + (psp->t_val[6] << 3); + break; + + case 7: + /* + * Got compatibility, LCT duration, MAC for LCT flag; + * time to do the LCT. + */ + lct = (psp->t_val[4] << 1) + psp->t_val[5]; + hislct = (psp->r_val[4] << 1) + psp->r_val[5]; + if (hislct > lct) + lct = hislct; + + /* set LCT duration */ + switch (lct) { + case 0: + plc->lc_length = pip->lc_short >> 8; + plc->ctrl_b &= ~CB_LONG_LCT; + break; + case 1: + plc->lc_length = pip->lc_medium >> 8; + plc->ctrl_b &= ~CB_LONG_LCT; + break; + case 2: + plc->ctrl_b |= CB_LONG_LCT; + /* XXX set up a timeout for pip->lc_long */ + break; + case 3: + plc->ctrl_b |= CB_LONG_LCT; + /* XXX set up a timeout for pip->lc_extended */ + break; + } + + /* start the LCT */ + i = plc->link_err_ct; /* clear the register */ + plc->ctrl_b &= ~CB_PC_LCT; + /* XXX assume we're not using the MAC for LCT; + if he's got a MAC, loop his stuff back, otherwise send idle. */ + if (psp->r_val[6]) + plc->ctrl_b |= CB_PC_LCT_LOOP; + else + plc->ctrl_b |= CB_PC_LCT_IDLE; + psp->phase = doing_lct; + break; + + case 8: + /* + * Got LCT result, send MAC for local loop and MAC on port + * output flags. + */ + if (psp->t_val[7] || psp->r_val[7]) { + printk("LCT failed, restarting.\n"); + /* LCT failed - do at least a medium length test next time. */ + if (psp->t_val[4] == 0 && psp->t_val[5] == 0) + psp->t_val[5] = 1; + pcm_dump_rtcodes(); + pc_restart(); + break; + } + plc->vec_length = 2 - 1; + plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1); + break; + + case 10: + /* + * Got MAC for local loop and MAC on port output flags. + * Let's join. + */ + plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED; + plc->ctrl_b |= CB_PC_JOIN; + psp->phase = joining; + /* printk("pcm: joining\n"); */ + break; + + default: + printk("pcm_pseudo_code bug: n = %d\n", psp->n); + } +} + +void pcm_lct_done(void) +{ + struct plc_state *psp = &this_plc_state; + int i; + + i = plc->link_err_ct; + psp->t_val[7] = i > 0; + printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i); + plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT); + plc->vec_length = 1 - 1; + plc->xmit_vector = psp->t_val[7]; + psp->phase = signalling; +} + +void pcm_dump_rtcodes(void) +{ + struct plc_state *psp = &this_plc_state; + int i; + + if (psp->n > 0) { + printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n); + for (i = 0; i < psp->n; ++i) + printk(" %d", psp->t_val[i]); + printk("\nr_val:"); + for (i = 0; i < psp->n; ++i) + printk(" %d", psp->r_val[i]); + printk("\n"); + } +} + +void pcm_enabled(void) +{ + struct plc_state *psp = &this_plc_state; + int i; + + printk("pcm: enabled\n"); + psp->phase = active; + i = plc->link_err_ct; /* clear the register */ + /* XXX should set up LEM here */ + /* XXX do we want to count violation symbols, minimum idle gaps, + or elasticity buffer errors? */ + plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP; + set_cf_join(1); /* we're up :-) */ +} + +void pcm_trace_prop(void) +{ + /* XXX help! what do I do now? */ + pc_stop(); +} diff --git a/drivers/ap1000/plc.h b/drivers/ap1000/plc.h new file mode 100644 index 000000000000..f87783f57c0f --- /dev/null +++ b/drivers/ap1000/plc.h @@ -0,0 +1,53 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Definitions for PLC state structures etc. + */ + +struct plc_info { + PortType port_type; + TimerTwosComplement c_min; + TimerTwosComplement tl_min; + TimerTwosComplement tb_min; + TimerTwosComplement t_out; + TimerTwosComplement lc_short; + TimerTwosComplement lc_medium; + TimerTwosComplement lc_long; + TimerTwosComplement lc_extended; + TimerTwosComplement t_scrub; + TimerTwosComplement ns_max; + Counter link_errors; + Counter viol_syms; + Counter mini_occur; + int min_idle_gap; + double link_error_rate; +}; + +void plc_init(struct plc_info *pip); +int plc_inited(struct plc_info *pip); +void pc_start(LoopbackType loopback); +void plc_sleep(void); +void plc_poll(void); +void pc_stop(void); +void pc_restart(void); +void pcm_dump_rtcodes(void); +void pcm_pseudo_code(void); +void pcm_lct_done(void); +void pcm_enabled(void); +void pcm_trace_prop(void); + + + + + + + + + + + diff --git a/drivers/ap1000/ringbuf.c b/drivers/ap1000/ringbuf.c new file mode 100644 index 000000000000..b8bcbb541c6c --- /dev/null +++ b/drivers/ap1000/ringbuf.c @@ -0,0 +1,327 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * linux/drivers/ap1000/ringbuf.c + * + * This provides the /proc/XX/ringbuf interface to the Tnet ring buffer + */ +#define _APLIB_ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* we have a small number of reserved ring buffers to ensure that at + least one parallel program can always run */ +#define RBUF_RESERVED 4 +#define RBUF_RESERVED_ORDER 5 +static struct { + char *rb_ptr; + char *shared_ptr; + int used; +} reserved_ringbuf[RBUF_RESERVED]; + + +void ap_ringbuf_init(void) +{ + int i,j; + char *rb_ptr, *shared_ptr; + int rb_size = PAGE_SIZE * (1<ringbuf) return; + + if (tsk->ringbuf->ringbuf) { + char *rb_ptr = tsk->ringbuf->ringbuf; + char *shared_ptr = tsk->ringbuf->shared; + int order = tsk->ringbuf->order; + int rb_size = PAGE_SIZE * (1<ringbuf,sizeof(*(tsk->ringbuf))); + tsk->ringbuf = NULL; +} + + +/* + * map the ring buffer into users memory + */ +static int cap_map(int rb_size) +{ + struct task_struct *tsk=current; + int i; + char *rb_ptr=NULL; + char *shared_ptr=NULL; + int order = 0; + int error,old_uid; + + error = verify_area(VERIFY_WRITE,(char *)RBUF_VBASE,rb_size); + if (error) return error; + + if (!MPP_IS_PAR_TASK(tsk->taskid)) { + printk("ringbuf_mmap called from non-parallel task\n"); + return -EINVAL; + } + + + if (tsk->ringbuf) return -EINVAL; + + rb_size -= RBUF_RING_BUFFER_OFFSET; + rb_size >>= 1; + + switch (rb_size/1024) { + case 128: + order = 5; + break; + case 512: + order = 7; + break; + case 2048: + order = 9; + break; + case 8192: + order = 11; + break; + default: + printk("ringbuf_mmap with invalid size %d\n",rb_size); + return -EINVAL; + } + + if (order == RBUF_RESERVED_ORDER) { + for (i=0;ieuid; + current->euid = 0; + error = sys_mlock(RBUF_VBASE,2*rb_size+RBUF_RING_BUFFER_OFFSET); + current->euid = old_uid; + if (error) { + printk("ringbuffer mlock failed\n"); + return error; + } +#endif + + /* the queue pages */ +#define MAP_QUEUE(offset,phys) \ + io_remap_page_range(RBUF_VBASE + offset, \ + phys<ringbuf) { + tsk->ringbuf = (void *)kmalloc(sizeof(*(tsk->ringbuf)),GFP_ATOMIC); + if (!tsk->ringbuf) + return -ENOMEM; + } + + memset(tsk->ringbuf,0,sizeof(*tsk->ringbuf)); + tsk->ringbuf->ringbuf = rb_ptr; + tsk->ringbuf->shared = shared_ptr; + tsk->ringbuf->order = order; + tsk->ringbuf->write_ptr = mmu_v2p((unsigned)rb_ptr)<<1; + tsk->ringbuf->vaddr = RBUF_VBASE; + + memset(tsk->ringbuf->vaddr+RBUF_SHARED_PAGE_OFF,0,PAGE_SIZE); + { + struct _kernel_cap_shared *_kernel = + (struct _kernel_cap_shared *)tsk->ringbuf->vaddr; + _kernel->rbuf_read_ptr = (rb_size>>5) - 1; + } + + return 0; +} + + +static int +ringbuf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int numcells, *phys_cells; + extern struct cap_init cap_init; + + switch (cmd) { + case CAP_GETINIT: + if (copy_to_user((char *)arg,(char *)&cap_init,sizeof(cap_init))) + return -EFAULT; + break; + + case CAP_SYNC: + if (verify_area(VERIFY_READ, (void *) arg, sizeof(int)*2)) + return -EFAULT; + if (get_user(numcells,(int *)arg)) return -EFAULT; + if (get_user((unsigned)phys_cells, + ((int *)arg)+1)) return -EFAULT; + if (verify_area(VERIFY_READ,phys_cells,sizeof(int)*numcells)) + return -EFAULT; + return ap_sync(numcells,phys_cells); + break; + + case CAP_SETGANG: + { + int v; + if (get_user(v,(int *)arg)) return -EFAULT; + mpp_set_gang_factor(v); + break; + } + + case CAP_MAP: + return cap_map(arg); + + default: + printk("unknown ringbuf ioctl %d\n",cmd); + return -EINVAL; + } + return 0; +} + + +static struct file_operations proc_ringbuf_operations = { + NULL, + NULL, + NULL, + NULL, /* readdir */ + NULL, /* poll */ + ringbuf_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_ringbuf_inode_operations = { + &proc_ringbuf_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff --git a/drivers/ap1000/smt-types.h b/drivers/ap1000/smt-types.h new file mode 100644 index 000000000000..b17c83176724 --- /dev/null +++ b/drivers/ap1000/smt-types.h @@ -0,0 +1,167 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Definitions for FDDI Station Management. + */ + +/* + * FDDI-COMMON types. + */ + +typedef unsigned int Counter; /* 32-bit event counter */ + +typedef enum { + cp_isolated, + cp_local, + cp_secondary, + cp_primary, + cp_concatenated, + cp_thru +} CurrentPath; + +typedef char Flag; + +typedef unsigned char LongAddressType[6]; + +typedef enum { + pt_a, + pt_b, + pt_s, + pt_m, + pt_none +} PortType; + +typedef unsigned short ResourceId; + +typedef int Time; /* time in 80ns units */ +#define FDDI_TIME_UNIT 80e-9 /* 80 nanoseconds */ +#define SECS_TO_FDDI_TIME(s) ((int)((s)/FDDI_TIME_UNIT+0.99)) + +typedef int TimerTwosComplement; + +/* + * FDDI-SMT types. + */ +typedef enum { + ec_Out, + ec_In, + ec_Trace, + ec_Leave, + ec_Path_Test, + ec_Insert, + ec_Check, + ec_Deinsert +} ECMState; + +/* + * FDDI-MAC types. + */ +typedef enum { + dat_none, + dat_pass, + dat_fail +} DupAddressTest; + +typedef unsigned short DupCondition; +#define DC_MYDUP 1 +#define DC_UNADUP 2 + +typedef unsigned short FS_Functions; +#define FSF_FS_REPEATING 1 +#define FSF_FS_SETTING 2 +#define FSF_FS_CLEARING 4 + +typedef unsigned char NACondition; +#define NAC_UNACHANGE 1 +#define NAC_DNACHANGE 2 + +typedef enum { + rmt_Isolated, + rmt_Non_Op, + rmt_Ring_Op, + rmt_Detect, + rmt_Non_Op_Dup, + rmt_Ring_Op_Dup, + rmt_Directed, + rmt_Trace +} RMTState; + +typedef unsigned char ShortAddressType[2]; + +/* + * FDDI-PATH types. + */ +typedef unsigned short TraceStatus; +#define TS_TRACEINITIATED 1 +#define TS_TRACEPROPAGATED 2 +#define TS_TRACETERMINATED 4 +#define TS_TRACETIMEOUT 8 + +/* + * FDDI-PORT types. + */ +typedef enum { + PC_Maint, + PC_Enable, + PC_Disable, + PC_Start, + PC_Stop +} ActionType; + +typedef unsigned char ConnectionPolicies; +#define PC_MAC_LCT 1 +#define PC_MAC_LOOP 2 + +typedef enum { + cs_disabled, + cs_connecting, + cs_standby, + cs_active +} ConnectState; + +typedef enum { + ls_qls, + ls_ils, + ls_mls, + ls_hls, + ls_pdr, + ls_lsu, + ls_nls +} LineState; + +typedef enum { + pc_Off, + pc_Break, + pc_Trace, + pc_Connect, + pc_Next, + pc_Signal, + pc_Join, + pc_Verify, + pc_Active, + pc_Maint +} PCMState; + +typedef enum { + pcw_none, + pcw_mm, + pcw_otherincompatible, + pcw_pathnotavailable +} PC_Withhold; + +typedef enum { + pmd_multimode, + pmd_single_mode1, + pmd_single_mode2, + pmd_sonet, + pmd_low_cost_fiber, + pmd_twisted_pair, + pmd_unknown, + pmd_unspecified +} PMDClass; + diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index efc1787e7543..da9af49b0137 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -279,7 +279,7 @@ static struct file_operations slm_fops = { slm_read, /* read - status reading */ slm_write, /* write - printing data write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ slm_ioctl, /* ioctl */ NULL, /* mmap */ slm_open, /* open */ diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 8271ff9bd74d..1a6b8109a00d 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3704,7 +3704,7 @@ static struct file_operations floppy_fops = { floppy_read, /* read - general block-dev read */ floppy_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ fd_ioctl, /* ioctl */ NULL, /* mmap */ floppy_open, /* open */ @@ -4128,6 +4128,7 @@ static void floppy_release_irq_and_dma(void) extern char *get_options(char *str, int *ints); char *floppy=NULL; +MODULE_PARM(floppy, "s"); static void parse_floppy_cfg_string(char *cfg) { diff --git a/drivers/block/hd.c b/drivers/block/hd.c index d50aa60786b7..7ffcadee7ebe 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -784,7 +784,7 @@ static struct file_operations hd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ hd_ioctl, /* ioctl */ NULL, /* mmap */ hd_open, /* open */ diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index 3db9f3007111..908bd6ef9fd6 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -3644,7 +3644,7 @@ static struct file_operations idetape_fops = { idetape_chrdev_read, /* read */ idetape_chrdev_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ idetape_chrdev_ioctl, /* ioctl */ NULL, /* mmap */ idetape_chrdev_open, /* open */ diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 99065347b5b0..be8d666f1416 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -2818,7 +2818,7 @@ struct file_operations ide_fops[] = {{ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ ide_ioctl, /* ioctl */ NULL, /* mmap */ ide_open, /* open */ diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 49556fb637d1..b3cac7ec2839 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -513,7 +513,7 @@ static struct file_operations lo_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ lo_ioctl, /* ioctl */ NULL, /* mmap */ lo_open, /* open */ diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 6d8803442c53..950392f778fa 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -152,7 +152,7 @@ static struct file_operations ps2esdi_fops = block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ ps2esdi_ioctl, /* ioctl */ NULL, /* mmap */ ps2esdi_open, /* open */ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 3b984deaef70..16d701cfa153 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -212,7 +212,7 @@ static struct file_operations initrd_fops = { initrd_read, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ @@ -254,7 +254,7 @@ static struct file_operations fd_fops = { block_read, /* read - block dev read */ block_write, /* write - block dev write */ NULL, /* readdir - not here! */ - NULL, /* select */ + NULL, /* poll */ rd_ioctl, /* ioctl */ NULL, /* mmap */ rd_open, /* open */ diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 3aab0f871675..759da91ea6c8 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -112,7 +112,7 @@ static struct file_operations xd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ xd_ioctl, /* ioctl */ NULL, /* mmap */ xd_open, /* open */ diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index a718683ff0ca..9e1dca8db197 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -274,7 +274,7 @@ static struct file_operations z2_fops = block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ z2_open, /* open */ diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index c13bf5a46071..f6e521a495c3 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -1,5 +1,5 @@ #define AZT_VERSION "2.50" -/* $Id: aztcd.c,v 2.50 1996/05/17 16:19:03 root Exp root $ +/* $Id: aztcd.c,v 1.16 1997/01/26 07:12:53 davem Exp $ linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver Copyright (C) 1994,95,96 Werner Zimmermann(zimmerma@rz.fht-esslingen.de) @@ -341,7 +341,7 @@ static struct file_operations azt_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ aztcd_ioctl, /* ioctl */ NULL, /* mmap */ aztcd_open, /* open */ diff --git a/drivers/cdrom/bpcd.c b/drivers/cdrom/bpcd.c index eddfbe17ca00..49225ec0c533 100644 --- a/drivers/cdrom/bpcd.c +++ b/drivers/cdrom/bpcd.c @@ -184,7 +184,7 @@ static struct file_operations bp_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ bp_ioctl, /* ioctl */ NULL, /* mmap */ bp_open, /* open */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 9d5149655dee..927ac9990445 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -38,7 +38,7 @@ struct file_operations cdrom_fops = block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ cdrom_ioctl, /* ioctl */ NULL, /* mmap */ cdrom_open, /* open */ diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 74877302452f..eb67039dd33f 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -2885,7 +2885,7 @@ static struct file_operations scd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ scd_ioctl, /* ioctl */ NULL, /* mmap */ scd_open, /* open */ diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index d1f5b894f164..73a01a120245 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -155,7 +155,7 @@ static struct file_operations gscd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ gscd_ioctl, /* ioctl */ NULL, /* mmap */ gscd_open, /* open */ diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index 89638812a4a7..63ea68ebfd40 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -1158,7 +1158,7 @@ static struct file_operations mcd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ mcd_ioctl, /* ioctl */ NULL, /* mmap */ mcd_open, /* open */ diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 01784d4b7e23..0c54e4a66c3c 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -49,7 +49,7 @@ #if RCS static const char *mcdx_c_version - = "$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $"; + = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $"; #endif #include @@ -280,7 +280,7 @@ static struct file_operations mcdx_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* no readdir */ - NULL, /* no select */ + NULL, /* no poll */ mcdx_ioctl, /* ioctl() */ NULL, /* no mmap */ mcdx_open, /* open() */ @@ -1170,7 +1170,7 @@ int mcdx_init(void) xwarn("Version 2.14(hs) \n"); #endif - xwarn("$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $\n"); + xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); /* zero the pointer array */ for (drive = 0; drive < MCDX_NDRIVES; drive++) diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 4fe117103783..8c7761408101 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -1,5 +1,5 @@ /* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver - $Id: optcd.c,v 1.29 1996/02/22 22:38:30 root Exp $ + $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $ Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) @@ -2002,7 +2002,7 @@ static struct file_operations opt_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ opt_ioctl, /* ioctl */ NULL, /* mmap */ opt_open, /* open */ diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index be850e12bad7..e2a0bb1f838f 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -5247,7 +5247,7 @@ static struct file_operations sbpcd_fops = block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ sbpcd_ioctl, /* ioctl */ NULL, /* mmap */ sbpcd_open, /* open */ diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 2bc62badb544..88ff3e56ec27 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -1420,7 +1420,7 @@ static struct file_operations sjcd_fops = { block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ sjcd_ioctl, /* ioctl */ NULL, /* mmap */ sjcd_open, /* open */ diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index f5ea541c2318..feb1fe3bb09e 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -1469,7 +1469,7 @@ static struct file_operations cdu_fops = block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ - NULL, /* select */ + NULL, /* poll */ cdu_ioctl, /* ioctl */ NULL, /* mmap */ cdu_open, /* open */ diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c index f893825a6b91..f2addb144832 100644 --- a/drivers/char/atarimouse.c +++ b/drivers/char/atarimouse.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -130,13 +131,11 @@ static long read_mouse(struct inode *inode, struct file *file, return r; } -static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) +static unsigned int mouse_poll(struct file *file, poll_table *wait) { - if (sel_type == SEL_IN) { - if (mouse.ready) - return 1; - select_wait(&mouse.wait, wait); - } + poll_wait(&mouse.wait, wait); + if (mouse.ready) + return POLLIN | POLLRDNORM; return 0; } @@ -145,7 +144,7 @@ struct file_operations atari_mouse_fops = { read_mouse, write_mouse, NULL, /* mouse_readdir */ - mouse_select, + mouse_poll, NULL, /* mouse_ioctl */ NULL, /* mouse_mmap */ open_mouse, diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index 53e74f5884a1..b75f64af59a2 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -172,13 +173,11 @@ static long read_mouse(struct inode * inode, struct file * file, return i; /* i data bytes returned */ } -static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +static unsigned int mouse_poll(struct file *file, poll_table * wait) { - if (sel_type != SEL_IN) - return 0; + poll_wait(&mouse.wait, wait); if (mouse.ready) - return 1; - select_wait(&mouse.wait,wait); + return POLLIN | POLLRDNORM; return 0; } @@ -187,7 +186,7 @@ struct file_operations atixl_busmouse_fops = { read_mouse, write_mouse, NULL, /* mouse_readdir */ - mouse_select, /* mouse_select */ + mouse_poll, /* mouse_poll */ NULL, /* mouse_ioctl */ NULL, /* mouse_mmap */ open_mouse, diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 91bcbb89243d..2ebba4b59aac 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -216,15 +217,13 @@ static long read_mouse(struct inode * inode, struct file * file, } /* - * select for mouse input + * poll for mouse input */ -static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +static unsigned int mouse_poll(struct file *file, poll_table * wait) { - if (sel_type == SEL_IN) { - if (mouse.ready) - return 1; - select_wait(&mouse.wait, wait); - } + poll_wait(&mouse.wait, wait); + if (mouse.ready) + return POLLIN | POLLRDNORM; return 0; } @@ -233,7 +232,7 @@ struct file_operations bus_mouse_fops = { read_mouse, write_mouse, NULL, /* mouse_readdir */ - mouse_select, /* mouse_select */ + mouse_poll, /* mouse_poll */ NULL, /* mouse_ioctl */ NULL, /* mouse_mmap */ open_mouse, diff --git a/drivers/char/console.c b/drivers/char/console.c index b9e72dba7f73..8d1afdcccddc 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -118,6 +118,10 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#ifdef __sparc__ +int serial_console; +#endif + struct tty_driver console_driver; static int console_refcount; static struct tty_struct *console_table[MAX_NR_CONSOLES]; @@ -151,8 +155,10 @@ extern void compute_shiftstate(void); extern void reset_palette(int currcons); extern void set_palette(void); extern unsigned long con_type_init(unsigned long, const char **); +extern void con_type_init_finish(void); extern int set_get_cmap(unsigned char *, int); extern int set_get_font(unsigned char *, int, int); +extern void rs_cons_hook(int chip, int out, int channel); /* Description of the hardware situation */ unsigned char video_type; /* Type of display being used */ @@ -640,40 +646,30 @@ void scrup(int currcons, unsigned int t, unsigned int b) } else { unsigned short * d = (unsigned short *) (origin+video_size_row*t); unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1)); - unsigned int count = (b-t-1) * video_num_columns; - while (count) { - count--; - scr_writew(scr_readw(s++), d++); - } - count = video_num_columns; - while (count) { - count--; - scr_writew(video_erase_char, d++); - } + memcpyw(d, s, (b-t-1) * video_size_row); + memsetw(d + (b-t-1) * video_num_columns, video_erase_char, video_size_row); } } void scrdown(int currcons, unsigned int t, unsigned int b) { - unsigned short *d, *s; + unsigned short *s; unsigned int count; if (b > video_num_lines || t >= b) return; - d = (unsigned short *) (origin+video_size_row*b); - s = (unsigned short *) (origin+video_size_row*(b-1)); - count = (b-t-1)*video_num_columns; - while (count) { - count--; - scr_writew(scr_readw(--s), --d); - } - count = video_num_columns; - while (count) { - count--; - scr_writew(video_erase_char, --d); + s = (unsigned short *) (origin+video_size_row*(b-2)); + if (b >= t + 1) { + count = b - t - 1; + while (count) { + count--; + memcpyw(s + video_num_columns, s, video_size_row); + s -= video_num_columns; + } } + memsetw(s + video_num_columns, video_erase_char, video_size_row); has_scrolled = 1; } @@ -746,10 +742,7 @@ static void csi_J(int currcons, int vpar) default: return; } - while (count) { - count--; - scr_writew(video_erase_char, start++); - } + memsetw(start, video_erase_char, 2*count); need_wrap = 0; } @@ -774,28 +767,17 @@ static void csi_K(int currcons, int vpar) default: return; } - while (count) { - count--; - scr_writew(video_erase_char, start++); - } + memsetw(start, video_erase_char, 2 * count); need_wrap = 0; } static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ { /* not vt100? */ - unsigned long count; - unsigned short * start; - if (!vpar) vpar++; - start = (unsigned short *) pos; - count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; - - while (count) { - count--; - scr_writew(video_erase_char, start++); - } + memsetw((unsigned short *) pos, video_erase_char, + (vpar > video_num_columns-x) ? 2 * (video_num_columns-x) : 2 * vpar); need_wrap = 0; } @@ -1348,8 +1330,10 @@ static void con_stop(struct tty_struct *tty) console_num = MINOR(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; +#if !CONFIG_AP1000 set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds(); +#endif } /* @@ -1363,8 +1347,10 @@ static void con_start(struct tty_struct *tty) console_num = MINOR(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; +#if !CONFIG_AP1000 clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds(); +#endif } static void con_flush_chars(struct tty_struct *tty) @@ -1384,6 +1370,11 @@ static int do_con_write(struct tty_struct * tty, int from_user, unsigned int currcons; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; +#if CONFIG_AP1000 + ap_write(1,buf,count); + return(count); +#endif + currcons = vt->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ @@ -1846,10 +1837,10 @@ static int con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { int retval; - + retval = do_con_write(tty, from_user, buf, count); con_flush_chars(tty); - + return retval; } @@ -1891,6 +1882,10 @@ void console_print(const char * b) unsigned char c; static int printing = 0; +#if CONFIG_AP1000 + prom_printf(b); + return; +#endif if (!printable || printing) return; /* console not yet initialized */ printing = 1; @@ -2026,6 +2021,19 @@ unsigned long con_init(unsigned long kmem_start) int orig_x = ORIG_X; int orig_y = ORIG_Y; +#ifdef __sparc__ + if (serial_console) { + fg_console = 0; + +#if CONFIG_SUN_SERIAL + rs_cons_hook(0, 0, serial_console); + rs_cons_hook(0, 1, serial_console); +#endif + + return kmem_start; + } +#endif + memset(&console_driver, 0, sizeof(struct tty_driver)); console_driver.magic = TTY_DRIVER_MAGIC; console_driver.name = "tty"; @@ -2056,6 +2064,9 @@ unsigned long con_init(unsigned long kmem_start) if (tty_register_driver(&console_driver)) panic("Couldn't register console driver\n"); +#if CONFIG_AP1000 + return(kmem_start); +#endif con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS); timer_table[BLANK_TIMER].fn = blank_screen; @@ -2110,7 +2121,8 @@ unsigned long con_init(unsigned long kmem_start) printable = 1; if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC - || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC ) + || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC + || video_type == VIDEO_TYPE_SUN ) { default_font_height = video_font_height = ORIG_VIDEO_POINTS; /* This may be suboptimal but is a safe bet - go with it */ @@ -2130,6 +2142,8 @@ unsigned long con_init(unsigned long kmem_start) MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); + con_type_init_finish(); + /* * can't register TGA yet, because PCI bus probe has *not* taken * place before con_init() gets called. Trigger the real TGA hw diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c index fa8a0bd5c15c..83700e6d7d65 100644 --- a/drivers/char/fbmem.c +++ b/drivers/char/fbmem.c @@ -263,7 +263,7 @@ static struct file_operations fb_fops = { fb_read, /* read */ fb_write, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ fb_ioctl, /* ioctl */ fb_mmap, /* mmap */ fb_open, /* open */ diff --git a/drivers/char/ftape/kernel-interface.c b/drivers/char/ftape/kernel-interface.c index 5fba55bd2207..94eb0665043d 100644 --- a/drivers/char/ftape/kernel-interface.c +++ b/drivers/char/ftape/kernel-interface.c @@ -72,7 +72,7 @@ static struct file_operations ftape_cdev = ftape_read, /* read */ ftape_write, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ ftape_ioctl, /* ioctl */ NULL, /* mmap */ ftape_open, /* open */ @@ -129,16 +129,16 @@ int ftape_init(void) printk(KERN_INFO "ftape-2.08 960314\n" KERN_INFO " (c) 1993-1995 Bas Laarhoven (bas@vimec.nl)\n" KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n" - KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n" - KERN_INFO " Compiled for kernel version %s" + KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n" + KERN_INFO " Compiled for kernel version " UTS_RELEASE #ifdef MODVERSIONS " with versioned symbols" #endif - "\n", kernel_version); + "\n"); #else /* !MODULE */ /* print a short no-nonsense boot message */ printk("ftape-2.08 960314 for Linux 1.3.70\n"); -#endif /* MODULE */ +#endif /* MODULE */ TRACE(3, "installing QIC-117 ftape driver..."); if (register_chrdev(QIC117_TAPE_MAJOR, "ft", &ftape_cdev)) { TRACE(1, "register_chrdev failed"); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 281226f69dce..0b647708377e 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -527,7 +527,7 @@ static struct file_operations lp_fops = { NULL, /* lp_read */ lp_write, NULL, /* lp_readdir */ - NULL, /* lp_select */ + NULL, /* lp_poll */ lp_ioctl, NULL, /* lp_mmap */ lp_open, diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c index 3f80f30c95e7..cc5b2f9146de 100644 --- a/drivers/char/lp_m68k.c +++ b/drivers/char/lp_m68k.c @@ -450,7 +450,7 @@ static struct file_operations lp_fops = { NULL, /* lp_read */ lp_write, NULL, /* lp_readdir */ - NULL, /* lp_select */ + NULL, /* lp_poll */ lp_ioctl, NULL, /* lp_mmap */ lp_open, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 036e78d124c0..daf675a970f0 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -119,7 +119,7 @@ static struct file_operations misc_fops = { NULL, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ misc_open, diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index 6d5819b02179..d6bffedaac36 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -155,13 +156,11 @@ static long read_mouse(struct inode * inode, struct file * file, return i; } -static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +static unsigned int mouse_poll(struct file *file, poll_table * wait) { - if (sel_type != SEL_IN) - return 0; + poll_wait(&mouse.wait, wait); if (mouse.ready) - return 1; - select_wait(&mouse.wait,wait); + return POLLIN | POLLRDNORM; return 0; } @@ -170,7 +169,7 @@ struct file_operations ms_bus_mouse_fops = { read_mouse, write_mouse, NULL, /* mouse_readdir */ - mouse_select, /* mouse_select */ + mouse_poll, /* mouse_poll */ NULL, /* mouse_ioctl */ NULL, /* mouse_mmap */ open_mouse, diff --git a/drivers/char/selection.h b/drivers/char/selection.h index 95c1f21ec384..8cf5337fda61 100644 --- a/drivers/char/selection.h +++ b/drivers/char/selection.h @@ -62,7 +62,7 @@ extern void putconsxy(int currcons, char *p); #include -#ifdef CONFIG_TGA_CONSOLE +#if defined(CONFIG_TGA_CONSOLE) extern int tga_blitc(unsigned int, unsigned long); extern unsigned long video_mem_term; @@ -73,10 +73,6 @@ extern unsigned long video_mem_term; * TGA is *not* a character/attribute cell device; font bitmaps must be rendered * to the screen pixels. * - * The "unsigned short * addr" is *ALWAYS* a kernel virtual address, either - * of the VC's backing store, or the "shadow screen" memory where the screen - * contents are kept, as the TGA frame buffer is *not* char/attr cells. - * * We must test for an Alpha kernel virtual address that falls within * the "shadow screen" memory. This condition indicates we really want * to write to the screen, so, we do... :-) @@ -86,10 +82,10 @@ extern unsigned long video_mem_term; */ static inline void scr_writew(unsigned short val, unsigned short * addr) { - /* - * always deposit the char/attr, then see if it was to "screen" mem. + /* + * always deposit the char/attr, then see if it was to "screen" mem. * if so, then render the char/attr onto the real screen. - */ + */ *addr = val; if ((unsigned long)addr < video_mem_term && (unsigned long)addr >= video_mem_base) { @@ -101,7 +97,37 @@ static inline unsigned short scr_readw(unsigned short * addr) { return *addr; } -#else /* CONFIG_TGA_CONSOLE */ + +#elif defined(CONFIG_SUN_CONSOLE) +#include "vt_kern.h" +#include +extern int sun_blitc(unsigned int, unsigned long); +extern void memsetw(void * s, unsigned short c, unsigned int count); +extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count); +extern unsigned long video_mem_term; + +/* Basically the same as the TGA stuff. */ +static inline void scr_writew(unsigned short val, unsigned short * addr) +{ + /* + * always deposit the char/attr, then see if it was to "screen" mem. + * if so, then render the char/attr onto the real screen. + */ + if (*addr != val) { + *addr = val; + if ((unsigned long)addr < video_mem_term && + (unsigned long)addr >= video_mem_base && + vt_cons [fg_console]->vc_mode == KD_TEXT) + sun_blitc(val, (unsigned long) addr); + } +} + +static inline unsigned short scr_readw(unsigned short * addr) +{ + return *addr; +} + +#else /* CONFIG_TGA_CONSOLE || CONFIG_SUN_CONSOLE */ /* * normal VGA console access @@ -147,6 +173,7 @@ static inline unsigned short scr_readw(unsigned short * addr) #endif /* CONFIG_TGA_CONSOLE */ +#ifndef CONFIG_SUN_CONSOLE static inline void memsetw(void * s, unsigned short c, unsigned int count) { unsigned short * addr = (unsigned short *) s; @@ -167,3 +194,4 @@ static inline void memcpyw(unsigned short *to, unsigned short *from, scr_writew(scr_readw(from++), to++); } } +#endif /* CONFIG_SUN_CONSOLE */ diff --git a/drivers/char/tga.c b/drivers/char/tga.c index ca2706dba413..2f8d70b3b1c1 100644 --- a/drivers/char/tga.c +++ b/drivers/char/tga.c @@ -323,6 +323,11 @@ con_type_init(unsigned long kmem_start, const char **display_desc) return kmem_start; } +void +con_type_init_finish(void) +{ +} + /* * NOTE: get_scrmem() and set_scrmem() are here only because * the VGA version of set_scrmem() has some direct VGA references. diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 1d7e97ec9a52..add8bb31c71d 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -1,4 +1,4 @@ -/* $Id: tpqic02.c,v 0.7.1.5 1996/12/14 22:58:52 root Exp root $ +/* $Id: tpqic02.c,v 1.10 1997/01/26 07:13:20 davem Exp $ * * Driver for tape drive support for Linux-i386 * @@ -133,8 +133,8 @@ static volatile struct mtget ioctl_status; /* current generic status */ static volatile struct tpstatus tperror; /* last drive status */ -static char rcs_revision[] = "$Revision: 0.7.1.5 $"; -static char rcs_date[] = "$Date: 1996/12/14 22:58:52 $"; +static char rcs_revision[] = "$Revision: 1.10 $"; +static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $"; /* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) @@ -2747,7 +2747,7 @@ static struct file_operations qic02_tape_fops = { qic02_tape_read, /* read */ qic02_tape_write, /* write */ NULL, /* readdir not allowed */ - NULL, /* select ??? */ + NULL, /* poll ??? */ qic02_tape_ioctl, /* ioctl */ NULL, /* mmap not allowed */ qic02_tape_open, /* open */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 59d2c27cb703..d13738a34e7d 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -607,6 +607,25 @@ void complete_change_console(unsigned int new_console) if (vt_cons[new_console]->vc_mode == KD_TEXT) set_palette() ; +#ifdef CONFIG_SUN_CONSOLE + if (old_vc_mode != vt_cons[new_console]->vc_mode) + { + extern void set_cursor(int currcons); + extern void hide_cursor(void); + + if (old_vc_mode == KD_GRAPHICS) + { + extern void sun_clear_margin(void); + extern void render_screen(void); + + sun_clear_margin(); + render_screen(); + set_cursor(fg_console); + } + else + hide_cursor(); + } +#endif /* * Wake anyone waiting for their VT to activate */ @@ -1922,7 +1941,9 @@ int tty_init(void) if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/console driver\n"); +#if !CONFIG_NO_KEYBOARD kbd_init(); +#endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ espserial_init(); #endif diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 705afe0af293..34b579e762ba 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -98,7 +98,7 @@ vcs_read(struct inode *inode, struct file *file, char *buf, unsigned long count) unsigned int currcons = MINOR(inode->i_rdev); int viewed, attr, size, read; char *buf0; - unsigned short *org; + unsigned short *org = NULL; attr = (currcons & 128); currcons = (currcons & 127); @@ -159,7 +159,7 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, unsigned long unsigned int currcons = MINOR(inode->i_rdev); int viewed, attr, size, written; const char *buf0; - unsigned short *org; + unsigned short *org = NULL; attr = (currcons & 128); currcons = (currcons & 127); diff --git a/drivers/char/vga.c b/drivers/char/vga.c index 857979cf3ebb..9202f83898f9 100644 --- a/drivers/char/vga.c +++ b/drivers/char/vga.c @@ -247,6 +247,11 @@ con_type_init(unsigned long kmem_start, const char **display_desc) return kmem_start; } +void +con_type_init_finish(void) +{ +} + void get_scrmem(int currcons) { diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1fc0a81b3c46..5b49791a4246 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -1111,10 +1111,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, get_user(list, &ud->entries); i = verify_area(VERIFY_READ, (void *) list, ct*sizeof(struct unipair)); + if(!i) + return con_set_unimap(ct, list); } - if (i) - return i; - return con_set_unimap(ct, list); + return i; } case GIO_UNIMAP: @@ -1130,10 +1130,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (ct) i = verify_area(VERIFY_WRITE, (void *) list, ct*sizeof(struct unipair)); + if(!i) + return con_get_unimap(ct, &(ud->entry_ct), list); } - if (i) - return i; - return con_get_unimap(ct, &(ud->entry_ct), list); + return i; } case VT_LOCKSWITCH: if (!suser()) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4411ba789d02..6f0bcff36d26 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -255,14 +255,6 @@ else endif endif -ifeq ($(CONFIG_DE620),y) -L_OBJS += de620.o -else - ifeq ($(CONFIG_DE620),m) - M_OBJS += de620.o - endif -endif - ifeq ($(CONFIG_AT1500),y) L_OBJS += lance.o endif @@ -280,6 +272,10 @@ endif ifeq ($(CONFIG_SUNLANCE),y) L_OBJS += sunlance.o +else + ifeq ($(CONFIG_SUNLANCE),m) + M_OBJS += sunlance.o + endif endif ifeq ($(CONFIG_HAPPYMEAL),y) diff --git a/drivers/net/README.multicast b/drivers/net/README.multicast index 14801555994f..232ba90167fd 100644 --- a/drivers/net/README.multicast +++ b/drivers/net/README.multicast @@ -44,7 +44,7 @@ ni65 YES YES YES Software(#) seeq NO NO NO N/A sk_g16 NO NO YES N/A smc-ultra YES YES YES Hardware -sunlance YES YES YES Software(#) +sunlance YES YES YES Hardware tulip YES YES YES Hardware wavelan YES PROMISC YES Hardware wd YES YES YES Hardware diff --git a/drivers/net/Space.c b/drivers/net/Space.c index c6222f45afd9..ff853e8d3002 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -277,24 +277,31 @@ static struct device atp_dev = { #ifndef ETH0_IRQ # define ETH0_IRQ 0 #endif + +#ifndef __sparc__ +#define ETH_NOPROBE_ADDR 0xffe0 +#else +#define ETH_NOPROBE_ADDR 0 +#endif + /* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20), which means "don't probe". These entries exist to only to provide empty slots which may be enabled at boot-time. */ static struct device eth7_dev = { - "eth7", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; + "eth7", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; static struct device eth6_dev = { - "eth6", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð7_dev, ethif_probe }; + "eth6", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð7_dev, ethif_probe }; static struct device eth5_dev = { - "eth5", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð6_dev, ethif_probe }; + "eth5", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð6_dev, ethif_probe }; static struct device eth4_dev = { - "eth4", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð5_dev, ethif_probe }; + "eth4", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð5_dev, ethif_probe }; static struct device eth3_dev = { - "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð4_dev, ethif_probe }; + "eth3", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð4_dev, ethif_probe }; static struct device eth2_dev = { - "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe }; + "eth2", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe }; static struct device eth1_dev = { - "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe }; + "eth1", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe }; static struct device eth0_dev = { "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_probe }; @@ -446,19 +453,20 @@ static struct device tr0_dev = { #endif -#ifdef CONFIG_AP1000 +#ifdef CONFIG_APFDDI extern int apfddi_init(struct device *dev); static struct device fddi_dev = { "fddi", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, apfddi_init }; # undef NEXT_DEV # define NEXT_DEV (&fddi_dev) +#endif +#ifdef CONFIG_APBIF extern int bif_init(struct device *dev); static struct device bif_dev = { "bif", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init }; # undef NEXT_DEV # define NEXT_DEV (&bif_dev) - #endif extern int loopback_init(struct device *dev); diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 3f21195e6447..9c30bf815043 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -51,7 +51,7 @@ #define PPP_MAX_DEV 256 #endif -/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $ +/* $Id: ppp.c,v 1.27 1997/01/26 07:13:29 davem Exp $ * Added dynamic allocation of channels to eliminate * compiled-in limits on the number of channels. * @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -195,8 +196,7 @@ static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *, unsigned int); static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long); -static int ppp_tty_select (struct tty_struct *tty, struct inode *inode, - struct file *filp, int sel_type, select_table * wait); +static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait); static int ppp_tty_open (struct tty_struct *); static void ppp_tty_close (struct tty_struct *); static int ppp_tty_room (struct tty_struct *tty); @@ -365,7 +365,7 @@ ppp_first_time (void) ppp_ldisc.read = ppp_tty_read; ppp_ldisc.write = ppp_tty_write; ppp_ldisc.ioctl = ppp_tty_ioctl; - ppp_ldisc.select = ppp_tty_select; + ppp_ldisc.poll = ppp_tty_poll; ppp_ldisc.receive_room = ppp_tty_room; ppp_ldisc.receive_buf = ppp_tty_receive; ppp_ldisc.write_wakeup = ppp_tty_wakeup; @@ -680,7 +680,7 @@ ppp_release (struct ppp *ppp) ppp_ccp_closed (ppp); - /* Ensure that the pppd process is not hanging on select() */ + /* Ensure that the pppd process is not hanging on poll() */ wake_up_interruptible (&ppp->read_wait); wake_up_interruptible (&ppp->write_wait); @@ -2165,13 +2165,12 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) nb = CCP_MAX_OPTION_LENGTH; error = verify_area (VERIFY_READ, ptr, nb); + if(!error) + copy_from_user (ccp_option, ptr, nb); } - if (error != 0) return error; - copy_from_user (ccp_option, ptr, nb); - if (ccp_option[1] < 2) /* preliminary check on the length byte */ return (-EINVAL); @@ -2581,65 +2580,35 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, /* * TTY callback. * - * Process the select() statement for the PPP device. + * Process the poll() statement for the PPP device. */ -static int -ppp_tty_select (struct tty_struct *tty, struct inode *inode, - struct file *filp, int sel_type, select_table * wait) +static unsigned int +ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait) { struct ppp *ppp = tty2ppp (tty); - int result = 1; -/* - * Verify the status of the PPP device. - */ - if (!ppp) - return -EBADF; + unsigned int mask = 0; - if (ppp->magic != PPP_MAGIC) - return -EBADF; + if(ppp && ppp->magic == PPP_MAGIC) { + CHECK_PPP (0); - CHECK_PPP (0); -/* - * Branch on the type of select mode. A read request must lock the user - * buffer area. - */ - switch (sel_type) { - case SEL_IN: - if (set_bit (0, &ppp->ubuf->locked) == 0) { - /* Test for the presence of data in the queue */ - if (ppp->ubuf->head != ppp->ubuf->tail) { - clear_bit (0, &ppp->ubuf->locked); - break; - } - clear_bit (0, &ppp->ubuf->locked); - } /* fall through */ -/* - * Exceptions or read errors. - */ - case SEL_EX: - /* Is this a pty link and the remote disconnected? */ - if (tty->flags & (1 << TTY_OTHER_CLOSED)) - break; - - /* Is this a local link and the modem disconnected? */ - if (tty_hung_up_p (filp)) - break; + poll_wait(&ppp->read_wait, wait); + poll_wait(&ppp->write_wait, wait); - select_wait (&ppp->read_wait, wait); - result = 0; - break; -/* - * Write mode. A write is allowed if there is no current transmission. - */ - case SEL_OUT: - if (ppp->tbuf->locked != 0) { - select_wait (&ppp->write_wait, wait); - result = 0; + /* Must lock the user buffer area while checking. */ + if(set_bit(0, &ppp->ubuf->locked) == 0) { + if(ppp->ubuf->head != ppp->ubuf->tail) + mask |= POLLIN | POLLRDNORM; + clear_bit(0, &ppp->ubuf->locked); } - break; - } - return result; + if(tty->flags & (1 << TTY_OTHER_CLOSED)) + mask |= POLLHUP; + if(tty_hung_up_p(filp)) + mask |= POLLHUP; + if(ppp->tbuf->locked == 0) + mask |= POLLOUT | POLLWRNORM; + } + return mask; } /************************************************************* diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 4a1f7deb3f8f..9910cfebf0bc 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -111,7 +111,7 @@ static void sl_outfill(unsigned long sls); static inline struct slip * sl_alloc(void) { - slip_ctrl_t *slp; + slip_ctrl_t *slp = NULL; int i; if (slip_ctrls == NULL) return NULL; /* Master array missing ! */ @@ -1123,7 +1123,7 @@ int slip_init_ctrl_dev(struct device *dummy) sl_ldisc.write = NULL; sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long)) slip_ioctl; - sl_ldisc.select = NULL; + sl_ldisc.poll = NULL; sl_ldisc.receive_buf = slip_receive_buf; sl_ldisc.receive_room = slip_receive_room; sl_ldisc.write_wakeup = slip_write_wakeup; diff --git a/drivers/net/strip.c b/drivers/net/strip.c index 47517b1e15fb..67ee76b5724f 100644 --- a/drivers/net/strip.c +++ b/drivers/net/strip.c @@ -2752,7 +2752,7 @@ int strip_init_ctrl_dev(struct device *dummy) strip_ldisc.read = NULL; strip_ldisc.write = NULL; strip_ldisc.ioctl = strip_ioctl; - strip_ldisc.select = NULL; + strip_ldisc.poll = NULL; strip_ldisc.receive_buf = strip_receive_buf; strip_ldisc.receive_room = strip_receive_room; strip_ldisc.write_wakeup = strip_write_some_more; diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index a7e2c98eb6e2..a9e02312b813 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -346,7 +346,7 @@ struct hmeal_tcvregs { #define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ #define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ #define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -#define LPA_100BASE4 0x0100 /* Can do 100mbps 4k packets */ +#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ #define LPA_RESV 0x1c00 /* Unused... */ #define LPA_RFAULT 0x2000 /* Link partner faulted */ #define LPA_LPACK 0x4000 /* Link partner acked us */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 824ca404995b..200568683388 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,60 +1,70 @@ -/* lance.c: Linux/Sparc/Lance driver */ -/* - Written 1995, 1996 by Miguel de Icaza - Sources: - The Linux depca driver - The Linux lance driver. - The Linux skeleton driver. - The NetBSD Sparc/Lance driver. - Theo de Raadt (deraadt@openbsd.org) - NCR92C990 Lan Controller manual - -1.4: - Added support to run with a ledma on the Sun4m -1.5: - Added multiple card detection. - - 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost - (ecd@skynet.be) - - 5/15/96: auto carrier detection on sun4m by Eddie C. Dost - (ecd@skynet.be) - - 5/17/96: lebuffer on scsi/ether cards now work David S. Miller - (davem@caip.rutgers.edu) - - 5/29/96: override option 'tpe-link-test?', if it is 'false', as - this disables auto carrier detection on sun4m. Eddie C. Dost - (ecd@skynet.be) -1.7: - 6/26/96: Bug fix for multiple ledmas, miguel. -1.8: - Stole multicast code from depca.c, fixed lance_tx. -1.9: - Fixed the multicast code (Pedro Roque) - - 8/28/96: Send fake packet in lance_open() if auto_select is true, - so we can detect the carrier loss condition in time. - Eddie C. Dost (ecd@skynet.be) - - 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an - MNA trap during chksum_partial_copy(). (ecd@skynet.be) - - 11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be) - - 12/22/96: Don't loop forever in lance_rx() on incomplete packets. - This was the sun4c killer. Shit, stupid bug. - (ecd@skynet.be) -*/ +/* $Id: sunlance.c,v 1.52 1997/01/25 23:29:56 ecd Exp $ + * lance.c: Linux/Sparc/Lance driver + * + * Written 1995, 1996 by Miguel de Icaza + * Sources: + * The Linux depca driver + * The Linux lance driver. + * The Linux skeleton driver. + * The NetBSD Sparc/Lance driver. + * Theo de Raadt (deraadt@openbsd.org) + * NCR92C990 Lan Controller manual + * + * 1.4: + * Added support to run with a ledma on the Sun4m + * + * 1.5: + * Added multiple card detection. + * + * 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost + * (ecd@skynet.be) + * + * 5/15/96: auto carrier detection on sun4m by Eddie C. Dost + * (ecd@skynet.be) + * + * 5/17/96: lebuffer on scsi/ether cards now work David S. Miller + * (davem@caip.rutgers.edu) + * + * 5/29/96: override option 'tpe-link-test?', if it is 'false', as + * this disables auto carrier detection on sun4m. Eddie C. Dost + * (ecd@skynet.be) + * + * 1.7: + * 6/26/96: Bug fix for multiple ledmas, miguel. + * + * 1.8: + * Stole multicast code from depca.c, fixed lance_tx. + * + * 1.9: + * 8/21/96: Fixed the multicast code (Pedro Roque) + * + * 8/28/96: Send fake packet in lance_open() if auto_select is true, + * so we can detect the carrier loss condition in time. + * Eddie C. Dost (ecd@skynet.be) + * + * 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an + * MNA trap during chksum_partial_copy(). (ecd@skynet.be) + * + * 11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be) + * + * 12/22/96: Don't loop forever in lance_rx() on incomplete packets. + * This was the sun4c killer. Shit, stupid bug. + * (ecd@skynet.be) + * + * 1.10: + * 1/26/97: Modularize driver. (ecd@skynet.be) + */ #undef DEBUG_DRIVER static char *version = - "sunlance.c:v1.9 21/Aug/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + "sunlance.c:v1.10 26/Jan/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; static char *lancestr = "LANCE"; static char *lancedma = "LANCE DMA"; +#include + #include #include #include @@ -211,12 +221,18 @@ struct lance_private { int rx_old, tx_old; struct enet_statistics stats; - struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ + struct Linux_SBus_DMA *ledma; /* If set this points to ledma */ + /* and arch = sun4m */ + + int tpe; /* cable-selection is TPE */ + int auto_select; /* cable-selection by carrier */ + int burst_sizes; /* ledma SBus burst sizes */ - int tpe; /* cable-selection is TPE */ - int auto_select; /* cable-selection by carrier */ - int burst_sizes; /* ledma SBus burst sizes */ - unsigned short busmaster_regval, pio_buffer; + unsigned short busmaster_regval; + unsigned short pio_buffer; + + struct device *dev; /* Backpointer */ + struct lance_private *next_module; }; #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ @@ -241,6 +257,10 @@ int sparc_lance_debug = 2; #define LANCE_ADDR(x) ((int)(x) & ~0xff000000) +#ifdef MODULE +static struct lance_private *root_lance_dev = NULL; +#endif + /* Load the CSR registers */ static void load_csrs (struct lance_private *lp) { @@ -686,6 +706,9 @@ static int lance_open (struct device *dev) flush = ll->rdp; } + if (!status) + MOD_INC_USE_COUNT; + return status; } @@ -702,7 +725,7 @@ static int lance_close (struct device *dev) ll->rdp = LE_C0_STOP; free_irq (dev->irq, (void *) dev); - + MOD_DEC_USE_COUNT; return 0; } @@ -916,11 +939,13 @@ int sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, volatile struct lance_regs *ll; if (dev == NULL) { - dev = init_etherdev (0, sizeof (struct lance_private)); + dev = init_etherdev (0, sizeof (struct lance_private) + 8); } else { - dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL); + dev->priv = kmalloc (sizeof (struct lance_private) + 8, + GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; + memset(dev->priv, 0, sizeof (struct lance_private) + 8); } if (sparc_lance_debug && version_printed++ == 0) printk (version); @@ -948,7 +973,6 @@ int sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *)(((int)dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; - memset ((char *)dev->priv, 0, sizeof (struct lance_private)); if (lebuffer){ prom_apply_sbus_ranges (lebuffer->my_bus, @@ -1045,6 +1069,7 @@ no_link_test: return ENODEV; } + lp->dev = dev; dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; @@ -1055,6 +1080,11 @@ no_link_test: dev->dma = 0; ether_setup (dev); +#ifdef MODULE + dev->ifindex = dev_new_index(); + lp->next_module = root_lance_dev; + root_lance_dev = lp; +#endif return 0; } @@ -1064,7 +1094,7 @@ find_ledma (struct linux_sbus_device *dev) { struct Linux_SBus_DMA *p; - for (p = dma_chain; p; p = p->next) + for_each_dvma(p) if (p->SBus_dev == dev) return p; return 0; @@ -1113,9 +1143,27 @@ int sparc_lance_probe (struct device *dev) return 0; } -/* - * Local variables: - * version-control: t - * kept-new-versions: 5 - * End: - */ +#ifdef MODULE + +int +init_module(void) +{ + root_lance_dev = NULL; + return sparc_lance_probe(NULL); +} + +void +cleanup_module(void) +{ + struct lance_private *lp; + + while (root_lance_dev) { + lp = root_lance_dev->next_module; + + unregister_netdev(root_lance_dev->dev); + kfree(root_lance_dev->dev); + root_lance_dev = lp; + } +} + +#endif /* MODULE */ diff --git a/drivers/sbus/audio/Config.in b/drivers/sbus/audio/Config.in new file mode 100644 index 000000000000..36c341b1ca58 --- /dev/null +++ b/drivers/sbus/audio/Config.in @@ -0,0 +1,11 @@ +# +# Configuration script for sparcaudio subsystem +# + +if [ "x$CONFIG_EXPERIMENTAL" = "xy" ]; then + + comment 'Linux/SPARC audio subsystem' + + tristate 'Audio support' CONFIG_SPARCAUDIO + dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO +fi diff --git a/drivers/sbus/audio/Makefile b/drivers/sbus/audio/Makefile new file mode 100644 index 000000000000..72156225ef6b --- /dev/null +++ b/drivers/sbus/audio/Makefile @@ -0,0 +1,36 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +# +# sbus audio drivers +# + +O_TARGET := sparcaudio.o +O_OBJS := +M_OBJS := + +ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) +M=y +O_OBJS += amd7930.o +else + ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m) + MM=y + M_OBJS += amd7930.o + endif +endif + +ifdef M +O_OBJS += audio.o +else + ifdef MM + M_OBJS += audio.o + endif +endif + +include $(TOPDIR)/Rules.make diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c new file mode 100644 index 000000000000..f771d7bb2939 --- /dev/null +++ b/drivers/sbus/audio/amd7930.c @@ -0,0 +1,372 @@ +/* + * drivers/sbus/audio/amd7930.c + * + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * + * This is the lowlevel driver for the AMD7930 audio chip found on all + * sun4c machines and some sun4m machines. + * + * XXX Add note about the fun of getting the docs. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audio.h" +#include "amd7930.h" + +/* + * Chip interface + */ +struct mapreg { + u_short mr_x[8]; + u_short mr_r[8]; + u_short mr_gx; + u_short mr_gr; + u_short mr_ger; + u_short mr_stgr; + u_short mr_ftgr; + u_short mr_atgr; + u_char mr_mmr1; + u_char mr_mmr2; +} map; + + +/* Write 16 bits of data from variable v to the data port of the audio chip */ +#define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) + +/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */ + +/* + * gx, gr & stg gains. this table must contain 256 elements with + * the 0th being "infinity" (the magic value 9008). The remaining + * elements match sun's gain curve (but with higher resolution): + * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. + */ +static const u_short gx_coeff[256] = { + 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, + 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, + 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, + 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, + 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, + 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, + 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, + 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, + 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, + 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, + 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, + 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, + 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, + 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, + 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, + 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, + 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, + 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, + 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, + 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, + 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, + 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, + 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, + 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, + 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, + 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, + 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, + 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, + 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, + 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, + 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, + 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, +}; + +/* + * second stage play gain. + */ +static const u_short ger_coeff[] = { + 0x431f, /* 5. dB */ + 0x331f, /* 5.5 dB */ + 0x40dd, /* 6. dB */ + 0x11dd, /* 6.5 dB */ + 0x440f, /* 7. dB */ + 0x411f, /* 7.5 dB */ + 0x311f, /* 8. dB */ + 0x5520, /* 8.5 dB */ + 0x10dd, /* 9. dB */ + 0x4211, /* 9.5 dB */ + 0x410f, /* 10. dB */ + 0x111f, /* 10.5 dB */ + 0x600b, /* 11. dB */ + 0x00dd, /* 11.5 dB */ + 0x4210, /* 12. dB */ + 0x110f, /* 13. dB */ + 0x7200, /* 14. dB */ + 0x2110, /* 15. dB */ + 0x2200, /* 15.9 dB */ + 0x000b, /* 16.9 dB */ + 0x000f /* 18. dB */ +#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) +}; + +#if 0 +int +amd7930_commit_settings(addr) + void *addr; +{ + register struct amd7930_softc *sc = addr; + register struct mapreg *map; + register volatile struct amd7930 *amd; + register int s, level; + + DPRINTF(("sa_commit.\n")); + + map = &sc->sc_map; + amd = sc->sc_au.au_amd; + + map->mr_gx = gx_coeff[sc->sc_rlevel]; + map->mr_stgr = gx_coeff[sc->sc_mlevel]; + + level = (sc->sc_plevel * (256 + NGER)) >> 8; + if (level >= 256) { + map->mr_ger = ger_coeff[level - 256]; + map->mr_gr = gx_coeff[255]; + } else { + map->mr_ger = ger_coeff[0]; + map->mr_gr = gx_coeff[level]; + } + + if (sc->sc_out_port == SUNAUDIO_SPEAKER) + map->mr_mmr2 |= AMD_MMR2_LS; + else + map->mr_mmr2 &= ~AMD_MMR2_LS; + + s = splaudio(); + + amd->cr = AMDR_MAP_MMR1; + amd->dr = map->mr_mmr1; + amd->cr = AMDR_MAP_GX; + WAMD16(amd, map->mr_gx); + amd->cr = AMDR_MAP_STG; + WAMD16(amd, map->mr_stgr); + amd->cr = AMDR_MAP_GR; + WAMD16(amd, map->mr_gr); + amd->cr = AMDR_MAP_GER; + WAMD16(amd, map->mr_ger); + amd->cr = AMDR_MAP_MMR2; + amd->dr = map->mr_mmr2; + + splx(s); + return(0); +} +#endif + +static int amd7930_node, amd7930_irq, amd7930_regs_size, amd7930_ints_on = 0; +static struct amd7930 *amd7930_regs = NULL; +static __u8 * ptr; +static size_t count; + +/* Enable amd7930 interrupts atomically. */ +static __inline__ void amd7930_enable_ints(void) +{ + register unsigned long flags; + + if (amd7930_ints_on) + return; + + save_and_cli(flags); + amd7930_regs->cr = AMR_INIT; + amd7930_regs->dr = AM_INIT_ACTIVE; + restore_flags(flags); + + amd7930_ints_on = 1; +} + +/* Disable amd7930 interrupts atomically. */ +static __inline__ void amd7930_disable_ints(void) +{ + register unsigned long flags; + + if (!amd7930_ints_on) + return; + + save_and_cli(flags); + amd7930_regs->cr = AMR_INIT; + amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS; + restore_flags(flags); + + amd7930_ints_on = 0; +} + + +/* Audio interrupt handler. */ +static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + __u8 dummy; + + /* Clear the interrupt. */ + dummy = amd7930_regs->ir; + + /* Send the next byte of outgoing data. */ + if (ptr && count > 0) { + /* Send the next byte and advance the head pointer. */ + amd7930_regs->bbtb = *ptr; + ptr++; + count--; + + /* Empty buffer? Notify the midlevel driver. */ + if (count == 0) + sparcaudio_output_done(); + } +} + +static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + int level; + + /* Set the default audio parameters. */ + map.mr_gx = gx_coeff[128]; + map.mr_stgr = gx_coeff[0]; + + level = (128 * (256 + NGER)) >> 8; + if (level >= 256) { + map.mr_ger = ger_coeff[level-256]; + map.mr_gr = gx_coeff[255]; + } else { + map.mr_ger = ger_coeff[0]; + map.mr_gr = gx_coeff[level]; + } + + map.mr_mmr2 |= AM_MAP_MMR2_LS; + + cli(); + + amd7930_regs->cr = AMR_MAP_MMR1; + amd7930_regs->dr = map.mr_mmr1; + amd7930_regs->cr = AMR_MAP_GX; + WAMD16(amd7930_regs,map.mr_gx); + amd7930_regs->cr = AMR_MAP_STG; + WAMD16(amd7930_regs,map.mr_stgr); + amd7930_regs->cr = AMR_MAP_GR; + WAMD16(amd7930_regs,map.mr_gr); + amd7930_regs->cr = AMR_MAP_GER; + WAMD16(amd7930_regs,map.mr_ger); + amd7930_regs->cr = AMR_MAP_MMR2; + amd7930_regs->dr = map.mr_mmr2; + + sti(); + + MOD_INC_USE_COUNT; + + return 0; +} + +static void amd7930_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + amd7930_disable_ints(); + MOD_DEC_USE_COUNT; +} + +static void amd7930_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count) +{ + count = the_count; + ptr = buffer; + amd7930_enable_ints(); +} + +static void amd7930_stop_output(struct sparcaudio_driver *drv) +{ + amd7930_disable_ints(); + ptr = NULL; + count = 0; +} + + +static struct sparcaudio_operations amd7930_ops = { + amd7930_open, + amd7930_release, + NULL, /* amd7930_ioctl */ + amd7930_start_output, + amd7930_stop_output, +}; + +static struct sparcaudio_driver amd7930_drv = { + "amd7930", + &amd7930_ops, +}; + +/* Probe for the amd7930 chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int amd7930_init(void)) +#endif +{ + struct linux_prom_registers regs[1]; + struct linux_prom_irqs irq; + int err; + +#ifdef MODULE + register_symtab(0); +#endif + + /* Find the PROM "audio" node. */ + amd7930_node = prom_getchild(prom_root_node); + amd7930_node = prom_searchsiblings(amd7930_node, "audio"); + if (!amd7930_node) + return -EIO; + + /* Map the registers into memory. */ + prom_getproperty(amd7930_node, "reg", (char *)regs, sizeof(regs)); + amd7930_regs_size = regs[0].reg_size; + amd7930_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size, + "amd7930", regs[0].which_io, 0); + if (!amd7930_regs) { + printk(KERN_ERR "amd7930: could not allocate registers\n"); + return -EIO; + } + + /* Disable amd7930 interrupt generation. */ + amd7930_disable_ints(); + + /* Initialize the MUX unit to connect the MAP to the CPU. */ + amd7930_regs->cr = AMR_MUX_1_4; + amd7930_regs->dr = (AM_MUX_CHANNEL_Bb << 4) | AM_MUX_CHANNEL_Ba; + amd7930_regs->dr = 0; + amd7930_regs->dr = 0; + amd7930_regs->dr = AM_MUX_MCR4_ENABLE_INTS; + + /* Attach the interrupt handler to the audio interrupt. */ + prom_getproperty(amd7930_node, "intr", (char *)&irq, sizeof(irq)); + amd7930_irq = irq.pri; + request_irq(amd7930_irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", NULL); + enable_irq(amd7930_irq); + + memset(&map, 0, sizeof(map)); + map.mr_mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG; + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(&amd7930_drv); + if (err < 0) { + /* XXX We should do something. Complain for now. */ + printk(KERN_ERR "amd7930: really screwed now\n"); + return -EIO; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + amd7930_disable_ints(); + disable_irq(amd7930_irq); + free_irq(amd7930_irq, NULL); + sparc_free_io(amd7930_regs, amd7930_regs_size); +} +#endif diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c new file mode 100644 index 000000000000..390e268997f6 --- /dev/null +++ b/drivers/sbus/audio/audio.c @@ -0,0 +1,271 @@ +/* + * drivers/sbus/audio/audio.c + * + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * + * This is the audio midlayer that sits between the VFS character + * devices and the low-level audio hardware device drivers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audio.h" + + +/* + * Low-level driver interface. + */ + +/* We only support one low-level audio driver. */ +static struct sparcaudio_driver *driver; + +int register_sparcaudio_driver(struct sparcaudio_driver *drv) +{ + /* If a driver is already present, don't allow it to register. */ + if (driver) + return -EIO; + + MOD_INC_USE_COUNT; + + driver = drv; + return 0; +} + +int unregister_sparcaudio_driver(struct sparcaudio_driver *drv) +{ + /* Make sure that the current driver is unregistering. */ + if (driver != drv) + return -EIO; + + MOD_DEC_USE_COUNT; + + driver = NULL; + return 0; +} + +static void sparcaudio_output_done_task(void * unused) +{ + unsigned long flags; + + save_and_cli(flags); + printk(KERN_DEBUG "sparcaudio: next buffer\n"); + driver->ops->start_output(driver, driver->output_buffers[driver->output_front], + driver->output_sizes[driver->output_front]); + driver->output_active = 1; + restore_flags(flags); +} + +static struct tq_struct sparcaudio_output_tqueue = { + 0, 0, sparcaudio_output_done_task, 0 }; + +void sparcaudio_output_done(void) +{ + /* Point the queue after the "done" buffer. */ + driver->output_front++; + driver->output_count--; + + /* If the output queue is empty, shutdown the driver. */ + if (driver->output_count == 0) { + /* Stop the lowlevel driver from outputing. */ + printk(KERN_DEBUG "sparcaudio: lowlevel driver shutdown\n"); + driver->ops->stop_output(driver); + driver->output_active = 0; + return; + } + + /* Otherwise, queue a task to give the driver the next buffer. */ + queue_task(&sparcaudio_output_tqueue, &tq_immediate); + + /* Wake up any tasks that are waiting. */ + wake_up_interruptible(&driver->output_write_wait); +} + + +/* + * VFS layer interface + */ + +static int sparcaudio_lseek(struct inode * inode, struct file * file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int sparcaudio_read(struct inode * inode, struct file * file, + char *buf, int count) +{ + return -EINVAL; +} + +static int sparcaudio_write(struct inode * inode, struct file * file, + const char *buf, int count) +{ + unsigned long flags; + int bytes_written = 0, bytes_to_copy, err; + + /* Ensure that we have something to write. */ + if (count < 1) + return 0; + + /* Loop until all output is written to device. */ + while (count > 0) { + /* Check to make sure that an output buffer is available. */ + if (driver->output_count == driver->num_output_buffers) { + printk(KERN_DEBUG "sparcaudio: waiting for free buffer\n"); + interruptible_sleep_on(&driver->output_write_wait); + if (current->signal & ~current->blocked) + return bytes_written > 0 ? bytes_written : -EINTR; + } + + /* Determine how much we can copy in this run. */ + bytes_to_copy = count; + if (bytes_to_copy > PAGE_SIZE) + bytes_to_copy = PAGE_SIZE; + + err = verify_area(VERIFY_READ, buf, bytes_to_copy); + if (err) + return err; + + memcpy_fromfs(driver->output_buffers[driver->output_rear], buf, bytes_to_copy); + + /* Update the queue pointers. */ + bytes_written += bytes_to_copy; + driver->output_sizes[driver->output_rear] = bytes_to_copy; + driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; + driver->output_count++; + + /* If the low-level driver is not active, activate it. */ + save_and_cli(flags); + if (! driver->output_active) { + printk(KERN_DEBUG "sparcaudio: activating lowlevel driver\n"); + driver->ops->start_output(driver, driver->output_buffers[driver->output_front], + driver->output_sizes[driver->output_front]); + driver->output_active = 1; + } + restore_flags(flags); + } + + /* Return the number of bytes written to the caller. */ + return bytes_written; +} + +static int sparcaudio_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + default: + if (driver->ops->ioctl) + return driver->ops->ioctl(inode,file,cmd,arg,driver); + else + return -EINVAL; + } + return 0; +} + +static int sparcaudio_open(struct inode * inode, struct file * file) +{ + unsigned int minor = MINOR(inode->i_rdev); + int i; + + /* We only support minor #4 (/dev/audio right now. */ + if (minor != 4) + return -ENXIO; + + /* Make sure that the driver is not busy. */ + if (driver->busy) + return -EBUSY; + + /* Setup the queue of output buffers. */ + driver->num_output_buffers = 32; + driver->output_front = 0; + driver->output_rear = 0; + driver->output_count = 0; + driver->output_active = 0; + driver->output_buffers = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); + driver->output_sizes = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); + if (!driver->output_buffers || !driver->output_sizes) + return -ENOMEM; + + /* Allocate space for the output buffers. */ + for (i = 0; i < driver->num_output_buffers; i++) { + driver->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL); + if (!driver->output_buffers[i]) + return -ENOMEM; + } + + /* Allow the low-level driver to initialize itself. */ + if (driver->ops->open) + driver->ops->open(inode,file,driver); + + + /* Mark the driver as busy. */ + driver->busy = 1; + + MOD_INC_USE_COUNT; + + /* Success return. */ + return 0; +} + +static void sparcaudio_release(struct inode * inode, struct file * file) +{ + int i; + + if (driver->ops->release) + driver->ops->release(inode,file,driver); + + MOD_DEC_USE_COUNT; + + driver->busy = 0; + + for (i = 0; i < driver->num_output_buffers; i++) + kfree(driver->output_buffers[i]); + kfree(driver->output_buffers); + kfree(driver->output_sizes); +} + +static struct file_operations sparcaudio_fops = { + sparcaudio_lseek, + sparcaudio_read, + sparcaudio_write, + NULL, /* sparcaudio_readdir */ + NULL, /* sparcaudio_poll */ + sparcaudio_ioctl, + NULL, /* sparcaudio_mmap */ + sparcaudio_open, + sparcaudio_release +}; + + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int sparcaudio_init(void)) +#endif +{ + /* Register our character device driver with the VFS. */ + if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops)) + return -EIO; + +#ifdef CONFIG_SPARCAUDIO_AMD7930 + amd7930_init(); +#endif + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff --git a/drivers/sbus/audio/audio.h b/drivers/sbus/audio/audio.h new file mode 100644 index 000000000000..7dab325f0cda --- /dev/null +++ b/drivers/sbus/audio/audio.h @@ -0,0 +1,75 @@ +/* + * drivers/sbus/audio/audio.h + * + * Sparc Audio Midlayer + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + */ + +#ifndef _AUDIO_H_ +#define _AUDIO_H_ + +#ifdef __KERNEL__ + +#include +#include +#include + + +#define NR_SPARCAUDIO_DRIVERS 1 + + +struct sparcaudio_driver +{ + const char * name; + struct sparcaudio_operations *ops; + void *private; + + /* Nonzero if the driver is busy. */ + int busy; + + /* Support for a circular queue of output buffers. */ + __u8 **output_buffers; + size_t *output_sizes; + int num_output_buffers, output_front, output_rear, output_count, output_active; + struct wait_queue *output_write_wait, *output_drain_wait; +}; + +struct sparcaudio_operations +{ + int (*open)(struct inode *, struct file *, struct sparcaudio_driver *); + void (*release)(struct inode *, struct file *, struct sparcaudio_driver *); + int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, + struct sparcaudio_driver *); + + /* Ask driver to begin playing a buffer. */ + void (*start_output)(struct sparcaudio_driver *, __u8 * buffer, size_t count); + + /* Ask driver to stop playing a buffer. */ + void (*stop_output)(struct sparcaudio_driver *); + + /* Set and get the audio encoding method. */ + int (*set_encoding)(int encoding); + int (*get_encoding)(void); + + /* Set and get the audio sampling rate (samples per second). */ + int (*set_sampling_rate)(int sampling_rate); + int (*get_sampling_rate)(void); + + /* Set and get the audio output port. */ + int (*set_output_port)(int output_port); + int (*get_output_port)(void); + + /* Set and get the audio input port. */ + int (*set_input_port)(int input_port); + int (*get_input_port)(void); +}; + +extern int register_sparcaudio_driver(struct sparcaudio_driver *); +extern int unregister_sparcaudio_driver(struct sparcaudio_driver *); +extern void sparcaudio_output_done(void); +extern int sparcaudio_init(void); +extern int amd7930_init(void); + +#endif + +#endif diff --git a/drivers/sbus/audio/bounce.c b/drivers/sbus/audio/bounce.c deleted file mode 100644 index 6c4189ff6997..000000000000 --- a/drivers/sbus/audio/bounce.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * drivers/sbus/audio/bounce.c - * - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) - * - * Simple bounce buffer allocator used for allocating pages for use in - * DMA and pseudo-DMA (byte-by-byte using an interrupt) - * applications. For safety, we do most operations in bottom half so - * we have some guarnatee of atomicity. System calls can do - * "start_bh_atomic" to get some atomicity. - */ - -#include -#include -#include "bounce.h" - - -static struct bounce_page *pages[NR_BOUNCE_PAGES]; -static struct bounce_page *free_list_head, *free_list_tail; - -/* Add a bounce page to the free list. */ -static void add_bounce_page(struct bounce_page *page) -{ - unsigned long flags; - -#ifdef DEBUG_BOUNCE - if (page->next) { - printk(KERN_DEBUG "add_bounce_page: page already on list from %p\n", - __builtin_return_address(0)); - return; - } -#endif - - save_flags(flags); - cli(); - - /* Case #1: Nothing on the list. */ - if (!free_list_tail) { -#ifdef DEBUG_BOUNCE - if (free_list_head) { - printk(KERN_DEBUG "add_bounce_page: inconsistent free list from %p\n", - __builtin_return_address(0)); - restore_flags(flags); - return; - } -#endif - free_list_head = free_list_tail = page; - } else { - free_list_tail->next = page; - page->next = NULL; - free_list_tail = page; - } - - restore_flags(flags); -} - -/* Remove a bounce page from the free list. */ -static struct bounce_page *next_bounce_page(void) -{ - struct bounce_page *p; - unsigned long flags; - - save_flags(flags); - cli(); - - /* If the free list is empty, return empty handed. */ - if (!free_list_head) { - restore_flags(flags); - return NULL; - } - - /* Remove the next available bounce page from the free list. */ - p = free_list_head; - - /* Update the free list pointers. */ - free_list_head = free_list_head->next; - if (!free_list_head) - free_list_tail = NULL; - - /* Return the page that we found. */ - p->next = NULL; - restore_flags(flags); - return p; -} - -/* Allocate the bounce buffers and the page lists. */ -int bounce_init(void) -{ - register int i; - - /* Allocate space for all of the bounce pages. */ - for (i = 0; i < NR_BOUNCE_PAGES; i++) { - pages[i] = __get_free_page(GFP_KERNEL); - if (!pages[i]) { - register int j; - for (j = 0; j < i; j++) free_page(pages[i]); - return -ENOMEM; - } - } - - /* Place all of the pages onto the free list. */ - for (i = 0; i < NR_BOUNCE_PAGES - 1; i++) - pages[i]->next = pages[i+1]; - pages[NR_BOUNCE_BUFFERS-1]->next = NULL; - - /* Setup pointers to the free list head and tail. */ - free_list_head = pages[0]; - free_list_tail = pages[NR_BOUNCE_BUFFERS-1]; - return 0; -} - -/* Allocate a bounce buffer to a process. */ -struct bounce_page * get_bounce_page(int timeout) -{ - struct bounce_page *p; - int tries; - - do { - /* Do not allow interrupts to muck with the lists. */ - start_bh_atomic(); - - /* Check to see if a bounce page is available. */ - p = next_bounce_page(); - if (p) { - end_bh_atomic(); - return p; - } - - /* No bounce page was available. Sleep and wait for one. */ - end_bh_atomic(); - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ / 10; - schedule(); - - /* If we received a signal, then bail out. */ - if (current->signal & ~current->blocked) - return NULL; - - } while (jiffies <= timeout); - - /* We did not find anything before the timeout. */ - return NULL; -} - -/* Return a bounce buffer to the free list. */ -void put_bounce_page(struct bounce_page *page) -{ - add_bounce_page(page); -} - diff --git a/drivers/sbus/audio/bounce.h b/drivers/sbus/audio/bounce.h deleted file mode 100644 index 71e581871758..000000000000 --- a/drivers/sbus/audio/bounce.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _BOUNCE_H_ -#define _BOUNCE_H_ - -#include - -/* Each page that is used for a bounce buffer has the following header - * at the top which points to the next page in the free or in-use list - * and provides some other stats for drivers. - */ - -#define NR_BOUNCE_PAGES 32 - -struct bounce_page -{ - struct bounce_page *next; - __u32 size; - __u32 remaining; - __u8 *current; - __u8 data[PAGE_SIZE - 1*sizeof(struct bounce_page *) - - 2*sizeof(__u32) - sizeof(__u8)]; -}; - -#endif diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c new file mode 100644 index 000000000000..91b7c404c5ac --- /dev/null +++ b/drivers/sbus/audio/cs4231.c @@ -0,0 +1,518 @@ +/* + * drivers/sbus/audio/cs4231.c + * + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright (C) 1996 Derrick J Brashear (shadow@andrew.cmu.edu) + * + * This is the lowlevel driver for the CS4231 audio chip found on some + * sun4m machines. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audio.h" +#include "cs4231.h" + +/* Stolen for now from compat.h */ +#ifndef MAX /* Usually found in . */ +#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a)) +#endif +#ifndef MIN /* Usually found in . */ +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#endif + +static int cs4231_node, cs4231_irq, cs4231_is_revision_a, cs4231_ints_on = 0; +static unsigned int cs4231_monitor_gain_value; +cs4231_regs_size + +static int cs4231_output_muted_value; + +static struct cs4231_stream_info cs4231_input; +static struct cs4231_stream_info cs4231_output; + +static int cs4231_busy = 0, cs4231_need_init = 0; + +static volatile struct cs4231_chip *cs4231_chip = NULL; + +static __u8 * ptr; +static size_t count; + +#define CHIP_BUG udelay(100); cs4231_ready(); udelay(1000); + +static void cs4231_ready(void) +{ + register unsigned int x = 0; + + cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; + while (cs4231_chip->pioregs.iar == IAR_NOT_READY && x <= CS_TIMEOUT) { + x++; + } + + x = 0; + + cs4231_chip->pioregs.iar = 0x0b; + + while (cs4231_chip->pioregs.idr == AUTOCAL_IN_PROGRESS && x <= CS_TIMEOUT) { + x++; + } +} + +/* Enable cs4231 interrupts atomically. */ +static __inline__ void cs4231_enable_ints(void) +{ + register unsigned long flags; + + if (cs4231_ints_on) + return; + + save_and_cli(flags); + /* do init here + amd7930_regs->cr = AMR_INIT; + amd7930_regs->dr = AM_INIT_ACTIVE; + */ + restore_flags(flags); + + cs4231_ints_on = 1; +} + +/* Disable cs4231 interrupts atomically. */ +static __inline__ void cs4231_disable_ints(void) +{ + register unsigned long flags; + + if (!cs4231_ints_on) + return; + + save_and_cli(flags); +/* + amd7930_regs->cr = AMR_INIT; + amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS; +*/ + restore_flags(flags); + + cs4231_ints_on = 0; +} + + +/* Audio interrupt handler. */ +static void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + __u8 dummy; + + /* Clear the interrupt. */ + dummy = cs4231_chip->dmaregs.dmacsr; + + cs4231_chip->dmaregs.dmacsr = dummy; + +} + +static unsigned int cs4231_output_muted(unsigned int value) +{ + if (!value) { + cs4231_chip->pioregs.iar = 0x7; + cs4231_chip->pioregs.idr &= OUTCR_UNMUTE; + cs4231_chip->pioregs.iar = 0x6; + cs4231_chip->pioregs.idr &= OUTCR_UNMUTE; + cs4231_output_muted_value = 0; + } else { + cs4231_chip->pioregs.iar = 0x7; + cs4231_chip->pioregs.idr |= OUTCR_MUTE; + cs4231_chip->pioregs.iar = 0x6; + cs4231_chip->pioregs.idr |= OUTCR_MUTE; + cs4231_output_muted_value = 1; + } + return (cs4231_output_muted_value); +} + +static unsigned int cs4231_out_port(unsigned int value) +{ + unsigned int r = 0; + + /* You can have any combo you want. Just don't tell anyone. */ + + cs4231_chip->pioregs.iar = 0x1a; + cs4231_chip->pioregs.idr |= MONO_IOCR_MUTE; + cs4231_chip->pioregs.iar = 0x0a; + cs4231_chip->pioregs.idr |= PINCR_LINE_MUTE; + cs4231_chip->pioregs.idr |= PINCR_HDPH_MUTE; + + if (value & AUDIO_SPEAKER) { + cs4231_chip->pioregs.iar = 0x1a; + cs4231_chip->pioregs.idr &= ~MONO_IOCR_MUTE; + r |= AUDIO_SPEAKER; + } + + if (value & AUDIO_HEADPHONE) { + cs4231_chip->pioregs.iar = 0x0a; + cs4231_chip->pioregs.idr &= ~PINCR_HDPH_MUTE; + r |= AUDIO_HEADPHONE; + } + + if (value & AUDIO_LINE_OUT) { + cs4231_chip->pioregs.iar = 0x0a; + cs4231_chip->pioregs.idr &= ~PINCR_LINE_MUTE; + r |= AUDIO_LINE_OUT; + } + + return (r); +} + +static unsigned int cs4231_in_port(unsigned int value) +{ + unsigned int r = 0; + + /* The order of these seems to matter. Can't tell yet why. */ + + if (value & AUDIO_INTERNAL_CD_IN) { + cs4231_chip->pioregs.iar = 0x1; + cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs.iar = 0x0; + cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr); + r = AUDIO_INTERNAL_CD_IN; + } + if ((value & AUDIO_LINE_IN)) { + cs4231_chip->pioregs.iar = 0x1; + cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs.iar = 0x0; + cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr); + r = AUDIO_LINE_IN; + } else if (value & AUDIO_MICROPHONE) { + cs4231_chip->pioregs.iar = 0x1; + cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs.iar = 0x0; + cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr); + r = AUDIO_MICROPHONE; + } + + return (r); +} + +static unsigned int cs4231_monitor_gain(unsigned int value) +{ + int a = 0; + + a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) / + (AUDIO_MAX_GAIN + 1)); + + cs4231_chip->pioregs.iar = 0x0d; + if (a >= CS4231_MON_MAX_ATEN) + cs4231_chip->pioregs.idr = LOOPB_OFF; + else + cs4231_chip->pioregs.idr = ((a << 2) | LOOPB_ON); + + + if (value == AUDIO_MAX_GAIN) + return AUDIO_MAX_GAIN; + + return ((CS4231_MAX_DEV_ATEN - a) * (AUDIO_MAX_GAIN + 1) / + (CS4231_MAX_DEV_ATEN + 1)); +} + +/* Set record gain */ +static unsigned int cs4231_record_gain(unsigned int value, unsigned char balance) +{ + unsigned int tmp = 0, r, l, ra, la; + unsigned char old_gain; + + + r = l = value; + + if (balance < AUDIO_MID_BALANCE) { + r = MAX(0, (int)(value - + ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); + } else if (balance > AUDIO_MID_BALANCE) { + l = MAX(0, (int)(value - + ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); + } + + la = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); + ra = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); + + cs4231_chip->pioregs.iar = 0x0; + old_gain = cs4231_chip->pioregs.idr; + cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, la); + cs4231_chip->pioregs.iar = 0x1; + old_gain = cs4231_chip->pioregs.idr; + cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, ra); + + if (l == value) { + (l == 0) ? (tmp = 0) : (tmp = ((la + 1) * AUDIO_MAX_GAIN) / (CS4231_MAX_GAIN + 1)); + } else if (r == value) { + (r == 0) ? (tmp = 0) : (tmp = ((ra + 1) * AUDIO_MAX_GAIN) / (CS4231_MAX_GAIN + 1)); + } + return (tmp); +} + +/* Set play gain */ +static unsigned int cs4231_play_gain(unsigned int value, unsigned char balance) +{ + unsigned int tmp = 0, r, l, ra, la; + unsigned char old_gain; + + r = l = value; + if (balance < AUDIO_MID_BALANCE) { + r = MAX(0, (int)(value - + ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); + } else if (balance > AUDIO_MID_BALANCE) { + l = MAX(0, (int)(value - + ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); + } + + if (l == 0) { + la = CS4231_MAX_DEV_ATEN; + } else { + la = CS4231_MAX_ATEN - + (l * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); + } + if (r == 0) { + ra = CS4231_MAX_DEV_ATEN; + } else { + ra = CS4231_MAX_ATEN - + (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); + } + + cs4231_chip->pioregs.iar = 0x6; + old_gain = cs4231_chip->pioregs.idr; + cs4231_chip->pioregs.idr = GAIN_SET(old_gain, la); + cs4231_chip->pioregs.iar = 0x7; + old_gain = cs4231_chip->pioregs.idr; + cs4231_chip->pioregs.idr = GAIN_SET(old_gain, ra); + + if ((value == 0) || (value == AUDIO_MAX_GAIN)) { + tmp = value; + } else { + if (l == value) { + tmp = ((CS4231_MAX_ATEN - la) * + (AUDIO_MAX_GAIN + 1) / + (CS4231_MAX_ATEN + 1)); + } else if (r == value) { + tmp = ((CS4231_MAX_ATEN - ra) * + (AUDIO_MAX_GAIN + 1) / + (CS4231_MAX_ATEN + 1)); + } + } + return (tmp); +} + +/* Reset the audio chip to a sane state. */ +static void cs4231_reset(void) +{ + cs4231_chip->dmaregs.dmacsr = APC_RESET; + cs4231_chip->dmaregs.dmacsr = 0x00; + cs4231_chip->dmaregs.dmacsr |= APC_CODEC_PDN; + + udelay(20); + + cs4231_chip->dmaregs.dmacsr &= ~(APC_CODEC_PDN); + cs4231_chip->pioregs.iar |= IAR_AUTOCAL_BEGIN; + + CHIP_BUG + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x0c; + cs4231_chip->pioregs.idr = MISC_IR_MODE2; + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08; + cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + + CHIP_BUG + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c; + cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + + CHIP_BUG + + cs4231_chip->pioregs.iar = 0x19; + + if (cs4231_chip->pioregs.idr & CS4231A) + cs4231_is_revision_a = 1; + else + cs4231_is_revision_a = 0; + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x10; + cs4231_chip->pioregs.idr = (u_char)OLB_ENABLE; + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x11; + if (cs4231_is_revision_a) + cs4231_chip->pioregs.idr = (HPF_ON | XTALE_ON); + else + cs4231_chip->pioregs.idr = (HPF_ON); + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1a; + cs4231_chip->pioregs.idr = 0x00; + + cs4231_output.gain = cs4231_play_gain(CS4231_DEFAULT_PLAYGAIN, + AUDIO_MID_BALANCE); + cs4231_input.gain = cs4231_record_gain(CS4231_DEFAULT_RECGAIN, + AUDIO_MID_BALANCE); + + cs4231_output.port = cs4231_out_port(AUDIO_SPEAKER); + cs4231_input.port = cs4231_in_port(AUDIO_MICROPHONE); + + cs4231_monitor_gain_value = cs4231_monitor_gain(LOOPB_OFF); + + cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; + + cs4231_ready(); + + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x09; + cs4231_chip->pioregs.idr &= ACAL_DISABLE; + cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; + + cs4231_ready(); + + cs4231_output_muted_value = cs4231_output_muted(0x0); +} + +static int cs4231_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + int level; + + /* Set the default audio parameters. */ + + cs4231_output.sample_rate = CS4231_RATE; + cs4231_output.channels = CS4231_CHANNELS; + cs4231_output.precision = CS4231_PRECISION; + cs4231_output.encoding = AUDIO_ENCODING_ULAW; + + cs4231_input.sample_rate = CS4231_RATE; + cs4231_input.channels = CS4231_CHANNELS; + cs4231_input.precision = CS4231_PRECISION; + cs4231_input.encoding = AUDIO_ENCODING_ULAW; + + cs4231_ready(); + + cs4231_need_init = 1; +#if 1 + /* Arguably this should only happen once. I need to play around + * on a Solaris box and see what happens + */ + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08; + cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c; + cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + +#endif + + CHIP_BUG + + MOD_INC_USE_COUNT; + + return 0; +} + +static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + cs4231_disable_ints(); + MOD_DEC_USE_COUNT; +} + +static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count) +{ + count = the_count; + ptr = buffer; + cs4231_enable_ints(); +} + +static void cs4231_stop_output(struct sparcaudio_driver *drv) +{ + cs4231_disable_ints(); + ptr = NULL; + count = 0; +} + + +static struct sparcaudio_operations cs4231_ops = { + cs4231_open, + cs4231_release, + NULL, /* cs4231_ioctl */ + cs4231_start_output, + cs4231_stop_output, +}; + +static struct sparcaudio_driver cs4231_drv = { + "cs4231", + &cs4231_ops, +}; + +/* Probe for the cs4231 chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int cs4231_init(void)) +#endif +{ + struct linux_prom_registers regs[1]; + struct linux_prom_irqs irq; + int err; + +#ifdef MODULE + register_symtab(0); +#endif + + /* Find the PROM CS4231 node. */ + cs4231_node = prom_getchild(prom_root_node); + cs4231_node = prom_searchsiblings(cs4231_node,"iommu"); + cs4231_node = prom_getchild(cs4231_node); + cs4231_node = prom_searchsiblings(cs4231_node,"sbus"); + cs4231_node = prom_getchild(cs4231_node); + cs4231_node = prom_searchsiblings(cs4231_node,"SUNW,CS4231"); + + if (!cs4231_node) + return -EIO; + + /* XXX Add for_each_sbus() search as well for LX and friends. */ + /* XXX Copy out for prom_apply_sbus_ranges. */ + + /* Map the registers into memory. */ + prom_getproperty(cs4231_node, "reg", (char *)regs, sizeof(regs)); + cs4231_regs_size = regs[0].reg_size; + cs4231_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size, + "cs4231", regs[0].which_io, 0); + if (!cs4231_regs) { + printk(KERN_ERR "cs4231: could not allocate registers\n"); + return -EIO; + } + + /* Disable cs4231 interrupt generation. */ + cs4231_disable_ints(); + + /* Reset the audio chip. */ + cs4231_reset(); + + /* Attach the interrupt handler to the audio interrupt. */ + prom_getproperty(cs4231_node, "intr", (char *)&irq, sizeof(irq)); + cs4231_irq = irq.pri; + request_irq(cs4231_irq, cs4231_interrupt, SA_INTERRUPT, "cs4231", NULL); + enable_irq(cs4231_irq); + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(&cs4231_drv); + if (err < 0) { + /* XXX We should do something. Complain for now. */ + printk(KERN_ERR "cs4231: really screwed now\n"); + return -EIO; + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + unregister_sparcaudio_driver(&cs4231_drv); + cs4231_disable_ints(); + disable_irq(cs4231_irq); + free_irq(cs4231_irq, NULL); + sparc_free_io(cs4231_regs, cs4231_regs_size); +} +#endif diff --git a/drivers/sbus/audio/cs4231.h b/drivers/sbus/audio/cs4231.h new file mode 100644 index 000000000000..82e6252f9439 --- /dev/null +++ b/drivers/sbus/audio/cs4231.h @@ -0,0 +1,138 @@ +/* + * drivers/sbus/audio/cs4231.h + * + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) + * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org) + */ + +#ifndef _CS4231_H_ +#define _CS4231_H_ + +#include + +struct cs4231_regs { + u_char iar; /* Index Address Register */ + u_char pad0[3]; + u_char idr; /* Indexed Data Register */ + u_char pad1[3]; + u_char statr; /* Status Register */ + u_char pad2[3]; + u_char piodr; /* PIO Data Register I/O */ + u_char pad3[3]; +}; + +struct cs4231_dma { + u_long dmacsr; /* APC CSR */ + u_long dmapad[3]; + u_long dmacva; /* Capture Virtual Address */ + u_long dmacc; /* Capture Count */ + u_long dmacnva; /* Capture Next VAddress */ + u_long dmacnc; /* Capture Next Count */ + u_long dmapva; /* Playback Virtual Address */ + u_long dmapc; /* Playback Count */ + u_long dmapnva; /* Playback Next VAddress */ + u_long dmapnc; /* Playback Next Count */ +}; + +struct cs4231_chip { + struct cs4231_regs pioregs; + struct cs4231_dma dmaregs; +}; + +struct cs4231_stream_info { + unsigned int sample_rate; /* samples per second */ + unsigned int channels; /* number of interleaved channels */ + unsigned int precision; /* bit-width of each sample */ + unsigned int encoding; /* data encoding method */ + unsigned int gain; /* gain level: 0 - 255 */ + unsigned int port; +}; + +#define CS_TIMEOUT 9000000 + +#define GAIN_SET(var, gain) ((var & ~(0x3f)) | gain) +#define RECGAIN_SET(var, gain) ((var & ~(0x1f)) | gain) + +#define IAR_AUTOCAL_BEGIN 0x40 +#define IAR_AUTOCAL_END ~(0x40) +#define IAR_NOT_READY 0x80 /* 80h not ready CODEC state */ + +#define MIC_ENABLE(var) ((var & 0x2f) | 0x80) +#define LINE_ENABLE(var) (var & 0x2f) +#define CDROM_ENABLE(var) ((var & 0x2f) | 0x40) + +#define OUTCR_MUTE 0x80 +#define OUTCR_UNMUTE ~0x80 + +/* 8 */ +#define DEFAULT_DATA_FMAT 0x20 + +/* 10 */ +#define PINCR_LINE_MUTE 0x40 +#define PINCR_HDPH_MUTE 0x80 + +/* 11 */ +#define AUTOCAL_IN_PROGRESS 0x20 + +/* 12 */ +#define MISC_IR_MODE2 0x40 + +/* 13 */ +#define LOOPB_ON 0x01 +#define LOOPB_OFF 0x00 + +/* 16 */ +#define OLB_ENABLE 0x80 + +/* 17 */ +#define HPF_ON 0x01 +#define XTALE_ON 0x20 + +#define MONO_IOCR_MUTE 0x40; + +/* 30 */ +#define CS4231A 0x20 + + +#define APC_CODEC_PDN 0x20 +#define APC_RESET 0x01 + +#define CS4231_DEFAULT_PLAYGAIN (132) +#define CS4231_DEFAULT_RECGAIN (126) + +#define CS4231_MIN_ATEN (0) +#define CS4231_MAX_ATEN (31) +#define CS4231_MAX_DEV_ATEN (63) +#define CS4231_MIN_GAIN (0) +#define CS4231_MAX_GAIN (15) +#define CS4231_MON_MIN_ATEN (0) +#define CS4231_MON_MAX_ATEN (63) + +#define CS4231_PRECISION (8) /* Bits per sample unit */ +#define CS4231_CHANNELS (1) /* Channels per sample frame */ + +#define CS4231_RATE (8000) + +#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ +#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ +#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ +#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ +#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ + +#define AUDIO_LEFT_BALANCE (0) +#define AUDIO_MID_BALANCE (32) +#define AUDIO_RIGHT_BALANCE (64) +#define AUDIO_BALANCE_SHIFT (3) + +#define AUDIO_SPEAKER 0x01 +#define AUDIO_HEADPHONE 0x02 +#define AUDIO_LINE_OUT 0x04 + +#define AUDIO_MICROPHONE 0x01 +#define AUDIO_LINE_IN 0x02 +#define AUDIO_INTERNAL_CD_IN 0x04 + +#define AUDIO_MAX_GAIN (255) + +#endif diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index bc32c7fafa22..4c74012b379b 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -558,23 +558,29 @@ static struct file_operations openprom_fops = { NULL, /* openprom_read */ NULL, /* openprom_write */ NULL, /* openprom_readdir */ - NULL, /* openprom_select */ + NULL, /* openprom_poll */ openprom_ioctl, NULL, /* openprom_mmap */ openprom_open, openprom_release }; -static struct miscdevice misc_openprom = { +static struct miscdevice openprom_dev = { SUN_OPENPROM_MINOR, "openprom", &openprom_fops }; +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else __initfunc(int openprom_init(void)) +#endif { unsigned long flags; int error; - error = misc_register(&misc_openprom); + error = misc_register(&openprom_dev); if (error) { printk(KERN_ERR "openprom: unable to get misc minor\n"); return error; @@ -587,7 +593,7 @@ __initfunc(int openprom_init(void)) if (options_node == 0 || options_node == -1) { printk(KERN_ERR "openprom: unable to find options node\n"); - misc_deregister(&misc_openprom); + misc_deregister(&openprom_dev); return -EIO; } @@ -596,15 +602,9 @@ __initfunc(int openprom_init(void)) #ifdef MODULE -int init_module(void) -{ - register_symtab(0); - return openprom_init(); -} - void cleanup_module(void) { - misc_deregister(&misc_openprom); + misc_deregister(&openprom_dev); } #endif diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index 59bc34ea7bd9..59de9fcc64f1 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.6 1996/11/21 16:57:50 jj Exp $ +/* $Id: rtc.c,v 1.9 1997/01/26 07:13:40 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +129,7 @@ static struct file_operations rtc_fops = { NULL, /* rtc_read */ NULL, /* rtc_write */ NULL, /* rtc_readdir */ - NULL, /* rtc_select */ + NULL, /* rtc_poll */ rtc_ioctl, NULL, /* rtc_mmap */ rtc_open, @@ -137,16 +138,22 @@ static struct file_operations rtc_fops = { static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; +EXPORT_NO_SYMBOLS; + #ifdef MODULE int init_module(void) #else __initfunc(int rtc_init(void)) #endif { -#ifdef MODULE - register_symtab(0); -#endif - misc_register(&rtc_dev); + int error; + + error = misc_register(&rtc_dev); + if (error) { + printk(KERN_ERR "rtc: unable to get misc minor\n"); + return error; + } + return 0; } diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c index cd8e1c2ddefa..b09bcbf510dc 100644 --- a/drivers/sbus/char/suncons.c +++ b/drivers/sbus/char/suncons.c @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.43 1996/12/23 10:16:12 ecd Exp $ +/* $Id: suncons.c,v 1.44 1997/01/25 02:47:10 miguel Exp $ * * suncons.c: Sun SparcStation console support. * @@ -74,6 +74,7 @@ #include #include #include +#include #include "../../char/kbd_kern.h" #include "../../char/vt_kern.h" @@ -383,7 +384,7 @@ __initfunc(void serial_finish_init(void (*printfunc)(const char *))) __initfunc(void con_type_init_finish(void)) { - int i; + int i, cpu; char *p = con_fb_base + skip_bytes; char q[2] = {0,5}; int currcons = 0; @@ -408,14 +409,17 @@ __initfunc(void con_type_init_finish(void)) fbinfo[0].color_map CM(i+32,2) = linux_logo_blue [i]; } (*fbinfo [0].loadcmap)(&fbinfo [0], 0, LINUX_LOGO_COLORS + 32); - for (i = 0; i < 80; i++, p += chars_per_line) - memcpy (p, linux_logo + 80 * i, 80); + for (i = 0; i < 80; i++, p += chars_per_line){ + for (cpu = 0; cpu < linux_num_cpus; cpu++){ + memcpy (p + (cpu * 84), linux_logo + 80 * i, 80); + } + } } else if (con_depth == 1) { for (i = 0; i < 80; i++, p += chars_per_line) memcpy (p, linux_logo_bw + 10 * i, 10); } putconsxy(0, q); - ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20; + ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 80 * (linux_num_cpus - 1); for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) { *ush = (attr << 8) + *p; @@ -1163,6 +1167,7 @@ __initfunc(unsigned long sun_console_init(unsigned long memory_start)) prom_printf("Could not probe console, bailing out...\n"); prom_halt(); } + sun_clear_screen(); for (i = FRAME_BUFFERS; i > 1; i--) if (fbinfo[i - 1].type.fb_type != FBTYPE_NOTYPE) break; diff --git a/drivers/sbus/char/sunfb.c b/drivers/sbus/char/sunfb.c index 7c2e00a2f182..65a16c81352e 100644 --- a/drivers/sbus/char/sunfb.c +++ b/drivers/sbus/char/sunfb.c @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.19 1996/12/23 10:16:15 ecd Exp $ +/* $Id: sunfb.c,v 1.20 1997/01/26 07:13:40 davem Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -298,7 +298,7 @@ static struct file_operations graphdev_fops = NULL, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ fb_ioctl, fb_mmap, fb_open, /* open */ diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 51f43c7564bc..db418092719b 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,8 @@ extern void reset_vc(unsigned int new_console); extern void scrollback(int); extern void scrollfront(int); -unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ +unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ +unsigned char aux_device_present = 0x00; /* To make kernel/ksyms.c happy */ /* * global state includes the following, and various static variables @@ -1240,14 +1242,11 @@ kbd_fasync (struct inode *inode, struct file *filp, int on) return 0; } -static int -kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait) +static unsigned int kbd_poll (struct file *f, poll_table *wait) { - if (sel_type != SEL_IN) - return 0; + poll_wait(&kbd_wait, wait); if (kbd_head != kbd_tail) - return 1; - select_wait (&kbd_wait, wait); + return POLLIN | POLLRDNORM; return 0; } @@ -1355,7 +1354,7 @@ file_operations kbd_fops = kbd_read, /* read */ NULL, /* write */ NULL, /* readdir */ - kbd_select, /* select */ + kbd_poll, /* poll */ kbd_ioctl, /* ioctl */ NULL, /* mmap */ kbd_open, /* open */ diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index d4e60cfbb4df..2ad211de2c88 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -346,15 +347,11 @@ sun_mouse_read(struct inode *inode, struct file *file, char *buffer, return 0; } -static int -sun_mouse_select(struct inode *inode, struct file *file, int sel_type, - select_table *wait) +static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { - if(sel_type != SEL_IN) - return 0; + poll_wait(&sunmouse.proc_list, wait); if(sunmouse.ready) - return 1; - select_wait(&sunmouse.proc_list, wait); + return POLLIN | POLLRDNORM; return 0; } int @@ -400,7 +397,7 @@ struct file_operations sun_mouse_fops = { sun_mouse_read, sun_mouse_write, NULL, - sun_mouse_select, + sun_mouse_poll, sun_mouse_ioctl, NULL, sun_mouse_open, diff --git a/drivers/scsi/ChangeLog b/drivers/scsi/ChangeLog index c8aa128f8cbe..43d4500a5c73 100644 --- a/drivers/scsi/ChangeLog +++ b/drivers/scsi/ChangeLog @@ -1,3 +1,8 @@ +Sat Jan 18 15:51:45 1997 Richard Henderson + + * Don't play with usage_count directly, instead hand around + the module header and use the module macros. + Fri May 17 00:00:00 1996 Leonard N. Zubkoff * BusLogic Driver Version 2.0.3 Released. @@ -40,10 +45,10 @@ Wed Jul 19 10:09:17 1995 Michael Neuffer * eata_dma.c (eata_queue)(eata_int_handler): Added code to do command latency measurements if requested by root through - /proc/scsi interface. + /proc/scsi interface. Throughout Use HZ constant for time references. - * eata_pio.c: Use HZ constant for time references. + * eata_pio.c: Use HZ constant for time references. * aic7xxx.c, aic7xxx.h, aic7xxx_asm.c: Changed copyright from BSD to GNU style. @@ -54,7 +59,7 @@ Wed Jul 19 09:25:30 1995 Michael Neuffer * Linux 1.3.10 released. - * scsi_proc.c (dispatch_scsi_info): Removed unused variable. + * scsi_proc.c (dispatch_scsi_info): Removed unused variable. Wed Jul 19 09:25:30 1995 Michael Neuffer @@ -62,11 +67,11 @@ Wed Jul 19 09:25:30 1995 Michael Neuffer * scsi.c Blacklist concept expanded to 'support' more device deficiencies. blacklist[] renamed to device_list[] - (scan_scsis): Code cleanup. - + (scan_scsis): Code cleanup. + * scsi_debug.c (scsi_debug_proc_info): Added support to control - device lockup simulation via /proc/scsi interface. - + device lockup simulation via /proc/scsi interface. + Wed Jul 19 09:22:34 1995 Michael Neuffer @@ -80,7 +85,7 @@ Wed Jul 19 09:18:28 1995 Michael Neuffer * Native wide, multichannel and /proc/scsi support now in official kernel distribution. - + * scsi.c/h, hosts.c/h et al reindented to increase readability (especially on 80 column wide terminals). @@ -94,7 +99,7 @@ Wed Jul 19 09:18:28 1995 Michael Neuffer Thu Jun 20 15:20:27 1995 Michael Neuffer - * proc.c: Renamed to scsi_proc.c + * proc.c: Renamed to scsi_proc.c Mon Jun 12 20:32:45 1995 Michael Neuffer @@ -102,15 +107,15 @@ Mon Jun 12 20:32:45 1995 Michael Neuffer Mon May 15 19:33:14 1995 Michael Neuffer - * scsi.c: Added native multichannel and wide scsi support. + * scsi.c: Added native multichannel and wide scsi support. - * proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries): - Updated /proc/scsi interface. + * proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries): + Updated /proc/scsi interface. Thu May 4 17:58:48 1995 Michael Neuffer * sd.c (requeue_sd_request): Zero out the scatterlist only if - scsi_malloc returned memory for it. + scsi_malloc returned memory for it. * eata_dma.c (register_HBA) (eata_queue): Add support for large scatter/gather tables and set use_clustering accordingly @@ -127,11 +132,11 @@ Wed Apr 12 15:25:52 1995 Eric Youngdale (eric@andante) cards. * eata_dma.c: Update to 2.3.5r. Modularize. Improved error handling - throughout and fixed bug interrupt routine which resulted in shifted + throughout and fixed bug interrupt routine which resulted in shifted status bytes. Added blink LED state checks for ISA and EISA HBAs. - Memory management bug seems to have disappeared ==> increasing - C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for - performance reasons. + Memory management bug seems to have disappeared ==> increasing + C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for + performance reasons. * scsi.c: If we get a FMK, EOM, or ILI when attempting to scan the bus, assume that it was just noise on the bus, and ignore @@ -211,8 +216,8 @@ Mon Feb 20 08:57:17 1995 Eric Youngdale (eric@andante) * hosts.h: Change io_port to long int from short. * 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP, - NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output - fixed, should initialize correctly if left running, now loadable, + NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output + fixed, should initialize correctly if left running, now loadable, new memory allocation, extraneous diagnostic output suppressed, splx() replaced with save/restore flags. [ Drew ] @@ -243,7 +248,7 @@ Wed Feb 15 10:52:56 1995 Eric Youngdale (eric@andante) * eata.c: Update to 1.17. - * eata_dma.c: Update to 2.31a. Add more support for /proc/scsi. + * eata_dma.c: Update to 2.31a. Add more support for /proc/scsi. Continuing modularization. Less crashes because of the bug in the memory management ==> increase C_P_L_CURRENT_MAX to 10 and decrease C_P_L_DIV to 4. @@ -315,13 +320,13 @@ Wed Feb 1 09:20:45 1995 Eric Youngdale (eric@andante) * NCR5380.c: Update interrupt handler with new arglist. Minor cleanups. - * eata_dma.c: Begin to modularize. Add hooks for /proc/scsi. + * eata_dma.c: Begin to modularize. Add hooks for /proc/scsi. New version 2.3.0a. Add code in interrupt handler to allow - certain CDROM drivers to be detected which return a + certain CDROM drivers to be detected which return a CHECK_CONDITION during SCSI bus scan. Add opcode check to get all DATA IN and DATA OUT phases right. Utilize HBA_interpret flag. Improvements in HBA identification. Various other minor stuff. - + * hosts.c: Initialize ->dma_channel and ->io_port when registering a new host. @@ -370,7 +375,7 @@ Mon Jan 23 23:53:10 1995 Eric Youngdale (eric@andante) * 53c7,8xx.h: Change SG size to 127. * eata_dma: Update to version 2.10i. Remove bug in the registration - of multiple HBAs and channels. Minor other improvements and stylistic + of multiple HBAs and channels. Minor other improvements and stylistic changes. * scsi.c: Test for Toshiba XM-3401TA and exclude from detection @@ -396,7 +401,7 @@ Sun Jan 22 22:08:46 1995 Eric Youngdale (eric@andante) * aha152x.c: Update to version 1.8 from Juergen. * eata_dma.c: Update from Michael Neuffer. - Remove hard limit of 2 commands per lun and make it better + Remove hard limit of 2 commands per lun and make it better configurable. Improvements in HBA identification. * in2000.c: Fix biosparam to support large disks. @@ -413,7 +418,7 @@ Wed Jan 18 23:33:09 1995 Eric Youngdale (eric@andante) * buslogic.c: Likewise. * eata_dma.c: Use min of 2 cmd_per_lun for OCS_enabled boards. - + * scsi.c: Make RECOVERED_ERROR a SUGGEST_IS_OK. * sd.c: Fail if we are opening a non-existent partition. @@ -425,7 +430,7 @@ Wed Jan 18 23:33:09 1995 Eric Youngdale (eric@andante) * sr_ioctl.c: Remove CDROMMULTISESSION_SYS ioctl. * ultrastor.c: Fix bug in call to ultrastor_interrupt (wrong #args). - + Mon Jan 16 07:18:23 1995 Eric Youngdale (eric@andante) * Linux 1.1.82 released. @@ -635,7 +640,7 @@ Fri Dec 23 13:36:25 1994 Eric Youngdale (eric@andante) * st.c: New version from Kai - add better support for backspace. - * u14-34f.c: New version from Dario. Supports blocking. + * u14-34f.c: New version from Dario. Supports blocking. Wed Dec 14 14:46:30 1994 Eric Youngdale (eric@andante) @@ -733,7 +738,7 @@ Tue Nov 29 18:48:42 1994 Eric Youngdale (eric@andante) status. * README.st: Document this. - + * sr.c: Bugfix (do not subtract CD_BLOCK_OFFSET) for photo-cd code. @@ -811,7 +816,7 @@ Tue Nov 29 15:43:50 1994 Eric Youngdale (eric@andante.aib.com) * hosts.h: Add n_io_port to Scsi_Host (used when releasing module). * hosts.c: Initialize block field. - + * in2000.c: Remove "static" declarations from exported functions. * in2000.h: Likewise. @@ -1083,7 +1088,7 @@ Sat Aug 6 21:29:36 1994 Eric Youngdale (eric@andante) * constants.c: Fix typo (;;). - * g_NCR5380.c: + * g_NCR5380.c: * pas16.c: Correct usage of NCR5380_init. * scsi.c: Remove redundant (and unused variables). @@ -1279,7 +1284,7 @@ Sat Jul 9 15:01:03 1994 Eric Youngdale (eric@esp22) when we discover a device. Free pointer before returning. Change scsi_devices into a linked list. - * scsi.c (scan_scsis): Change to only scan one host. + * scsi.c (scan_scsis): Change to only scan one host. (scsi_dev_init): Loop over all detected hosts, and scan them. * hosts.c (scsi_init_free): Change so that number of extra bytes @@ -1331,7 +1336,7 @@ Thu Jun 16 10:31:59 1994 Eric Youngdale (eric@esp22) larger SG lists. * ultrastor.c: Changes from me - use scsi_register to register - host. Add some consistency checking, + host. Add some consistency checking, Wed Jun 1 21:12:13 1994 Eric Youngdale (eric@esp22) @@ -1447,7 +1452,7 @@ Wed Apr 13 11:33:02 1994 * Linux 1.1.3 released. * fdomain.c: Update to version 5.16 (Handle different FIFO sizes - better). + better). Fri Apr 8 08:57:19 1994 @@ -1472,7 +1477,7 @@ Sun Apr 17 00:17:39 1994 * Linux 1.0, patchlevel 9 released. * fdomain.c: Update to version 5.16 (Handle different FIFO sizes - better). + better). Thu Apr 7 08:36:20 1994 @@ -1555,7 +1560,7 @@ Tue Feb 1 15:47:43 1994 * wd7000.c (wd_bases): Fix typo in last change. -Mon Jan 24 17:37:23 1994 +Mon Jan 24 17:37:23 1994 * pl14u released. @@ -1569,25 +1574,25 @@ Mon Jan 24 17:37:23 1994 * NCR5380.c: Update from Drew - should work a lot better now. -Sat Jan 8 15:13:10 1994 +Sat Jan 8 15:13:10 1994 * pl14o released. * sr_ioctl.c: Zero reserved field before trying to set audio volume. -Wed Jan 5 13:21:10 1994 +Wed Jan 5 13:21:10 1994 * pl14m released. * fdomain.c: Update to version 5.8. No functional difference??? -Tue Jan 4 14:26:13 1994 +Tue Jan 4 14:26:13 1994 * pl14l released. * ultrastor.c: Remove outl, inl functions (now provided elsewhere). -Mon Jan 3 12:27:25 1994 +Mon Jan 3 12:27:25 1994 * pl14k released. @@ -1595,7 +1600,7 @@ Mon Jan 3 12:27:25 1994 * fdomain.c: Ditto. -Wed Dec 29 09:47:20 1993 +Wed Dec 29 09:47:20 1993 * pl14i released. @@ -1603,7 +1608,7 @@ Wed Dec 29 09:47:20 1993 * st.c: Update of tape driver from Kai. -Tue Dec 21 09:18:30 1993 +Tue Dec 21 09:18:30 1993 * pl14g released. @@ -1617,11 +1622,11 @@ Tue Dec 21 09:18:30 1993 do not report this properly). Set needs_sector_size flag if drive did not return sensible sector size. -Mon Dec 13 12:13:47 1993 +Mon Dec 13 12:13:47 1993 * aha152x.c: Update to version .101 from Juergen. -Mon Nov 29 03:03:00 1993 +Mon Nov 29 03:03:00 1993 * linux 0.99.14 released. @@ -1655,7 +1660,7 @@ Mon Nov 29 03:03:00 1993 * hosts.c: Support new low-level adapters. Allow for more than one adapter of a given type. - * hosts.h: Allow for more than one adapter of a given type. + * hosts.h: Allow for more than one adapter of a given type. * scsi.c: Add scsi_device_types array, if NEEDS_JUMPSTART is set after a low-level reset, start the command again. Sort blacklist, @@ -1699,7 +1704,7 @@ Mon Nov 29 03:03:00 1993 wd7000.c: Supply jumpstart flag for reset. Do not round up number of cylinders in biosparam function. -Sat Sep 4 20:49:56 1993 +Sat Sep 4 20:49:56 1993 * 0.99pl13 released. @@ -1721,7 +1726,7 @@ Sat Sep 4 20:49:56 1993 * st.c: Change sense to unsigned. -Thu Aug 5 11:59:18 1993 +Thu Aug 5 11:59:18 1993 * 0.99pl12 released. @@ -1775,7 +1780,7 @@ Thu Aug 5 11:59:18 1993 unchecked_isa_dma flag, even though this may not be needed (gets set later). -Sat Jul 17 18:32:44 1993 +Sat Jul 17 18:32:44 1993 * 0.99pl11 released. C++ compilable. @@ -1807,7 +1812,7 @@ Sat Jul 17 18:32:44 1993 * sr.c: Set up blocksize array for all discs. Fix bug in freeing buffers if we run out of dma pool. -Thu Jun 2 17:58:11 1993 +Thu Jun 2 17:58:11 1993 * 0.99pl10 released. @@ -1833,7 +1838,7 @@ Thu Jun 2 17:58:11 1993 * wd7000.c: Allow another condition for power on that are normal and do not require a panic. -Thu Apr 22 23:10:11 1993 +Thu Apr 22 23:10:11 1993 * 0.99pl9 released. @@ -1848,7 +1853,7 @@ Thu Apr 22 23:10:11 1993 * scsi_ioctl.c: Further bugfix to ioctl_probe. * sd.c: Use long instead of int for last parameter in sd_ioctl. - Initialize transfersize and underflow fields. + Initialize transfersize and underflow fields. * sd_ioctl.c: Ditto for sd_ioctl(,,,,); @@ -1866,7 +1871,7 @@ Thu Apr 22 23:10:11 1993 * wd7000.c: Change () to (void) in wd7000_enable_dma. -Wed Mar 31 16:36:25 1993 +Wed Mar 31 16:36:25 1993 * 0.99pl8 released. @@ -1912,7 +1917,7 @@ Wed Mar 31 16:36:25 1993 -Sat Mar 13 17:31:29 1993 +Sat Mar 13 17:31:29 1993 * 0.99pl7 released. @@ -1928,7 +1933,7 @@ Sat Mar 13 17:31:29 1993 * ultrastor.c: Update to use scatter-gather. -Sat Feb 20 17:57:15 1993 +Sat Feb 20 17:57:15 1993 * 0.99pl6 released. @@ -1943,7 +1948,7 @@ Sat Feb 20 17:57:15 1993 * wd7000.c: Undo previous change. -Sat Feb 6 11:20:43 1993 +Sat Feb 6 11:20:43 1993 * 0.99pl5 released. @@ -1952,7 +1957,7 @@ Sat Feb 6 11:20:43 1993 * wd7000.c: Check at more addresses for bios. Fix bug in biosparam (heads & sectors turned around). -Wed Jan 20 18:13:59 1993 +Wed Jan 20 18:13:59 1993 * 0.99pl4 released. @@ -1965,7 +1970,7 @@ Wed Jan 20 18:13:59 1993 with Syquest cartridge drives (used to crash kernel), because they do not disconnect with large data transfers. -Tue Jan 12 14:33:36 1993 +Tue Jan 12 14:33:36 1993 * 0.99pl3 released. @@ -1980,7 +1985,7 @@ Tue Jan 12 14:33:36 1993 * st.c: Changes from Kai. -Wed Dec 30 20:03:47 1992 +Wed Dec 30 20:03:47 1992 * 0.99pl2 released. @@ -2001,7 +2006,7 @@ Wed Dec 30 20:03:47 1992 * wd7000.c (wd7000_set_sync): Remove redundant function. -Sun Dec 20 16:26:24 1992 +Sun Dec 20 16:26:24 1992 * 0.99pl1 released. @@ -2013,6 +2018,6 @@ Sun Dec 20 16:26:24 1992 * st.c: Patches from Kai - change timeout values, improve end of tape handling. -Sun Dec 13 18:15:23 1992 +Sun Dec 13 18:15:23 1992 * 0.99 kernel released. Baseline for this ChangeLog. diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h index fe3812043ecc..2689083586ff 100644 --- a/drivers/scsi/a2091.h +++ b/drivers/scsi/a2091.h @@ -1,6 +1,6 @@ #ifndef A2091_H -/* $Id: a2091.h,v 1.4 1996/04/25 20:57:48 root Exp root $ +/* $Id: a2091.h,v 1.4 1997/01/19 23:07:09 davem Exp $ * * Header file for the Commodore A2091 Zorro II SCSI controller for Linux * @@ -34,7 +34,7 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); extern struct proc_dir_entry proc_scsi_a2091; #define A2091_SCSI { /* next */ NULL, \ - /* usage_count */ NULL, \ + /* module */ NULL, \ /* proc_dir_entry */ &proc_scsi_a2091, \ /* proc_info */ NULL, \ /* name */ "Commodore A2091/A590 SCSI", \ @@ -59,7 +59,7 @@ extern struct proc_dir_entry proc_scsi_a2091; /* * if the transfer address ANDed with this results in a non-zero * result, then we can't use DMA. - */ + */ #define A2091_XFER_MASK (0xff000001) typedef struct { diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h index 52ae6aad96ae..1b13557b9b2b 100644 --- a/drivers/scsi/a3000.h +++ b/drivers/scsi/a3000.h @@ -1,6 +1,6 @@ #ifndef A3000_H -/* $Id: a3000.h,v 1.3 1996/04/25 20:58:09 root Exp root $ +/* $Id: a3000.h,v 1.4 1997/01/19 23:07:10 davem Exp $ * * Header file for the Amiga 3000 built-in SCSI controller for Linux * @@ -34,7 +34,7 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); extern struct proc_dir_entry proc_scsi_a3000; #define A3000_SCSI { /* next */ NULL, \ - /* usage_count */ NULL, \ + /* module */ NULL, \ /* proc_dir_entry */ &proc_scsi_a3000, \ /* proc_info */ NULL, \ /* name */ "Amiga 3000 built-in SCSI", \ @@ -59,7 +59,7 @@ extern struct proc_dir_entry proc_scsi_a3000; /* * if the transfer address ANDed with this results in a non-zero * result, then we can't use DMA. - */ + */ #define A3000_XFER_MASK (0x00000003) typedef struct { diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h index 4683ea293adc..22f028f5c918 100644 --- a/drivers/scsi/advansys.h +++ b/drivers/scsi/advansys.h @@ -1,4 +1,4 @@ -/* $Id: advansys.h,v 1.12 1996/09/23 18:12:02 bobf Exp bobf $ */ +/* $Id: advansys.h,v 1.5 1997/01/19 23:07:10 davem Exp $ */ /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * @@ -57,7 +57,7 @@ void advansys_setup(char *, int *); #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #define ADVANSYS { \ NULL, /* struct SHT *next */ \ - NULL, /* int *usage_count */ \ + NULL, /* struct module *module */ \ "advansys", /* char *name */ \ advansys_detect, /* int (*detect)(struct SHT *) */ \ advansys_release, /* int (*release)(struct Scsi_Host *) */ \ @@ -95,7 +95,7 @@ void advansys_setup(char *, int *); #else /* version >= v1.3.0 */ #define ADVANSYS { \ NULL, /* struct SHT *next */ \ - NULL, /* long *usage_count */ \ + NULL, /* struct module *module */ \ &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ advansys_proc_info, \ /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h index a018d1ba4eda..56c56e52bf4b 100644 --- a/drivers/scsi/aha152x.h +++ b/drivers/scsi/aha152x.h @@ -2,7 +2,7 @@ #define _AHA152X_H /* - * $Id: aha152x.h,v 1.18 1996/09/07 20:10:26 fischer Exp $ + * $Id: aha152x.h,v 1.7 1997/01/19 23:07:11 davem Exp $ */ #if defined(__KERNEL__) @@ -23,13 +23,13 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int (unless we support more than 1 cmd_per_lun this should do) */ #define AHA152X_MAXQUEUE 7 -#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.18 $" +#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.7 $" extern struct proc_dir_entry proc_scsi_aha152x; /* Initial value of Scsi_Host entry */ #define AHA152X { /* next */ 0, \ - /* usage_count */ 0, \ + /* module */ 0, \ /* proc_dir */ &proc_scsi_aha152x, \ /* proc_info */ aha152x_proc_info, \ /* name */ AHA152X_REVID, \ diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h index 0479089dda81..f0584f4fa4a7 100644 --- a/drivers/scsi/esp.h +++ b/drivers/scsi/esp.h @@ -396,7 +396,7 @@ extern struct proc_dir_entry proc_scsi_esp; #define SCSI_SPARC_ESP { \ /* struct SHT *next */ NULL, \ -/* long *usage_count */ NULL, \ +/* struct module *module */ NULL, \ /* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \ /* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \ /* const char *name */ "Sun ESP 100/100a/200", \ diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h index 0e0891d4ec6a..77004d0d397e 100644 --- a/drivers/scsi/gvp11.h +++ b/drivers/scsi/gvp11.h @@ -1,6 +1,6 @@ #ifndef GVP11_H -/* $Id: gvp11.h,v 1.5 1996/04/25 20:58:31 root Exp root $ +/* $Id: gvp11.h,v 1.4 1997/01/19 23:07:12 davem Exp $ * * Header file for the GVP Series II SCSI controller for Linux * @@ -35,7 +35,7 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); extern struct proc_dir_entry proc_scsi_gvp11; #define GVP11_SCSI { /* next */ NULL, \ - /* usage_count */ NULL, \ + /* module */ NULL, \ /* proc_dir_entry */ &proc_scsi_gvp11, \ /* proc_info */ NULL, \ /* name */ "GVP Series II SCSI", \ @@ -60,7 +60,7 @@ extern struct proc_dir_entry proc_scsi_gvp11; /* * if the transfer address ANDed with this results in a non-zero * result, then we can't use DMA. - */ + */ #define GVP11_XFER_MASK (0xff000001) typedef struct { diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index 08475df6a4b2..d7e366350a04 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -1,5 +1,5 @@ /* - * hosts.h Copyright (C) 1992 Drew Eckhardt + * hosts.h Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * mid to low-level SCSI driver interface header @@ -11,7 +11,7 @@ * Modified by Eric Youngdale eric@aib.com to * add scatter-gather, multiple outstanding request, and other * enhancements. - * + * * Further modified by Eric Youngdale to support multiple host adapters * of the same type. */ @@ -20,13 +20,13 @@ #define _HOSTS_H /* - $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $ + $Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $ */ #include /* It is senseless to set SG_ALL any higher than this - the performance - * does not get any better, and it wastes memory + * does not get any better, and it wastes memory */ #define SG_NONE 0 #define SG_ALL 0xff @@ -53,18 +53,18 @@ typedef struct scsi_disk Disk; typedef struct SHT { - + /* Used with loadable modules so we can construct a linked list. */ struct SHT * next; - + /* Used with loadable modules so that we know when it is safe to unload */ - long * usage_count; - + struct module * module; + /* The pointer to the /proc/scsi directory entry */ struct proc_dir_entry *proc_dir; /* proc-fs info function. - * Can be used to export driver statistics and other infos to the world + * Can be used to export driver statistics and other infos to the world * outside the kernel ie. userspace and it also provides an interface * to feed the driver with information. Check eata_dma_proc.c for reference */ @@ -75,7 +75,7 @@ typedef struct SHT * device detected. */ const char *name; - + /* * The detect function shall return non zero on detection, * indicating the number of host adapters of this particular @@ -83,7 +83,7 @@ typedef struct SHT * initialize all data necessary for this particular * SCSI driver. It is passed the host number, so this host * knows where the first entry is in the scsi_hosts[] array. - * + * * Note that the detect routine MUST not call any of the mid level * functions to queue commands because things are not guaranteed * to be set up yet. The detect routine can send commands to @@ -91,12 +91,12 @@ typedef struct SHT * passed to scsi.c in the processing of the command. Note * especially that scsi_malloc/scsi_free must not be called. */ - int (* detect)(struct SHT *); - + int (* detect)(struct SHT *); + /* Used with loadable modules to unload the host structures. Note: * there is a default action built into the modules code which may * be sufficient for most host adapters. Thus you may not have to supply - * this at all. + * this at all. */ int (*release)(struct Scsi_Host *); @@ -106,12 +106,12 @@ typedef struct SHT * the name field will be used instead. */ const char *(* info)(struct Scsi_Host *); - + /* - * The command function takes a target, a command (this is a SCSI - * command formatted as per the SCSI spec, nothing strange), a + * The command function takes a target, a command (this is a SCSI + * command formatted as per the SCSI spec, nothing strange), a * data buffer pointer, and data buffer length pointer. The return - * is a status int, bit fielded as follows : + * is a status int, bit fielded as follows : * Byte What * 0 SCSI status code * 1 SCSI 1 byte message @@ -123,31 +123,31 @@ typedef struct SHT /* * The QueueCommand function works in a similar manner * to the command function. It takes an additional parameter, - * void (* done)(int host, int code) which is passed the host - * # and exit result when the command is complete. + * void (* done)(int host, int code) which is passed the host + * # and exit result when the command is complete. * Host number is the POSITION IN THE hosts array of THIS * host adapter. */ int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - + /* - * Since the mid level driver handles time outs, etc, we want to - * be able to abort the current command. Abort returns 0 if the + * Since the mid level driver handles time outs, etc, we want to + * be able to abort the current command. Abort returns 0 if the * abortion was successful. The field SCpnt->abort reason * can be filled in with the appropriate reason why we wanted * the abort in the first place, and this will be used * in the mid-level code instead of the host_byte(). - * If non-zero, the code passed to it - * will be used as the return code, otherwise + * If non-zero, the code passed to it + * will be used as the return code, otherwise * DID_ABORT should be returned. - * - * Note that the scsi driver should "clean up" after itself, - * resetting the bus, etc. if necessary. + * + * Note that the scsi driver should "clean up" after itself, + * resetting the bus, etc. if necessary. */ int (* abort)(Scsi_Cmnd *); /* - * The reset function will reset the SCSI bus. Any executing + * The reset function will reset the SCSI bus. Any executing * commands should fail with a DID_RESET in the host byte. * The Scsi_Cmnd is passed so that the reset routine can figure * out which host adapter should be reset, and also which command @@ -155,24 +155,24 @@ typedef struct SHT * the first place. Some hosts do not implement a reset function, * and these hosts must call scsi_request_sense(SCpnt) to keep * the command alive. - */ + */ int (* reset)(Scsi_Cmnd *, unsigned int); /* * This function is used to select synchronous communications, * which will result in a higher data throughput. Not implemented * yet. - */ + */ int (* slave_attach)(int, int); - + /* * This function determines the bios parameters for a given * harddisk. These tend to be numbers that are made up by * the host adapter. Parameters: * size, device number, list (heads, sectors, cylinders) - */ + */ int (* bios_param)(Disk *, kdev_t, int []); - + /* * This determines if we will use a non-interrupt driven * or an interrupt driven scheme, It is set to the maximum number @@ -181,10 +181,10 @@ typedef struct SHT int can_queue; /* - * In many instances, especially where disconnect / reconnect are - * supported, our host also has an ID on the SCSI bus. If this is + * In many instances, especially where disconnect / reconnect are + * supported, our host also has an ID on the SCSI bus. If this is * the case, then it must be reserved. Please set this_id to -1 if - * your setup is in single initiator mode, and the host lacks an + * your setup is in single initiator mode, and the host lacks an * ID. */ int this_id; @@ -210,13 +210,13 @@ typedef struct SHT * present contains counter indicating how many boards of this * type were found when we did the scan. */ - unsigned char present; - + unsigned char present; + /* * true if this host adapter uses unchecked DMA onto an ISA bus. */ unsigned unchecked_isa_dma:1; - + /* * true if this host adapter can make good use of clustering. * I originally thought that if the tablesize was large that it @@ -230,7 +230,7 @@ typedef struct SHT } Scsi_Host_Template; /* - * The scsi_hosts array is the array containing the data for all + * The scsi_hosts array is the array containing the data for all * possible scsi hosts. This is similar to the * Scsi_Host_Template, except that we have one entry for each * actual physical host adapter on the system, stored as a linked @@ -248,32 +248,32 @@ struct Scsi_Host struct wait_queue *host_wait; Scsi_Cmnd *host_queue; Scsi_Host_Template * hostt; - + /* * These three parameters can be used to allow for wide scsi, - * and for host adapters that support multiple busses + * and for host adapters that support multiple busses * The first two should be set to 1 more than the actual max id * or lun (i.e. 8 for normal systems). */ unsigned int max_id; unsigned int max_lun; unsigned int max_channel; - + /* * Pointer to a circularly linked list - this indicates the hosts * that should be locked out of performing I/O while we have an active - * command on this host. + * command on this host. */ struct Scsi_Host * block; unsigned wish_block:1; - + /* These parameters should be set by the detect routine */ unsigned char *base; unsigned int io_port; unsigned char n_io_port; unsigned char irq; unsigned char dma_channel; - + /* * This is a unique identifier that must be assigned so that we * have some way of identifying each detected host adapter properly @@ -282,12 +282,12 @@ struct Scsi_Host * initialized to 0 in scsi_register. */ unsigned int unique_id; - + /* * The rest can be copied from the template, or specifically * initialized, as required. */ - + int this_id; int can_queue; short cmd_per_lun; @@ -298,7 +298,7 @@ struct Scsi_Host * True if this host was loaded as a loadable module */ unsigned loaded_as_module:1; - + void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); unsigned long hostdata[0]; /* Used for storage of host specific stuff */ @@ -316,11 +316,11 @@ extern void build_proc_dir_entries(Scsi_Host_Template *); * scsi_init initializes the scsi hosts. */ -/* +/* * We use these goofy things because the MM is not set up when we init * the scsi subsystem. By using these functions we can write code that * looks normal. Also, it makes it possible to use the same code for a - * loadable module. + * loadable module. */ extern void * scsi_init_malloc(unsigned int size, int priority); @@ -340,7 +340,7 @@ struct Scsi_Device_Template struct Scsi_Device_Template * next; const char * name; const char * tag; - long * usage_count; /* Used for loadable modules */ + struct module * module; /* Used for loadable modules */ unsigned char scsi_type; unsigned char major; unsigned char nr_dev; /* Number currently attached */ @@ -375,8 +375,8 @@ extern void scsi_unregister_module(int, void *); /* * This is an ugly hack. If we expect to be able to load devices at run time, - * we need to leave extra room in some of the data structures. Doing a - * realloc to enlarge the structures would be riddled with race conditions, + * we need to leave extra room in some of the data structures. Doing a + * realloc to enlarge the structures would be riddled with race conditions, * so until a better solution is discovered, we use this crude approach */ #define SD_EXTRA_DEVS 2 diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h index 8f50f5633997..49604a85dfc7 100644 --- a/drivers/scsi/ibmmca.h +++ b/drivers/scsi/ibmmca.h @@ -2,7 +2,7 @@ #ifndef _IBMMCA_H #define _IBMMCA_H -/* +/* * Low Level Driver for the IBM Microchannel SCSI Subsystem */ @@ -20,7 +20,7 @@ extern struct proc_dir_entry proc_scsi_ibmmca; /*initialization for Scsi_host_template type */ #define IBMMCA { \ NULL, /*next*/ \ - NULL, /*usage_count*/ \ + NULL, /*module*/ \ &proc_scsi_ibmmca, /*proc_dir*/ \ NULL, /*proc info fn*/ \ "IBMMCA", /*name*/ \ diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index a8fa2ccccd94..7cbb86070eb6 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -240,7 +240,7 @@ static void idescsi_pc_intr (ide_drive_t *drive) #if IDESCSI_DEBUG_LOG printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n"); -#endif /* IDESCSI_DEBUG_LOG */ +#endif /* IDESCSI_DEBUG_LOG */ if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { #if IDESCSI_DEBUG_LOG @@ -651,7 +651,7 @@ Scsi_Host_Template idescsi_template = IDESCSI; int init_module (void) { idescsi_init (); - idescsi_template.usage_count = &__this_module.usecount; + idescsi_template.module = &__this_module; scsi_register_module (MODULE_SCSI_HA, &idescsi_template); return 0; } diff --git a/drivers/scsi/ide-scsi.h b/drivers/scsi/ide-scsi.h index 94edaa1fbce1..44b524e73e63 100644 --- a/drivers/scsi/ide-scsi.h +++ b/drivers/scsi/ide-scsi.h @@ -16,7 +16,7 @@ extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags); #define IDESCSI \ { NULL, /* next */ \ - NULL, /* usage_count */ \ + NULL, /* module */ \ NULL, /* proc_dir */ \ NULL, /* proc_info */ \ "idescsi", /* name */ \ diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h index fa8442064a28..24b1e90c5933 100644 --- a/drivers/scsi/in2000.h +++ b/drivers/scsi/in2000.h @@ -325,7 +325,7 @@ int in2000_reset(Scsi_Cmnd *, unsigned int); #define IN2000_HOST_ID 7 #define IN2000 { NULL, /* link pointer for modules */ \ - NULL, /* usage_count for modules */ \ + NULL, /* module pointer for modules */ \ &proc_scsi_in2000, /* pointer to /proc/scsi directory entry */ \ in2000_proc_info, /* pointer to proc info function */ \ "Always IN2000", /* device name */ \ diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h index 66cf495eff92..7bc9ef26b00e 100644 --- a/drivers/scsi/qlogicisp.h +++ b/drivers/scsi/qlogicisp.h @@ -74,7 +74,7 @@ extern struct proc_dir_entry proc_scsi_isp1020; #define QLOGICISP { \ /* next */ NULL, \ - /* usage_count */ NULL, \ + /* module */ NULL, \ /* proc dir */ NULL, \ /* procfs info */ NULL, \ /* name */ NULL, \ diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h index ee0b4f620163..c0996039bb7a 100644 --- a/drivers/scsi/qlogicpti.h +++ b/drivers/scsi/qlogicpti.h @@ -475,7 +475,7 @@ struct qlogicpti { unsigned char bursts; struct host_param host_param; struct dev_param dev_param[MAX_TARGETS]; - + volatile unsigned char *sreg; #define SREG_TPOWER 0x80 /* State of termpwr */ #define SREG_FUSE 0x40 /* State of on board fuse */ @@ -717,7 +717,7 @@ struct qlogicpti { #define QLOGICPTI { \ /* next */ NULL, \ - /* usage_count */ NULL, \ + /* module */ NULL, \ /* proc dir */ NULL, \ /* procfs info */ NULL, \ /* name */ NULL, \ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 504004d09ba4..916ffd3a7ff8 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -17,7 +17,7 @@ * add scatter-gather, multiple outstanding request, and other * enhancements. * - * Native multichannel, wide scsi, /proc/scsi and hot plugging + * Native multichannel, wide scsi, /proc/scsi and hot plugging * support added by Michael Neuffer * * Added request_module("scsi_hostadapter") for kerneld: @@ -64,7 +64,7 @@ #undef USE_STATIC_SCSI_MEMORY /* -static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.34 1996/11/19 11:25:50 davem Exp $"; +static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $"; */ @@ -145,18 +145,18 @@ static void resize_dma_pool(void); /* This variable is merely a hook so that we can debug the kernel with gdb. */ Scsi_Cmnd * last_cmnd = NULL; -/* This is the pointer to the /proc/scsi code. - * It is only initialized to !=0 if the scsi code is present - */ -#if CONFIG_PROC_FS -extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, - off_t offset, int length, int inout); -extern int dispatch_scsi_info(int ino, char *buffer, char **start, - off_t offset, int length, int inout); +/* This is the pointer to the /proc/scsi code. + * It is only initialized to !=0 if the scsi code is present + */ +#if CONFIG_PROC_FS +extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, + off_t offset, int length, int inout); +extern int dispatch_scsi_info(int ino, char *buffer, char **start, + off_t offset, int length, int inout); struct proc_dir_entry proc_scsi_scsi = { PROC_SCSI_SCSI, 4, "scsi", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL @@ -201,7 +201,7 @@ static void scsi_dump_status(void); /* The following devices are known not to tolerate a lun != 0 scan for * one reason or another. Some will respond to all luns, others will - * lock up. + * lock up. */ #define BLIST_NOLUN 0x01 @@ -241,11 +241,11 @@ static struct dev_info device_list[] = {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ {"RODIME","RO3000S","2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes +{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for aha152x controller, which causes * SCSI code to reset bus.*/ -{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for aha152x controller, which causes +{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for aha152x controller, which causes * SCSI code to reset bus.*/ {"SEAGATE", "ST296","921", BLIST_NOLUN}, /* Responds to all lun */ {"SEAGATE","ST1581","6538",BLIST_NOLUN}, /* Responds to all lun */ @@ -253,11 +253,11 @@ static struct dev_info device_list[] = {"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN}, {"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN}, {"TANDBERG","TDC 3600","U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ -{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes +{"TEAC","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes * SCSI code to reset bus.*/ -{"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 - * for seagate controller, which causes +{"TEXEL","CD-ROM","1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 + * for seagate controller, which causes * SCSI code to reset bus.*/ {"QUANTUM","LPS525S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ {"QUANTUM","PD1225S","3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ @@ -310,7 +310,7 @@ void scsi_make_blocked_list(void) { int block_count = 0, index; unsigned long flags; struct Scsi_Host * sh[128], * shpnt; - + /* * Create a circular linked list from the scsi hosts which have * the "wish_block" field in the Scsi_Host structure set. @@ -328,13 +328,13 @@ void scsi_make_blocked_list(void) { * * (DB, 4 Feb 1995) */ - + save_flags(flags); cli(); host_active = NULL; - + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) { - + #if 0 /* * Is this is a candidate for the blocked list? @@ -343,12 +343,12 @@ void scsi_make_blocked_list(void) { */ if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1; #endif - + if (shpnt->wish_block) sh[block_count++] = shpnt; } - + if (block_count == 1) sh[0]->block = NULL; - + else if (block_count > 1) { for(index = 0; index < block_count - 1; index++) { @@ -356,23 +356,23 @@ void scsi_make_blocked_list(void) { printk("scsi%d : added to blocked host list.\n", sh[index]->host_no); } - + sh[block_count - 1]->block = sh[0]; printk("scsi%d : added to blocked host list.\n", sh[index]->host_no); } - + restore_flags(flags); } static void scan_scsis_done (Scsi_Cmnd * SCpnt) { - + #ifdef DEBUG printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result); #endif SCpnt->request.rq_status = RQ_SCSI_DONE; - + if (SCpnt->request.sem != NULL) up(SCpnt->request.sem); } @@ -452,7 +452,7 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, (*sdtpnt->attach)(oldSDpnt); if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);} resize_dma_pool(); - + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) {(*sdtpnt->finish)();} @@ -493,14 +493,14 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, if(hqptr) { prev = hqptr->prev; next = hqptr->next; - if(prev) + if(prev) prev->next = next; - else + else shpnt->host_queue = next; if(next) next->prev = prev; } } - + /* Last device block does not exist. Free memory. */ if (SDpnt != NULL) scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device)); @@ -819,7 +819,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, static void scsi_times_out (Scsi_Cmnd * SCpnt) { - + switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) { case NORMAL_TIMEOUT: @@ -828,7 +828,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) scsi_dump_status(); #endif } - + if (!scsi_abort (SCpnt, DID_TIME_OUT)) return; case IN_ABORT: @@ -840,7 +840,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) case (IN_ABORT | IN_RESET): /* This might be controversial, but if there is a bus hang, * you might conceivably want the machine up and running - * esp if you have an ide disk. + * esp if you have an ide disk. */ printk("SCSI host %d channel %d reset (pid %ld) timed out - " "trying harder\n", @@ -862,7 +862,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET); return; - + default: printk("SCSI host %d reset (pid %ld) timed out again -\n", SCpnt->host->host_no, SCpnt->pid); @@ -870,7 +870,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) return; } - + } @@ -878,7 +878,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt) * can be queued now, or if there would be a stall while waiting for * something else to finish. This routine assumes that interrupts are * turned off when entering the routine. It is the responsibility - * of the calling code to ensure that this is the case. + * of the calling code to ensure that this is the case. */ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) @@ -887,19 +887,19 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) int tablesize; Scsi_Cmnd * found = NULL; struct buffer_head * bh, *bhp; - + if (!device) panic ("No device passed to request_queueable().\n"); - + if (req && req->rq_status == RQ_INACTIVE) panic("Inactive in request_queueable"); /* * Look for a free command block. If we have been instructed not to queue - * multiple commands to multi-lun devices, then check to see what else is + * multiple commands to multi-lun devices, then check to see what else is * going for this device first. */ - + if (!device->single_lun) { SCpnt = device->device_queue; while(SCpnt){ @@ -909,19 +909,19 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) } else { SCpnt = device->host->host_queue; while(SCpnt){ - if(SCpnt->channel == device->channel + if(SCpnt->channel == device->channel && SCpnt->target == device->id) { if (SCpnt->lun == device->lun) { - if(found == NULL - && SCpnt->request.rq_status == RQ_INACTIVE) + if(found == NULL + && SCpnt->request.rq_status == RQ_INACTIVE) { found=SCpnt; } - } + } if(SCpnt->request.rq_status != RQ_INACTIVE) { /* * I think that we should really limit things to one - * outstanding command per device - this is what tends + * outstanding command per device - this is what tends * to trip up buggy firmware. */ return NULL; @@ -931,19 +931,19 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) } SCpnt = found; } - + if (!SCpnt) return NULL; - + if (SCSI_BLOCK(device->host)) return NULL; - + if (req) { memcpy(&SCpnt->request, req, sizeof(struct request)); tablesize = device->host->sg_tablesize; bhp = bh = req->bh; if(!tablesize) bh = NULL; - /* Take a quick look through the table to see how big it is. - * We already have our copy of req, so we can mess with that - * if we want to. + /* Take a quick look through the table to see how big it is. + * We already have our copy of req, so we can mess with that + * if we want to. */ while(req->nr_sectors && bh){ bhp = bhp->b_reqnext; @@ -958,7 +958,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) req->bh = bh->b_reqnext; /* Divide request */ bh->b_reqnext = NULL; bh = req->bh; - + /* Now reset things so that req looks OK */ SCpnt->request.nr_sectors -= req->nr_sectors; req->current_nr_sectors = bh->b_size >> 9; @@ -970,10 +970,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) } } else { SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Busy, but no request */ - SCpnt->request.sem = NULL; /* And no one is waiting for the device + SCpnt->request.sem = NULL; /* And no one is waiting for the device * either */ } - + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; @@ -982,7 +982,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) /* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. - */ + */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; @@ -997,7 +997,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device) * commands for the time being. We need to keep in mind that there is no * guarantee that the host remain not busy. Keep in mind the * request_queueable function also knows the internal allocation scheme - * of the packets for each device + * of the packets for each device */ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, @@ -1012,23 +1012,23 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, Scsi_Cmnd * SCpnt = NULL; Scsi_Cmnd * SCwait = NULL; Scsi_Cmnd * found = NULL; - + if (!device) panic ("No device passed to allocate_device().\n"); - + if (reqp) req = *reqp; - + /* See if this request has already been queued by an interrupt routine */ if (req) { if(req->rq_status == RQ_INACTIVE) return NULL; dev = req->rq_dev; } else dev = 0; /* unused */ - + host = device->host; - + if (intr_count && SCSI_BLOCK(host)) return NULL; - + while (1==1){ if (!device->single_lun) { SCpnt = device->device_queue; @@ -1040,16 +1040,16 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, } else { SCpnt = device->host->host_queue; while(SCpnt){ - if(SCpnt->channel == device->channel + if(SCpnt->channel == device->channel && SCpnt->target == device->id) { if (SCpnt->lun == device->lun) { SCwait = SCpnt; - if(found == NULL - && SCpnt->request.rq_status == RQ_INACTIVE) + if(found == NULL + && SCpnt->request.rq_status == RQ_INACTIVE) { found=SCpnt; } - } + } if(SCpnt->request.rq_status != RQ_INACTIVE) { /* * I think that we should really limit things to one @@ -1094,7 +1094,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, if(!wait) return NULL; if (!SCwait) { printk("Attempt to allocate device channel %d, target" - " %d, lun %d\n", device->channel, device->id, + " %d, lun %d\n", device->channel, device->id, device->lun); panic("No device found in allocate_device\n"); } @@ -1107,9 +1107,9 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, tablesize = device->host->sg_tablesize; bhp = bh = req->bh; if(!tablesize) bh = NULL; - /* Take a quick look through the table to see how big it is. - * We already have our copy of req, so we can mess with that - * if we want to. + /* Take a quick look through the table to see how big it is. + * We already have our copy of req, so we can mess with that + * if we want to. */ while(req->nr_sectors && bh){ bhp = bhp->b_reqnext; @@ -1138,14 +1138,14 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, } } else { SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = NULL; /* And no one is waiting for this + SCpnt->request.sem = NULL; /* And no one is waiting for this * to complete */ } restore_flags(flags); break; } } - + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ SCpnt->old_use_sg = 0; SCpnt->transfersize = 0; /* No default transfer size */ @@ -1155,7 +1155,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device, /* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. - */ + */ SCpnt->channel = device->channel; SCpnt->lun = device->lun; SCpnt->target = device->id; @@ -1183,9 +1183,9 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) ret = __builtin_return_address(0); #endif #endif - + host = SCpnt->host; - + save_flags(flags); cli(); /* Assign a unique nonzero serial_number. */ @@ -1213,20 +1213,20 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) host->last_reset = jiffies - MIN_RESET_DELAY; } restore_flags(flags); - + update_timeout(SCpnt, SCpnt->timeout_per_command); - + /* * We will use a queued command if possible, otherwise we will emulate the * queuing and calling of completion function ourselves. */ #ifdef DEBUG printk("internal_cmnd (host = %d, channel = %d, target = %d, " - "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, + "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", + SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done); #endif - + if (host->can_queue) { #ifdef DEBUG @@ -1239,14 +1239,14 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) * any given time, and we can only be in the interrupt * handler and the queuecommand function at the same time * when queuecommand is called while servicing the - * interrupt. + * interrupt. */ - + if(!intr_count && SCpnt->host->irq) disable_irq(SCpnt->host->irq); - + host->hostt->queuecommand (SCpnt, scsi_done); - + if(!intr_count && SCpnt->host->irq) enable_irq(SCpnt->host->irq); } @@ -1262,7 +1262,7 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) #ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; while (jiffies < clock) barrier(); - printk("done(host = %d, result = %04x) : routine at %p\n", + printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); #endif scsi_done(SCpnt); @@ -1275,20 +1275,20 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) static void scsi_request_sense (Scsi_Cmnd * SCpnt) { unsigned long flags; - + save_flags(flags); cli(); SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; update_timeout(SCpnt, SENSE_TIMEOUT); restore_flags(flags); - - - memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, + + + memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, sizeof(generic_sense)); - + SCpnt->cmnd[1] = SCpnt->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); - + SCpnt->request_buffer = &SCpnt->sense_buffer; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); SCpnt->use_sg = 0; @@ -1311,7 +1311,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , { unsigned long flags; struct Scsi_Host * host = SCpnt->host; - + #ifdef DEBUG { int i; @@ -1319,20 +1319,20 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , printk ("scsi_do_cmd (host = %d, channel = %d target = %d, " "buffer =%p, bufflen = %d, done = %p, timeout = %d, " "retries = %d)\n" - "command : " , host->host_no, SCpnt->channel, target, buffer, + "command : " , host->host_no, SCpnt->channel, target, buffer, bufflen, done, timeout, retries); for (i = 0; i < 10; ++i) printk ("%02x ", ((unsigned char *) cmnd)[i]); printk("\n"); } #endif - + if (!host) { panic ("Invalid or not present host.\n"); } - - + + /* * We must prevent reentrancy to the lowlevel host driver. This prevents * it - we enter a loop until the host we want to talk to is not busy. @@ -1344,25 +1344,25 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , save_flags(flags); cli(); SCpnt->pid = scsi_pid++; - + while (SCSI_BLOCK(host)) { restore_flags(flags); SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host)); cli(); } - + if (host->block) host_active = host; - + host->host_busy++; restore_flags(flags); - + /* * Our own function scsi_done (which marks the host as not busy, disables * the timeout counter, etc) will be called by us or by the * scsi_hosts[host].queuecommand() function needs to also call * the completion function for the high level driver. */ - + memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12); #if 0 SCpnt->host = host; @@ -1382,7 +1382,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , memcpy ((void *) SCpnt->cmnd , (const void *) cmnd, 12); /* Zero the sense buffer. Some host adapters automatically request - * sense on error. 0 is not a valid sense code. + * sense on error. 0 is not a valid sense code. */ memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); SCpnt->request_buffer = buffer; @@ -1407,7 +1407,7 @@ static int check_sense (Scsi_Cmnd * SCpnt) { /* If there is no sense information, request it. If we have already * requested it, there is no point in asking again - the firmware must - * be confused. + * be confused. */ if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { if(!(SCpnt->flags & ASKED_FOR_SENSE)) @@ -1415,9 +1415,9 @@ static int check_sense (Scsi_Cmnd * SCpnt) else return SUGGEST_RETRY; } - + SCpnt->flags &= ~ASKED_FOR_SENSE; - + #ifdef DEBUG_INIT printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel); print_sense("", SCpnt); @@ -1425,14 +1425,14 @@ static int check_sense (Scsi_Cmnd * SCpnt) #endif if (SCpnt->sense_buffer[2] & 0xe0) return SUGGEST_ABORT; - + switch (SCpnt->sense_buffer[2] & 0xf) { case NO_SENSE: return 0; case RECOVERED_ERROR: return SUGGEST_IS_OK; - + case ABORTED_COMMAND: return SUGGEST_RETRY; case NOT_READY: @@ -1449,12 +1449,12 @@ static int check_sense (Scsi_Cmnd * SCpnt) return SUGGEST_RETRY; } return SUGGEST_ABORT; - + /* these three are not supported */ case COPY_ABORTED: case VOLUME_OVERFLOW: case MISCOMPARE: - + case MEDIUM_ERROR: return SUGGEST_REMAP; case BLANK_CHECK: @@ -1497,14 +1497,14 @@ static void scsi_done (Scsi_Cmnd * SCpnt) int result = SCpnt->result; SCpnt->serial_number = 0; oldto = update_timeout(SCpnt, 0); - + #ifdef DEBUG_TIMEOUT if(result) printk("Non-zero result in scsi_done %x %d:%d\n", result, SCpnt->target, SCpnt->lun); #endif - + /* If we requested an abort, (and we got it) then fix up the return - * status to say why + * status to say why */ if(host_byte(result) == DID_ABORT && SCpnt->abort_reason) SCpnt->result = result = (result & 0xff00ffff) | @@ -1536,12 +1536,12 @@ static void scsi_done (Scsi_Cmnd * SCpnt) #if 0 /* This cannot possibly be correct. */ SCpnt->internal_timeout &= ~SENSE_TIMEOUT; #endif - + if (!(SCpnt->flags & WAS_RESET)) { printk("scsi%d : channel %d target %d lun %d request sense" " failed, performing reset.\n", - SCpnt->host->host_no, SCpnt->channel, SCpnt->target, + SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->lun); scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); return; @@ -1568,7 +1568,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) #if 0 /* This cannot possibly be correct. */ SCpnt->internal_timeout &= ~SENSE_TIMEOUT; #endif - + switch (checked = check_sense(SCpnt)) { case SUGGEST_SENSE: @@ -1617,7 +1617,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) status = FINISHED; } break; - + case CHECK_CONDITION: case COMMAND_TERMINATED: switch (check_sense(SCpnt)) @@ -1644,18 +1644,18 @@ static void scsi_done (Scsi_Cmnd * SCpnt) break; } break; - + case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD: break; - + case BUSY: case QUEUE_FULL: update_timeout(SCpnt, oldto); status = REDO; break; - + case RESERVATION_CONFLICT: printk("scsi%d, channel %d : RESERVATION CONFLICT performing" " reset.\n", SCpnt->host->host_no, SCpnt->channel); @@ -1670,11 +1670,11 @@ static void scsi_done (Scsi_Cmnd * SCpnt) printk ("Internal error %s %d \n" "status byte = %d \n", __FILE__, __LINE__, status_byte(result)); - + } break; default: - panic("scsi: unsupported message byte %d received\n", + panic("scsi: unsupported message byte %d received\n", msg_byte(result)); } break; @@ -1682,7 +1682,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) #ifdef DEBUG printk("Host returned DID_TIME_OUT - "); #endif - + if (SCpnt->flags & WAS_TIMEDOUT) { #ifdef DEBUG @@ -1732,7 +1732,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) status = REDO; break; } - + if(msg_byte(result) == GOOD && status_byte(result) == CHECK_CONDITION) { switch (check_sense(SCpnt)) { @@ -1762,7 +1762,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) default : exit = (DRIVER_ERROR | SUGGEST_DIE); } - + switch (status) { case FINISHED: @@ -1785,7 +1785,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); break; } - + } else { @@ -1793,9 +1793,9 @@ static void scsi_done (Scsi_Cmnd * SCpnt) break; } /* fall through to REDO */ - + case REDO: - + if (SCpnt->flags & WAS_SENSE) scsi_request_sense(SCpnt); else @@ -1813,34 +1813,34 @@ static void scsi_done (Scsi_Cmnd * SCpnt) default: INTERNAL_ERROR; } - + if (status == FINISHED) { #ifdef DEBUG printk("Calling done function - at address %p\n", SCpnt->done); #endif host->host_busy--; /* Indicate that we are free */ - + if (host->block && host->host_busy == 0) { host_active = NULL; - + /* For block devices "wake_up" is done in end_scsi_request */ if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR && MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) { struct Scsi_Host * next; - + for (next = host->block; next != host; next = next->block) wake_up(&next->host_wait); } - + } - + wake_up(&host->host_wait); SCpnt->result = result | ((exit & 0xff) << 24); SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; SCpnt->done (SCpnt); } - + #undef FINISHED #undef REDO #undef MAYREDO @@ -1852,7 +1852,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) * we are aborting, and causes the current command to not complete. The * caller should deal with any error messages or status returned on the * next call. - * + * * This will not be called reentrantly for a given host. */ @@ -1868,12 +1868,12 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) int oldto; unsigned long flags; struct Scsi_Host * host = SCpnt->host; - + while(1) { save_flags(flags); cli(); - + /* * Protect against races here. If the command is done, or we are * on a different command forget it. @@ -1893,16 +1893,16 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) { SCpnt->internal_timeout |= IN_ABORT; oldto = update_timeout(SCpnt, ABORT_TIMEOUT); - + if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) { /* OK, this command must have died when we did the - * reset. The device itself must have lied. + * reset. The device itself must have lied. */ printk("Stale command on %d %d:%d appears to have died when" - " the bus was reset\n", + " the bus was reset\n", SCpnt->channel, SCpnt->target, SCpnt->lun); } - + restore_flags(flags); if (!host->host_busy) { SCpnt->internal_timeout &= ~IN_ABORT; @@ -1911,7 +1911,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) } printk("scsi : aborting command due to timeout : pid %lu, scsi%d," " channel %d, id %d, lun %d ", - SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, + SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); print_command (SCpnt->cmnd); if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) @@ -1923,7 +1923,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) * WAS_TIMEDOUT flag set so we do not try this twice */ case SCSI_ABORT_BUSY: /* Tough call - returning 1 from - * this is too severe + * this is too severe */ case SCSI_ABORT_SNOOZE: if(why == DID_TIME_OUT) { @@ -1934,7 +1934,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) restore_flags(flags); return 1; /* Indicate we cannot handle this. * We drop down into the reset handler - * and try again + * and try again */ } else { SCpnt->flags |= WAS_TIMEDOUT; @@ -1954,7 +1954,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why) return 0; case SCSI_ABORT_SUCCESS: /* We should have already aborted this one. No - * need to adjust timeout + * need to adjust timeout */ SCpnt->internal_timeout &= ~IN_ABORT; return 0; @@ -2011,7 +2011,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) printk("SCSI bus is being reset for host %d channel %d.\n", host->host_no, SCpnt->channel); - + #if 0 /* * First of all, we need to make a recommendation to the low-level @@ -2021,7 +2021,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) * to determine what we should do. */ SCpnt->host->suggest_bus_reset = FALSE; - + /* * First see if all of the active devices on the bus have * been jammed up so that we are attempting resets. If so, @@ -2047,7 +2047,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) if( SCpnt1 == NULL ) { reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET; } - + /* * If the code that called us is suggesting a hard reset, then * definitely request it. This usually occurs because a @@ -2059,7 +2059,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) SCpnt->host->suggest_bus_reset = TRUE; } #endif - + while (1) { save_flags(flags); cli(); @@ -2084,7 +2084,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) { SCpnt->internal_timeout |= IN_RESET; update_timeout(SCpnt, RESET_TIMEOUT); - + if (host->host_busy) { restore_flags(flags); @@ -2100,7 +2100,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) } SCpnt1 = SCpnt1->next; } - + host->last_reset = jiffies; temp = host->hostt->reset(SCpnt, reset_flags); /* @@ -2123,16 +2123,16 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) host->last_reset = jiffies; SCpnt->flags |= (WAS_RESET | IS_RESETTING); temp = host->hostt->reset(SCpnt, reset_flags); - if ((host->last_reset < jiffies) || + if ((host->last_reset < jiffies) || (host->last_reset > (jiffies + 20 * HZ))) host->last_reset = jiffies; if (!host->block) host->host_busy--; } - + #ifdef DEBUG printk("scsi reset function returned %d\n", temp); #endif - + /* * Now figure out what we need to do, based upon * what the low level driver said that it did. @@ -2193,7 +2193,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) SCpnt1 = host->host_queue; while(SCpnt1) { if(SCpnt1->request.rq_status != RQ_INACTIVE - && SCpnt1 != SCpnt + && SCpnt1 != SCpnt && SCpnt1->channel == SCpnt->channel) scsi_request_sense (SCpnt); SCpnt1 = SCpnt1->next; @@ -2204,7 +2204,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) /* In this case, we set the timeout field to 0 * so that this command does not time out any more, * and we return 1 so that we get a message on the - * screen. + * screen. */ save_flags(flags); cli(); @@ -2216,7 +2216,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) default: return 1; } - + return temp; } } @@ -2228,12 +2228,12 @@ static void scsi_main_timeout(void) /* * We must not enter update_timeout with a timeout condition still pending. */ - + int timed_out; unsigned long flags; struct Scsi_Host * host; Scsi_Cmnd * SCpnt = NULL; - + save_flags(flags); cli(); @@ -2323,14 +2323,14 @@ int update_timeout(Scsi_Cmnd * SCset, int timeout) */ oldto = 0; - + if(SCset){ oldto = SCset->timeout - used; SCset->timeout = timeout; } least = 0xffffffff; - + for(host = scsi_hostlist; host; host = host->next) for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next) if (SCpnt->timeout > 0) { @@ -2340,12 +2340,12 @@ int update_timeout(Scsi_Cmnd * SCset, int timeout) if(SCpnt->timeout > 0 && SCpnt->timeout < least) least = SCpnt->timeout; } - + /* * If something is due to timeout again, then we will set the next timeout * interrupt to occur. Otherwise, timeouts are disabled. */ - + if (least != 0xffffffff) { time_start = jiffies; @@ -2373,12 +2373,12 @@ void *scsi_malloc(unsigned int len) int i, j; if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE) return NULL; - + save_flags(flags); cli(); nbits = len >> 9; mask = (1 << nbits) - 1; - + for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++) for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){ if ((dma_malloc_freelist[i] & (mask << j)) == 0){ @@ -2410,7 +2410,7 @@ int scsi_free(void *obj, unsigned int len) #endif printk("scsi_free %p %d\n",obj, len); #endif - + for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; if ((unsigned long) obj >= page_addr && @@ -2426,10 +2426,10 @@ int scsi_free(void *obj, unsigned int len) save_flags(flags); cli(); - if((dma_malloc_freelist[page] & + if((dma_malloc_freelist[page] & (mask << sector)) != (mask<host; int j; - Scsi_Cmnd * SCpnt; + Scsi_Cmnd * SCpnt; if (SDpnt->queue_depth == 0) SDpnt->queue_depth = host->cmd_per_lun; SDpnt->device_queue = NULL; - + for(j=0;jqueue_depth;j++){ SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), @@ -2531,7 +2531,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt) /* * scsi_dev_init() is our initialization routine, which in turn calls host - * initialization, bus scanning, and sd/st initialization routines. + * initialization, bus scanning, and sd/st initialization routines. */ int scsi_dev_init(void) @@ -2544,19 +2544,19 @@ int scsi_dev_init(void) #endif /* Yes we're here... */ -#if CONFIG_PROC_FS +#if CONFIG_PROC_FS dispatch_scsi_info_ptr = dispatch_scsi_info; #endif /* Init a few things so we can "malloc" memory. */ scsi_loadable_module_flag = 0; - + timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].expires = 0; /* Register the /proc/scsi/scsi entry */ -#if CONFIG_PROC_FS - proc_scsi_register(0, &proc_scsi_scsi); +#if CONFIG_PROC_FS + proc_scsi_register(0, &proc_scsi_scsi); #endif /* initialize all hosts */ @@ -2576,7 +2576,7 @@ int scsi_dev_init(void) printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name, (sdtpnt->dev_noticed != 1) ? "s" : ""); printk("total.\n"); - + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); @@ -2586,7 +2586,7 @@ int scsi_dev_init(void) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); if(SDpnt->attached) scsi_build_commandblocks(SDpnt); } - + /* * This should build the DMA pool. @@ -2595,7 +2595,7 @@ int scsi_dev_init(void) /* * OK, now we finish the initialization by doing spin-up, read - * capacity, etc, etc + * capacity, etc, etc */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->finish && sdtpnt->nr_dev) @@ -2609,7 +2609,7 @@ int scsi_dev_init(void) static void print_inquiry(unsigned char *data) { int i; - + printk(" Vendor: "); for (i = 8; i < 16; i++) { @@ -2618,7 +2618,7 @@ static void print_inquiry(unsigned char *data) else printk(" "); } - + printk(" Model: "); for (i = 16; i < 32; i++) { @@ -2627,7 +2627,7 @@ static void print_inquiry(unsigned char *data) else printk(" "); } - + printk(" Rev: "); for (i = 32; i < 36; i++) { @@ -2636,11 +2636,11 @@ static void print_inquiry(unsigned char *data) else printk(" "); } - + printk("\n"); - + i = data[0] & 0x1f; - + printk(" Type: %s ", i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " ); printk(" ANSI SCSI revision: %02x", data[2] & 0x07); @@ -2652,7 +2652,7 @@ static void print_inquiry(unsigned char *data) #ifdef CONFIG_PROC_FS -int scsi_proc_info(char *buffer, char **start, off_t offset, int length, +int scsi_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { Scsi_Cmnd *SCpnt; @@ -2668,24 +2668,24 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, scd = scsi_devices; HBA_ptr = scsi_hostlist; - if(inout == 0) { + if(inout == 0) { size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none"); - len += size; + len += size; pos = begin + len; while (HBA_ptr) { #if 0 - size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, + size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, HBA_ptr->hostt->procname); - len += size; + len += size; pos = begin + len; #endif scd = scsi_devices; while (scd) { if (scd->host == HBA_ptr) { proc_print_scsidevice(scd, buffer, &size, len); - len += size; + len += size; pos = begin + len; - + if (pos < offset) { len = 0; begin = pos; @@ -2697,13 +2697,13 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, } HBA_ptr = HBA_ptr->next; } - + stop_output: *start=buffer+(offset-begin); /* Start of wanted data */ len-=(offset-begin); /* Start slop */ if(len>length) len = length; /* Ending slop */ - return (len); + return (len); } if(!buffer || length < 25 || strncmp("scsi", buffer, 4)) @@ -2715,9 +2715,9 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, * Consider this feature BETA. * CAUTION: This is not for hotplugging your peripherals. As * SCSI was not designed for this you could damage your - * hardware ! + * hardware ! * However perhaps it is legal to switch on an - * already connected device. It is perhaps not + * already connected device. It is perhaps not * guaranteed this device doesn't corrupt an ongoing data transfer. */ if(!strncmp("add-single-device", buffer + 5, 17)) { @@ -2731,9 +2731,9 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, printk("scsi singledevice %d %d %d %d\n", host, channel, id, lun); - while(scd && (scd->host->host_no != host - || scd->channel != channel - || scd->id != id + while(scd && (scd->host->host_no != host + || scd->channel != channel + || scd->id != id || scd->lun != lun)) { scd = scd->next; } @@ -2747,8 +2747,8 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, scan_scsis (HBA_ptr, 1, channel, id, lun); return(length); - - } + + } /* * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi @@ -2758,40 +2758,40 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, * * CAUTION: This is not for hotplugging your peripherals. As * SCSI was not designed for this you could damage your - * hardware and thoroughly confuse the SCSI subsystem. + * hardware and thoroughly confuse the SCSI subsystem. * */ else if(!strncmp("remove-single-device", buffer + 5, 20)) { p = buffer + 26; - + host = simple_strtoul(p, &p, 0); channel = simple_strtoul(p+1, &p, 0); id = simple_strtoul(p+1, &p, 0); lun = simple_strtoul(p+1, &p, 0); - + while(scd != NULL) { - if(scd->host->host_no == host - && scd->channel == channel - && scd->id == id + if(scd->host->host_no == host + && scd->channel == channel + && scd->id == id && scd->lun == lun){ - break; + break; } scd_h = scd; scd = scd->next; } - + if(scd == NULL) return(-ENODEV); /* there is no such device attached */ - + if(scd->access_count) return(-EBUSY); - + SDTpnt = scsi_devicelist; while(SDTpnt != NULL) { if(SDTpnt->detach) (*SDTpnt->detach)(scd); SDTpnt = SDTpnt->next; } - + if(scd->attached == 0) { /* * Nobody is using this device any more. @@ -2814,7 +2814,7 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, } else if (scsi_devices == scd) { /* We had a hit on the first entry of the device list */ scsi_devices = scd->next; - } + } scsi_init_free((char *) scd, sizeof(Scsi_Device)); } else { return(-EBUSY); @@ -2865,24 +2865,24 @@ static void resize_dma_pool(void) return; } /* Next, check to see if we need to extend the DMA buffer pool */ - + new_dma_sectors = 2*SECTORS_PER_PAGE; /* Base value we use */ if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD) scsi_need_isa_bounce_buffers = 1; else scsi_need_isa_bounce_buffers = 0; - + if (scsi_devicelist) for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) new_dma_sectors += SECTORS_PER_PAGE; /* Increment for each host */ - + for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) { host = SDpnt->host; /* * sd and sr drivers allocate scatterlists. - * sr drivers may allocate for each command 1x2048 or 2x1024 extra + * sr drivers may allocate for each command 1x2048 or 2x1024 extra * buffers for 2k sector size and 1k fs. * sg driver allocates buffers < 4k. * st driver does not need buffers from the dma pool. @@ -2921,7 +2921,7 @@ static void resize_dma_pool(void) /* limit DMA memory to 32MB: */ new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; - + /* * We never shrink the buffers - this leads to * race conditions that I would rather not even think @@ -2929,7 +2929,7 @@ static void resize_dma_pool(void) */ if( new_dma_sectors < dma_sectors ) new_dma_sectors = dma_sectors; - + if (new_dma_sectors) { size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); @@ -2940,7 +2940,7 @@ static void resize_dma_pool(void) new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC); memset(new_dma_malloc_pages, 0, size); } - + /* * If we need more buffers, expand the list. */ @@ -2949,9 +2949,9 @@ static void resize_dma_pool(void) new_dma_malloc_pages[i] = (unsigned char *) scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); } - - /* When we dick with the actual DMA list, we need to - * protect things + + /* When we dick with the actual DMA list, we need to + * protect things */ save_flags(flags); cli(); @@ -2962,14 +2962,14 @@ static void resize_dma_pool(void) scsi_init_free((char *) dma_malloc_freelist, size); } dma_malloc_freelist = new_dma_malloc_freelist; - + if (dma_malloc_pages) { size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages); memcpy(new_dma_malloc_pages, dma_malloc_pages, size); scsi_init_free((char *) dma_malloc_pages, size); } - + dma_free_sectors += new_dma_sectors - dma_sectors; dma_malloc_pages = new_dma_malloc_pages; dma_sectors = new_dma_sectors; @@ -2996,9 +2996,9 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) Scsi_Device * SDpnt; struct Scsi_Device_Template * sdtpnt; const char * name; - + if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or - * no detect routine available + * no detect routine available */ pcount = next_scsi_host; if ((tpnt->present = tpnt->detect(tpnt))) @@ -3010,18 +3010,18 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) return 1; } /* The low-level driver failed to register a driver. We - * can do this now. + * can do this now. */ scsi_register(tpnt,0); } tpnt->next = scsi_hosts; /* Add to the linked list */ scsi_hosts = tpnt; - + /* Add the new driver to /proc/scsi */ -#if CONFIG_PROC_FS +#if CONFIG_PROC_FS build_proc_dir_entries(tpnt); #endif - + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) if(shpnt->hostt == tpnt) { @@ -3032,28 +3032,28 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) printk ("scsi%d : %s\n", /* And print a little message */ shpnt->host_no, name); } - + printk ("scsi : %d host%s.\n", next_scsi_host, (next_scsi_host == 1) ? "" : "s"); - + scsi_make_blocked_list(); - + /* The next step is to call scan_scsis here. This generates the - * Scsi_Devices entries + * Scsi_Devices entries */ - + for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) if(shpnt->hostt == tpnt) { scan_scsis(shpnt,0,0,0,0); if (shpnt->select_queue_depths != NULL) (shpnt->select_queue_depths)(shpnt, scsi_devices); } - + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - + /* Next we create the Scsi_Cmnd structures for this host */ - + for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) if(SDpnt->host->hostt == tpnt) { @@ -3061,7 +3061,7 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); if(SDpnt->attached) scsi_build_commandblocks(SDpnt); } - + /* * Now that we have all of the devices, resize the DMA pool, * as required. */ @@ -3073,14 +3073,14 @@ static int scsi_register_host(Scsi_Host_Template * tpnt) if(sdtpnt->finish && sdtpnt->nr_dev) (*sdtpnt->finish)(); } - + #if defined(USE_STATIC_SCSI_MEMORY) printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, (scsi_init_memory_start - scsi_memory_lower_value) / 1024, (scsi_memory_upper_value - scsi_init_memory_start) / 1024); #endif - + MOD_INC_USE_COUNT; return 0; } @@ -3098,14 +3098,14 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) struct Scsi_Device_Template * sdtpnt; struct Scsi_Host * shpnt, *sh1; int pcount; - + /* First verify that this host adapter is completely free with no pending * commands */ - + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) - if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count - && *sdpnt->host->hostt->usage_count) return; - + if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module + && sdpnt->host->hostt->module->usecount) return; + for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { if (shpnt->hostt != tpnt) continue; @@ -3126,7 +3126,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) } } /* Next we detach the high level drivers from the Scsi_Device structures */ - + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) if(sdpnt->host->hostt == tpnt) { @@ -3138,9 +3138,9 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) return; } } - + /* Next we free up the Scsi_Cmnd structures for this host */ - + for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) if(sdpnt->host->hostt == tpnt) while (sdpnt->host->host_queue) { @@ -3150,9 +3150,9 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) if (SCpnt) SCpnt->prev = NULL; sdpnt->has_cmdblocks = 0; } - + /* Next free up the Scsi_Device structures for this host */ - + sdppnt = NULL; for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1) { @@ -3166,10 +3166,10 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) } else sdppnt = sdpnt; } - + /* Next we go through and remove the instances of the individual hosts * that were detected */ - + shpnt = scsi_hostlist; while(shpnt) { sh1 = shpnt->next; @@ -3177,16 +3177,16 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) if(shpnt->loaded_as_module) { pcount = next_scsi_host; /* Remove the /proc/scsi directory entry */ -#if CONFIG_PROC_FS - proc_scsi_unregister(tpnt->proc_dir, +#if CONFIG_PROC_FS + proc_scsi_unregister(tpnt->proc_dir, shpnt->host_no + PROC_SCSI_FILE); -#endif +#endif if(tpnt->release) (*tpnt->release)(shpnt); else { - /* This is the default case for the release function. - * It should do the right thing for most correctly - * written host adapters. + /* This is the default case for the release function. + * It should do the right thing for most correctly + * written host adapters. */ if (shpnt->irq) free_irq(shpnt->irq, NULL); if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel); @@ -3199,7 +3199,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) } shpnt = sh1; } - + /* * If there are absolutely no more hosts left, it is safe * to completely nuke the DMA pool. The resize operation will @@ -3210,20 +3210,20 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) printk ("scsi : %d host%s.\n", next_scsi_host, (next_scsi_host == 1) ? "" : "s"); - + #if defined(USE_STATIC_SCSI_MEMORY) printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", (scsi_memory_upper_value - scsi_memory_lower_value) / 1024, (scsi_init_memory_start - scsi_memory_lower_value) / 1024, (scsi_memory_upper_value - scsi_init_memory_start) / 1024); #endif - + scsi_make_blocked_list(); - + /* There were some hosts that were loaded at boot time, so we cannot do any more than this */ if (tpnt->present) return; - + /* OK, this is the very last step. Remove this host adapter from the linked list. */ for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next) @@ -3235,9 +3235,9 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) SHT->next = NULL; break; } - + /* Rebuild the /proc/scsi directory entries */ -#if CONFIG_PROC_FS +#if CONFIG_PROC_FS proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino); #endif MOD_DEC_USE_COUNT; @@ -3250,24 +3250,24 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) { Scsi_Device * SDpnt; - + if (tpnt->next) return 1; - + scsi_register_device(tpnt); /* * First scan the devices that we know about, and see if we notice them. */ - + for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt); - + /* * If any of the devices would match this driver, then perform the * init function. */ if(tpnt->init && tpnt->dev_noticed) if ((*tpnt->init)()) return 1; - + /* * Now actually connect the devices to the new driver. */ @@ -3281,9 +3281,9 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt) if(SDpnt->attached && SDpnt->has_cmdblocks == 0) scsi_build_commandblocks(SDpnt); } - + /* - * This does any final handling that is required. + * This does any final handling that is required. */ if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)(); MOD_INC_USE_COUNT; @@ -3296,15 +3296,16 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) Scsi_Cmnd * SCpnt; struct Scsi_Device_Template * spnt; struct Scsi_Device_Template * prev_spnt; - + /* * If we are busy, this is not going to fly. */ - if( *tpnt->usage_count != 0) return 0; + if(tpnt->module->usecount != 0) return 0; + /* * Next, detach the devices from the driver. */ - + for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next) { if(tpnt->detach) (*tpnt->detach)(SDpnt); @@ -3344,10 +3345,10 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) scsi_devicelist = tpnt->next; else prev_spnt->next = spnt->next; - + MOD_DEC_USE_COUNT; /* - * Final cleanup for the driver is done in the driver sources in the + * Final cleanup for the driver is done in the driver sources in the * cleanup function. */ return 0; @@ -3359,7 +3360,7 @@ int scsi_register_module(int module_type, void * ptr) switch(module_type){ case MODULE_SCSI_HA: return scsi_register_host((Scsi_Host_Template *) ptr); - + /* Load upper level device handler of some kind */ case MODULE_SCSI_DEV: #ifdef CONFIG_KERNELD @@ -3368,14 +3369,14 @@ int scsi_register_module(int module_type, void * ptr) #endif return scsi_register_device_module((struct Scsi_Device_Template *) ptr); /* The rest of these are not yet implemented */ - + /* Load constants.o */ case MODULE_SCSI_CONST: - - /* Load specialized ioctl handler for some device. Intended for + + /* Load specialized ioctl handler for some device. Intended for * cdroms that have non-SCSI2 audio command sets. */ case MODULE_SCSI_IOCTL: - + default: return 1; } @@ -3478,14 +3479,14 @@ int init_module(void) { proc_scsi_register(0, &proc_scsi_scsi); #endif - + dma_sectors = PAGE_SIZE / SECTOR_SIZE; dma_free_sectors= dma_sectors; /* * Set up a minimal DMA buffer list - this will be used during scan_scsis * in some cases. */ - + /* One bit per sector to indicate free/busy */ size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); dma_malloc_freelist = (unsigned char *) scsi_init_malloc(size, GFP_ATOMIC); @@ -3499,7 +3500,7 @@ int init_module(void) { return 0; } -void cleanup_module( void) +void cleanup_module( void) { #if CONFIG_PROC_FS proc_scsi_unregister(0, PROC_SCSI_SCSI); diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c index 644327d34d53..5316e2e642ee 100644 --- a/drivers/scsi/scsi_module.c +++ b/drivers/scsi/scsi_module.c @@ -32,7 +32,7 @@ #include int init_module(void) { - driver_template.usage_count = &__this_module.usecount; + driver_template.module = &__this_module; scsi_register_module(MODULE_SCSI_HA, &driver_template); return (driver_template.present == 0); } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e20baf99e0c1..2a18071ca007 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1,9 +1,9 @@ /* - * sd.c Copyright (C) 1992 Drew Eckhardt + * sd.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * Linux scsi disk driver - * Initial versions: Drew Eckhardt + * Initial versions: Drew Eckhardt * Subsequent revisions: Eric Youngdale * * @@ -87,8 +87,8 @@ static int sd_attach(Scsi_Device *); static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); -struct Scsi_Device_Template sd_template = -{ NULL, "disk", "sd", NULL, TYPE_DISK, +struct Scsi_Device_Template sd_template = +{ NULL, "disk", "sd", NULL, TYPE_DISK, SCSI_DISK_MAJOR, 0, 0, 0, 1, sd_detect, sd_init, sd_finish, sd_attach, sd_detach @@ -98,21 +98,21 @@ static int sd_open(struct inode * inode, struct file * filp) { int target; target = DEVICE_NR(inode->i_rdev); - + if(target >= sd_template.dev_max || !rscsi_disks[target].device) return -ENXIO; /* No such device */ - - /* + + /* * Make sure that only one process can do a check_change_disk at one time. - * This is also used to lock out further access when the partition table - * is being re-read. + * This is also used to lock out further access when the partition table + * is being re-read. */ - + while (rscsi_disks[target].device->busy) - barrier(); + barrier(); if(rscsi_disks[target].device->removable) { check_disk_change(inode->i_rdev); - + /* * If the drive is empty, just let the open fail. */ @@ -134,15 +134,16 @@ static int sd_open(struct inode * inode, struct file * filp) */ if(sd_sizes[MINOR(inode->i_rdev)] == 0) return -ENXIO; - + if(rscsi_disks[target].device->removable) if(!rscsi_disks[target].device->access_count) sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); rscsi_disks[target].device->access_count++; - if (rscsi_disks[target].device->host->hostt->usage_count) - (*rscsi_disks[target].device->host->hostt->usage_count)++; - if(sd_template.usage_count) (*sd_template.usage_count)++; + if (rscsi_disks[target].device->host->hostt->module) + __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if(sd_template.module) + __MOD_INC_USE_COUNT(sd_template.module); return 0; } @@ -150,18 +151,20 @@ static void sd_release(struct inode * inode, struct file * file) { int target; fsync_dev(inode->i_rdev); - + target = DEVICE_NR(inode->i_rdev); - + rscsi_disks[target].device->access_count--; - if (rscsi_disks[target].device->host->hostt->usage_count) - (*rscsi_disks[target].device->host->hostt->usage_count)--; - if(sd_template.usage_count) (*sd_template.usage_count)--; - + if(rscsi_disks[target].device->removable) { if(!rscsi_disks[target].device->access_count) sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); } + + if(rscsi_disks[target].device->host->hostt->module) + __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); + if(sd_template.module) + __MOD_DEC_USE_COUNT(sd_template.module); } static void sd_geninit(struct gendisk *); @@ -199,9 +202,9 @@ static struct gendisk sd_gendisk = { static void sd_geninit (struct gendisk *ignored) { int i; - + for (i = 0; i < sd_template.dev_max; ++i) - if(rscsi_disks[i].device) + if(rscsi_disks[i].device) sd[i << 4].nr_sects = rscsi_disks[i].capacity; #if 0 /* No longer needed - we keep track of this as we attach/detach */ @@ -221,9 +224,9 @@ static void rw_intr (Scsi_Cmnd *SCpnt) int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 1; - + #ifdef DEBUG - printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev), + printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev), SCpnt->host->host_no, result); #endif @@ -258,15 +261,15 @@ static void rw_intr (Scsi_Cmnd *SCpnt) if (good_sectors < 0 || good_sectors >= this_count) good_sectors = 0; } - + /* - * First case : we assume that the command succeeded. One of two things + * First case : we assume that the command succeeded. One of two things * will happen here. Either we will be finished, or there will be more * sectors that we were unable to read last time. */ if (good_sectors > 0) { - + #ifdef DEBUG printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev), SCpnt->request.nr_sectors); @@ -278,25 +281,25 @@ static void rw_intr (Scsi_Cmnd *SCpnt) sgpnt = (struct scatterlist *) SCpnt->buffer; for(i=0; iuse_sg; i++) { #ifdef DEBUG - printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, + printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); #endif if (sgpnt[i].alt_address) { if (SCpnt->request.cmd == READ) - memcpy(sgpnt[i].alt_address, sgpnt[i].address, + memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); scsi_free(sgpnt[i].address, sgpnt[i].length); } } /* Free list of scatter-gather pointers */ - scsi_free(SCpnt->buffer, SCpnt->sglist_len); + scsi_free(SCpnt->buffer, SCpnt->sglist_len); } else { if (SCpnt->buffer != SCpnt->request.buffer) { #ifdef DEBUG printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen); -#endif +#endif if (SCpnt->request.cmd == READ) memcpy(SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen); @@ -311,7 +314,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) if (SCpnt->request.nr_sectors > this_count) { SCpnt->request.errors = 0; - + if (!SCpnt->request.bh) { #ifdef DEBUG @@ -319,7 +322,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) 'a' + MINOR(SCpnt->request.rq_dev)); #endif /* - * The SCpnt->request.nr_sectors field is always done in + * The SCpnt->request.nr_sectors field is always done in * 512 byte sectors, even if this really isn't the case. */ panic("sd.c: linked page request (%lx %x)", @@ -333,7 +336,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) return; } } - + if (good_sectors == 0) { /* Free up any indirection buffers we allocated for DMA purposes. */ @@ -381,13 +384,13 @@ static void rw_intr (Scsi_Cmnd *SCpnt) else #endif } - + if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { if(rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) { /* detected disc change. set a bit and quietly refuse * further access. - */ + */ rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; SCpnt = end_scsi_request(SCpnt, 0, this_count); requeue_sd_request(SCpnt); @@ -405,13 +408,13 @@ static void rw_intr (Scsi_Cmnd *SCpnt) } } } - - + + /* If we had an ILLEGAL REQUEST returned, then we may have - * performed an unsupported command. The only thing this should be + * performed an unsupported command. The only thing this should be * would be a ten byte read where only a six byte read was supported. - * Also, on a system where READ CAPACITY failed, we have have read - * past the end of the disk. + * Also, on a system where READ CAPACITY failed, we have have read + * past the end of the disk. */ if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { @@ -426,7 +429,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, + SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); print_command(SCpnt->cmnd); print_sense("sd", SCpnt); @@ -441,7 +444,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel, rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id, rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result); - + if (driver_byte(result) & DRIVER_SENSE) print_sense("sd", SCpnt); SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); @@ -463,7 +466,7 @@ static void do_sd_request (void) struct request * req = NULL; unsigned long flags; int flag = 0; - + save_flags(flags); while (1==1){ cli(); @@ -471,10 +474,10 @@ static void do_sd_request (void) restore_flags(flags); return; } - + INIT_SCSI_REQUEST; SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device; - + /* * I am not sure where the best place to do this is. We need * to hook in a place where we are likely to come if in user @@ -497,25 +500,25 @@ static void do_sd_request (void) } SDev->was_reset = 0; } - + /* We have to be careful here. allocate_device will get a free pointer, - * but there is no guarantee that it is queueable. In normal usage, - * we want to call this, because other types of devices may have the - * host all tied up, and we want to make sure that we have at least - * one request pending for this type of device. We can also come - * through here while servicing an interrupt, because of the need to - * start another command. If we call allocate_device more than once, - * then the system can wedge if the command is not queueable. The - * request_queueable function is safe because it checks to make sure + * but there is no guarantee that it is queueable. In normal usage, + * we want to call this, because other types of devices may have the + * host all tied up, and we want to make sure that we have at least + * one request pending for this type of device. We can also come + * through here while servicing an interrupt, because of the need to + * start another command. If we call allocate_device more than once, + * then the system can wedge if the command is not queueable. The + * request_queueable function is safe because it checks to make sure * that the host is able to take another command before it returns - * a pointer. + * a pointer. */ if (flag++ == 0) SCpnt = allocate_device(&CURRENT, - rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); + rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); else SCpnt = NULL; - + /* * The following restore_flags leads to latency problems. FIXME. * Using a "sti()" gets rid of the latency problems but causes @@ -523,13 +526,13 @@ static void do_sd_request (void) */ restore_flags(flags); - /* This is a performance enhancement. We dig down into the request - * list and try to find a queueable request (i.e. device not busy, - * and host able to accept another command. If we find one, then we - * queue it. This can make a big difference on systems with more than - * one disk drive. We want to have the interrupts off when monkeying - * with the request list, because otherwise the kernel might try to - * slip in a request in between somewhere. + /* This is a performance enhancement. We dig down into the request + * list and try to find a queueable request (i.e. device not busy, + * and host able to accept another command. If we find one, then we + * queue it. This can make a big difference on systems with more than + * one disk drive. We want to have the interrupts off when monkeying + * with the request list, because otherwise the kernel might try to + * slip in a request in between somewhere. */ if (!SCpnt && sd_template.nr_dev > 1){ @@ -538,27 +541,27 @@ static void do_sd_request (void) cli(); req = CURRENT; while(req){ - SCpnt = request_queueable(req, + SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(req->rq_dev)].device); if(SCpnt) break; req1 = req; req = req->next; } if (SCpnt && req->rq_status == RQ_INACTIVE) { - if (req == CURRENT) + if (req == CURRENT) CURRENT = CURRENT->next; else req1->next = req->next; } restore_flags(flags); } - + if (!SCpnt) return; /* Could not find anything to do */ - + /* Queue command */ requeue_sd_request(SCpnt); } /* While */ -} +} static void requeue_sd_request (Scsi_Cmnd * SCpnt) { @@ -568,14 +571,14 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) int max_sg; struct buffer_head * bh, *bhp; char * buff, *bounce_buffer; - + repeat: - + if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { do_sd_request(); return; } - + devm = MINOR(SCpnt->request.rq_dev); dev = DEVICE_NR(SCpnt->request.rq_dev); @@ -585,33 +588,33 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) #ifdef DEBUG printk("Doing sd request, dev = %d, block = %d\n", devm, block); #endif - - if (devm >= (sd_template.dev_max << 4) || + + if (devm >= (sd_template.dev_max << 4) || !rscsi_disks[dev].device || block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; } - + block += sd[devm].start_sect; - + if (rscsi_disks[dev].device->changed) { /* - * quietly refuse to do anything to a changed disc until the changed + * quietly refuse to do anything to a changed disc until the changed * bit has been reset */ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; } - + #ifdef DEBUG - printk("sd%c : real dev = /dev/sd%c, block = %d\n", + printk("sd%c : real dev = /dev/sd%c, block = %d\n", 'a' + devm, dev, block); #endif - + /* * If we have a 1K hardware sectorsize, prevent access to single * 512 byte sectors. In theory we could handle this - in fact @@ -629,7 +632,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; } - + switch (SCpnt->request.cmd) { case WRITE : @@ -646,71 +649,71 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) default : panic ("Unknown sd command %d\n", SCpnt->request.cmd); } - + SCpnt->this_count = 0; - + /* If the host adapter can deal with very large scatter-gather - * requests, it is a waste of time to cluster + * requests, it is a waste of time to cluster */ contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1); bounce_buffer = NULL; bounce_size = (SCpnt->request.nr_sectors << 9); - - /* First see if we need a bounce buffer for this request. If we do, make - * sure that we can allocate a buffer. Do not waste space by allocating - * a bounce buffer if we are straddling the 16Mb line - */ + + /* First see if we need a bounce buffer for this request. If we do, make + * sure that we can allocate a buffer. Do not waste space by allocating + * a bounce buffer if we are straddling the 16Mb line + */ if (contiguous && SCpnt->request.bh && - virt_to_phys(SCpnt->request.bh->b_data) - + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD + virt_to_phys(SCpnt->request.bh->b_data) + + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) { if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD) bounce_buffer = (char *) scsi_malloc(bounce_size); if(!bounce_buffer) contiguous = 0; } - + if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext) - for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, + for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, bhp = bhp->b_reqnext) { - if(!CONTIGUOUS_BUFFERS(bh,bhp)) { + if(!CONTIGUOUS_BUFFERS(bh,bhp)) { if(bounce_buffer) scsi_free(bounce_buffer, bounce_size); contiguous = 0; break; - } + } } if (!SCpnt->request.bh || contiguous) { - + /* case of page request (i.e. raw device), or unlinked buffer */ this_count = SCpnt->request.nr_sectors; buff = SCpnt->request.buffer; SCpnt->use_sg = 0; - + } else if (SCpnt->host->sg_tablesize == 0 || (need_isa_buffer && dma_free_sectors <= 10)) { - + /* Case of host adapter that cannot scatter-gather. We also * come here if we are running low on DMA buffer memory. We set * a threshold higher than that we would need for this request so * we leave room for other requests. Even though we would not need * it all, we need to be conservative, because if we run low enough - * we have no choice but to panic. + * we have no choice but to panic. */ if (SCpnt->host->sg_tablesize != 0 && - need_isa_buffer && + need_isa_buffer && dma_free_sectors <= 10) printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n"); - + this_count = SCpnt->request.current_nr_sectors; buff = SCpnt->request.buffer; SCpnt->use_sg = 0; - + } else { - + /* Scatter-gather capable host adapter */ struct scatterlist * sgpnt; int count, this_count_max; int counted; - + bh = SCpnt->request.bh; this_count = 0; this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff); @@ -739,7 +742,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) SCpnt->sglist_len = count; max_sg = count / sizeof(struct scatterlist); - if(SCpnt->host->sg_tablesize < max_sg) + if(SCpnt->host->sg_tablesize < max_sg) max_sg = SCpnt->host->sg_tablesize; sgpnt = (struct scatterlist * ) scsi_malloc(count); if (!sgpnt) { @@ -749,37 +752,37 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) buff = SCpnt->request.buffer; } else { memset(sgpnt, 0, count); /* Zero so it is easy to fill, but only - * if memory is available + * if memory is available */ buff = (char *) sgpnt; counted = 0; for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext; - count < SCpnt->use_sg && bh; + count < SCpnt->use_sg && bh; count++, bh = bhp) { - + bhp = bh->b_reqnext; - + if(!sgpnt[count].address) sgpnt[count].address = bh->b_data; sgpnt[count].length += bh->b_size; counted += bh->b_size >> 9; - + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && !sgpnt[count].alt_address) { sgpnt[count].alt_address = sgpnt[count].address; - /* We try to avoid exhausting the DMA pool, since it is - * easier to control usage here. In other places we might - * have a more pressing need, and we would be screwed if + /* We try to avoid exhausting the DMA pool, since it is + * easier to control usage here. In other places we might + * have a more pressing need, and we would be screwed if * we ran out */ if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) { sgpnt[count].address = NULL; } else { - sgpnt[count].address = + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); } - /* If we start running low on DMA buffers, we abort the - * scatter-gather operation, and free all of the memory - * we have allocated. We want to ensure that all scsi + /* If we start running low on DMA buffers, we abort the + * scatter-gather operation, and free all of the memory + * we have allocated. We want to ensure that all scsi * operations are able to do at least a non-scatter/gather * operation */ if(sgpnt[count].address == NULL){ /* Out of dma memory */ @@ -787,8 +790,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) printk("Warning: Running low on SCSI DMA buffers"); /* Try switching back to a non s-g operation. */ while(--count >= 0){ - if(sgpnt[count].alt_address) - scsi_free(sgpnt[count].address, + if(sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, sgpnt[count].length); } this_count = SCpnt->request.current_nr_sectors; @@ -799,25 +802,25 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) SCpnt->use_sg = count; this_count = counted -= bh->b_size >> 9; break; - } + } } - - /* Only cluster buffers if we know that we can supply DMA + + /* Only cluster buffers if we know that we can supply DMA * buffers large enough to satisfy the request. Do not cluster - * a new request if this would mean that we suddenly need to + * a new request if this would mean that we suddenly need to * start using DMA bounce buffers */ - if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) + if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) && CLUSTERABLE_DEVICE(SCpnt)) { char * tmp; - + if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length + - bhp->b_size - 1 > ISA_DMA_THRESHOLD && + bhp->b_size - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) && !sgpnt[count].alt_address) continue; - + if(!sgpnt[count].alt_address) {count--; continue; } if(dma_free_sectors > 10) - tmp = (char *) scsi_malloc(sgpnt[count].length + tmp = (char *) scsi_malloc(sgpnt[count].length + bhp->b_size); else { tmp = NULL; @@ -829,24 +832,24 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) count--; continue; } - - /* If we are allowed another sg chain, then increment - * counter so we can insert it. Otherwise we will end + + /* If we are allowed another sg chain, then increment + * counter so we can insert it. Otherwise we will end up truncating */ - + if (SCpnt->use_sg < max_sg) SCpnt->use_sg++; } /* contiguous buffers */ } /* for loop */ - + /* This is actually how many we are going to transfer */ - this_count = counted; - - if(count < SCpnt->use_sg || SCpnt->use_sg + this_count = counted; + + if(count < SCpnt->use_sg || SCpnt->use_sg > SCpnt->host->sg_tablesize){ bh = SCpnt->request.bh; - printk("Use sg, count %d %x %d\n", + printk("Use sg, count %d %x %d\n", SCpnt->use_sg, count, dma_free_sectors); - printk("maxsg = %x, counted = %d this_count = %d\n", + printk("maxsg = %x, counted = %d this_count = %d\n", max_sg, counted, this_count); while(bh){ printk("[%p %lx] ", bh->b_data, bh->b_size); @@ -860,19 +863,19 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) sgpnt[count].length); panic("Ooops"); } - + if (SCpnt->request.cmd == WRITE) for(count=0; countuse_sg; count++) if(sgpnt[count].alt_address) - memcpy(sgpnt[count].address, sgpnt[count].alt_address, + memcpy(sgpnt[count].address, sgpnt[count].alt_address, sgpnt[count].length); } /* Able to malloc sgpnt */ } /* Host adapter capable of scatter-gather */ - + /* Now handle the possibility of DMA to addresses > 16Mb */ - + if(SCpnt->use_sg == 0){ - if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && + if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma)) { if(bounce_buffer) buff = bounce_buffer; @@ -888,31 +891,31 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) } } #ifdef DEBUG - printk("sd%c : %s %d/%d 512 byte blocks.\n", + printk("sd%c : %s %d/%d 512 byte blocks.\n", 'a' + devm, (SCpnt->request.cmd == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors); #endif - + cmd[1] = (SCpnt->lun << 5) & 0xe0; - + if (rscsi_disks[dev].sector_size == 1024){ if(block & 1) panic("sd.c:Bad block number requested"); if(this_count & 1) panic("sd.c:Bad block number requested"); block = block >> 1; this_count = this_count >> 1; } - + if (rscsi_disks[dev].sector_size == 256){ block = block << 1; this_count = this_count << 1; } - + if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) { if (this_count > 0xffff) this_count = 0xffff; - + cmd[0] += READ_10 - READ_6 ; cmd[2] = (unsigned char) (block >> 24) & 0xff; cmd[3] = (unsigned char) (block >> 16) & 0xff; @@ -926,26 +929,26 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) { if (this_count > 0xff) this_count = 0xff; - + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); cmd[2] = (unsigned char) ((block >> 8) & 0xff); cmd[3] = (unsigned char) block & 0xff; cmd[4] = (unsigned char) this_count; cmd[5] = 0; } - + /* - * We shouldn't disconnect in the middle of a sector, so with a dumb - * host adapter, it's safe to assume that we can at least transfer - * this many bytes between each connect / disconnect. + * We shouldn't disconnect in the middle of a sector, so with a dumb + * host adapter, it's safe to assume that we can at least transfer + * this many bytes between each connect / disconnect. */ - + SCpnt->transfersize = rscsi_disks[dev].sector_size; - SCpnt->underflow = this_count << 9; - scsi_do_cmd (SCpnt, (void *) cmd, buff, + SCpnt->underflow = this_count << 9; + scsi_do_cmd (SCpnt, (void *) cmd, buff, this_count * rscsi_disks[dev].sector_size, - rw_intr, - (SCpnt->device->type == TYPE_DISK ? + rw_intr, + (SCpnt->device->type == TYPE_DISK ? SD_TIMEOUT : SD_MOD_TIMEOUT), MAX_RETRIES); } @@ -955,37 +958,37 @@ static int check_scsidisk_media_change(kdev_t full_dev){ int target; struct inode inode; int flag = 0; - + target = DEVICE_NR(full_dev); - + if (target >= sd_template.dev_max || !rscsi_disks[target].device) { printk("SCSI disk request error: invalid device.\n"); return 0; } - + if(!rscsi_disks[target].device->removable) return 0; - + inode.i_rdev = full_dev; /* This is all we really need here */ retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0); - + if(retval){ /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ - + rscsi_disks[target].ready = 0; rscsi_disks[target].device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ } - - /* + + /* * for removable scsi disk ( FLOPTICAL ) we have to recognise the * presence of disk in the drive. This is kept in the Scsi_Disk - * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) + * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) */ - + rscsi_disks[target].ready = 1; /* FLOPTICAL */ retval = rscsi_disks[target].device->changed; @@ -996,10 +999,10 @@ static int check_scsidisk_media_change(kdev_t full_dev){ static void sd_init_done (Scsi_Cmnd * SCpnt) { struct request * req; - + req = &SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - + if (req->sem != NULL) { up(req->sem); } @@ -1012,17 +1015,17 @@ static int sd_init_onedisk(int i) unsigned long spintime; int the_result, retries; Scsi_Cmnd * SCpnt; - - /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is - * considered a fatal error, and many devices report such an error - * just after a scsi bus reset. + + /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is + * considered a fatal error, and many devices report such an error + * just after a scsi bus reset. */ - + SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1); buffer = (unsigned char *) scsi_malloc(512); - + spintime = 0; - + /* Spin up drives, as required. Only do this at boot time */ if (!MODULE_FLAG){ do{ @@ -1054,10 +1057,10 @@ static int sd_init_onedisk(int i) || SCpnt->sense_buffer[2] != UNIT_ATTENTION) break; } - - /* Look for non-removable devices that return NOT_READY. + + /* Look for non-removable devices that return NOT_READY. * Issue command to spin up drive for these cases. */ - if(the_result && !rscsi_disks[i].device->removable && + if(the_result && !rscsi_disks[i].device->removable && SCpnt->sense_buffer[2] == NOT_READY) { unsigned long time1; if(!spintime){ @@ -1070,11 +1073,11 @@ static int sd_init_onedisk(int i) SCpnt->cmd_len = 0; SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; - + { struct semaphore sem = MUTEX_LOCKED; /* Mark as really busy again */ - SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.sem = &sem; scsi_do_cmd (SCpnt, (void *) cmd, (void *) buffer, @@ -1082,10 +1085,10 @@ static int sd_init_onedisk(int i) MAX_RETRIES); down(&sem); } - + spintime = jiffies; } - + time1 = jiffies + HZ; while(jiffies < time1); /* Wait 1 second for next try */ printk( "." ); @@ -1098,7 +1101,7 @@ static int sd_init_onedisk(int i) printk( "ready\n" ); } } /* !MODULE_FLAG */ - + retries = 3; do { cmd[0] = READ_CAPACITY; @@ -1120,32 +1123,32 @@ static int sd_init_onedisk(int i) MAX_RETRIES); down(&sem); /* sleep until it is ready */ } - + the_result = SCpnt->result; retries--; - + } while(the_result && retries); - + SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ - - wake_up(&SCpnt->device->device_wait); - + + wake_up(&SCpnt->device->device_wait); + /* Wake up a process waiting for device */ - + /* - * The SCSI standard says: + * The SCSI standard says: * "READ CAPACITY is necessary for self configuring software" * While not mandatory, support of READ CAPACITY is strongly encouraged. * We used to die if we couldn't successfully do a READ CAPACITY. * But, now we go on about our way. The side effects of this are * - * 1. We can't know block size with certainty. I have said "512 bytes + * 1. We can't know block size with certainty. I have said "512 bytes * is it" as this is most common. * - * 2. Recovery from when some one attempts to read past the end of the + * 2. Recovery from when some one attempts to read past the end of the * raw device will be slower. */ - + if (the_result) { printk ("sd%c : READ CAPACITY failed.\n" @@ -1157,27 +1160,27 @@ static int sd_init_onedisk(int i) driver_byte(the_result) ); if (driver_byte(the_result) & DRIVER_SENSE) - printk("sd%c : extended sense code = %1x \n", + printk("sd%c : extended sense code = %1x \n", 'a' + i, SCpnt->sense_buffer[2] & 0xf); else printk("sd%c : sense not available. \n", 'a' + i); - + printk("sd%c : block size assumed to be 512 bytes, disk size 1GB. \n", 'a' + i); rscsi_disks[i].capacity = 0x1fffff; rscsi_disks[i].sector_size = 512; - + /* Set dirty bit for removable devices if not ready - sometimes drives * will not report this properly. */ - if(rscsi_disks[i].device->removable && + if(rscsi_disks[i].device->removable && SCpnt->sense_buffer[2] == NOT_READY) rscsi_disks[i].device->changed = 1; - + } else { /* - * FLOPTICAL , if read_capa is ok , drive is assumed to be ready + * FLOPTICAL , if read_capa is ok , drive is assumed to be ready */ rscsi_disks[i].ready = 1; @@ -1185,7 +1188,7 @@ static int sd_init_onedisk(int i) (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); - + rscsi_disks[i].sector_size = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; @@ -1193,8 +1196,8 @@ static int sd_init_onedisk(int i) rscsi_disks[i].sector_size = 512; printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i); } - - + + if (rscsi_disks[i].sector_size != 512 && rscsi_disks[i].sector_size != 1024 && rscsi_disks[i].sector_size != 256) @@ -1230,7 +1233,7 @@ static int sd_init_onedisk(int i) sz_rem = m - (10 * sz_quot); printk ("SCSI device sd%c: hdwr sector= %d bytes." " Sectors= %d [%d MB] [%d.%1d GB]\n", - i+'a', hard_sector, rscsi_disks[i].capacity, + i+'a', hard_sector, rscsi_disks[i].capacity, mb, sz_quot, sz_rem); } if(rscsi_disks[i].sector_size == 1024) @@ -1238,7 +1241,7 @@ static int sd_init_onedisk(int i) if(rscsi_disks[i].sector_size == 256) rscsi_disks[i].capacity >>= 1; /* Change into 512 byte sectors */ } - + /* * Unless otherwise specified, this is not write protected. @@ -1247,13 +1250,13 @@ static int sd_init_onedisk(int i) if ( rscsi_disks[i].device->removable && rscsi_disks[i].ready ) { /* FLOPTICAL */ - /* - * for removable scsi disk ( FLOPTICAL ) we have to recognise + /* + * for removable scsi disk ( FLOPTICAL ) we have to recognise * the Write Protect Flag. This flag is kept in the Scsi_Disk struct * and tested at open ! * Daniel Roche ( dan@lectra.fr ) */ - + memset ((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; @@ -1274,11 +1277,11 @@ static int sd_init_onedisk(int i) MAX_RETRIES); down(&sem); } - + the_result = SCpnt->result; SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ - wake_up(&SCpnt->device->device_wait); - + wake_up(&SCpnt->device->device_wait); + if ( the_result ) { printk ("sd%c: test WP failed, assume Write Protected\n",i+'a'); rscsi_disks[i].write_prot = 1; @@ -1287,9 +1290,9 @@ static int sd_init_onedisk(int i) printk ("sd%c: Write Protect is %s\n",i+'a', rscsi_disks[i].write_prot ? "on" : "off"); } - + } /* check for write protect */ - + rscsi_disks[i].ten = 1; rscsi_disks[i].remap = 1; scsi_free(buffer, 512); @@ -1306,9 +1309,9 @@ static int sd_registered = 0; static int sd_init() { int i; - + if (sd_template.dev_noticed == 0) return 0; - + if(!sd_registered) { if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) { printk("Unable to get major %d for SCSI disk\n",MAJOR_NR); @@ -1316,26 +1319,26 @@ static int sd_init() } sd_registered++; } - + /* We do not support attaching loadable devices yet. */ if(rscsi_disks) return 0; - + sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; - - rscsi_disks = (Scsi_Disk *) + + rscsi_disks = (Scsi_Disk *) scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); - - sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * + + sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); - - sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * + + sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - - sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * + + sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - + for(i=0;i<(sd_template.dev_max << 4);i++){ sd_blocksizes[i] = 1024; sd_hardsizes[i] = 512; @@ -1345,8 +1348,8 @@ static int sd_init() sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(struct hd_struct), GFP_ATOMIC); - - + + sd_gendisk.max_nr = sd_template.dev_max; sd_gendisk.part = sd; sd_gendisk.sizes = sd_sizes; @@ -1359,12 +1362,12 @@ static void sd_finish() int i; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - + sd_gendisk.next = gendisk_head; gendisk_head = &sd_gendisk; - + for (i = 0; i < sd_template.dev_max; ++i) - if (!rscsi_disks[i].capacity && + if (!rscsi_disks[i].capacity && rscsi_disks[i].device) { if (MODULE_FLAG @@ -1377,10 +1380,10 @@ static void sd_finish() i=sd_init_onedisk(i); rscsi_disks[i].has_part_table = 1; } - + /* If our host adapter is capable of scatter-gather, then we increase * the read-ahead to 16 blocks (32 sectors). If not, we use - * a two block (4 sector) read ahead. + * a two block (4 sector) read ahead. */ if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize) read_ahead[MAJOR_NR] = 120; /* 120 sector read-ahead */ @@ -1392,31 +1395,31 @@ static void sd_finish() static int sd_detect(Scsi_Device * SDp){ if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - - printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n", + + printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n", SDp->removable ? "removable " : "", 'a'+ (sd_template.dev_noticed++), - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + return 1; } static int sd_attach(Scsi_Device * SDp){ Scsi_Disk * dpnt; int i; - + if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - + if(sd_template.nr_dev >= sd_template.dev_max) { SDp->attached--; return 1; } - - for(dpnt = rscsi_disks, i=0; idevice) break; - + if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)"); - + SDp->scsi_request_fn = do_sd_request; rscsi_disks[i].device = SDp; rscsi_disks[i].has_part_table = 0; @@ -1445,10 +1448,10 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){ int max_p; int start; int i; - + target = DEVICE_NR(dev); gdev = &GENDISK_STRUCT; - + save_flags(flags); cli(); if (DEVICE_BUSY || USAGE > maxusage) { @@ -1458,10 +1461,10 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){ } DEVICE_BUSY = 1; restore_flags(flags); - + max_p = gdev->max_p; start = target << gdev->minor_shift; - + for (i=max_p - 1; i >=0 ; i--) { int minor = start+i; kdev_t devi = MKDEV(MAJOR_NR, minor); @@ -1476,14 +1479,14 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){ */ blksize_size[MAJOR_NR][minor] = 1024; } - + #ifdef MAYBE_REINIT MAYBE_REINIT; #endif - + gdev->part[start].nr_sects = CAPACITY; resetup_one_dev(gdev, target); - + DEVICE_BUSY = 0; return 0; } @@ -1499,15 +1502,15 @@ static void sd_detach(Scsi_Device * SDp) int i; int max_p; int start; - - for(dpnt = rscsi_disks, i=0; idevice == SDp) { - - /* If we are disconnecting a disk driver, sync and invalidate + + /* If we are disconnecting a disk driver, sync and invalidate * everything */ max_p = sd_gendisk.max_p; start = i << sd_gendisk.minor_shift; - + for (i=max_p - 1; i >=0 ; i--) { int minor = start+i; kdev_t devi = MKDEV(MAJOR_NR, minor); @@ -1518,7 +1521,7 @@ static void sd_detach(Scsi_Device * SDp) sd_gendisk.part[minor].nr_sects = 0; sd_sizes[minor] = 0; } - + dpnt->has_part_table = 0; dpnt->device = NULL; dpnt->capacity = 0; @@ -1534,28 +1537,28 @@ static void sd_detach(Scsi_Device * SDp) #ifdef MODULE int init_module(void) { - sd_template.usage_count = &__this_module.usecount; + sd_template.module = &__this_module; return scsi_register_module(MODULE_SCSI_DEV, &sd_template); } -void cleanup_module( void) +void cleanup_module( void) { struct gendisk * prev_sdgd; struct gendisk * sdgd; - + scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); unregister_blkdev(SCSI_DISK_MAJOR, "sd"); sd_registered--; if( rscsi_disks != NULL ) { scsi_init_free((char *) rscsi_disks, - (sd_template.dev_noticed + SD_EXTRA_DEVS) + (sd_template.dev_noticed + SD_EXTRA_DEVS) * sizeof(Scsi_Disk)); - + scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd, + scsi_init_free((char *) sd, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); /* * Now remove sd_gendisk from the linked list @@ -1567,7 +1570,7 @@ void cleanup_module( void) prev_sdgd = sdgd; sdgd = sdgd->next; } - + if(sdgd != &sd_gendisk) printk("sd_gendisk not in disk chain.\n"); else { @@ -1577,10 +1580,10 @@ void cleanup_module( void) gendisk_head = sdgd->next; } } - + blksize_size[MAJOR_NR] = NULL; blk_dev[MAJOR_NR].request_fn = NULL; - blk_size[MAJOR_NR] = NULL; + blk_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; sd_template.dev_max = 0; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 1bcb065e9ee2..963e909b50be 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1,9 +1,9 @@ /* * History: - * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), + * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), * to allow user process control of SCSI devices. * Development Sponsored by Killy Corp. NY NY - * + * * Borrows code from st driver. */ #include @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,7 @@ static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); -struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, +struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, SCSI_GENERIC_MAJOR, 0, 0, 0, 0, sg_detect, sg_init, NULL, sg_attach, sg_detach}; @@ -129,7 +130,7 @@ static int sg_open(struct inode * inode, struct file * filp) * that other processes know that we have it, and initialize the * state variables to known values. */ - if (!scsi_generics[dev].users + if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete) { @@ -140,9 +141,10 @@ static int sg_open(struct inode * inode, struct file * filp) } if (!scsi_generics[dev].users) scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT; - if (scsi_generics[dev].device->host->hostt->usage_count) - (*scsi_generics[dev].device->host->hostt->usage_count)++; - if(sg_template.usage_count) (*sg_template.usage_count)++; + if (scsi_generics[dev].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + if (sg_template.module) + __MOD_INC_USE_COUNT(sg_template.module); scsi_generics[dev].users++; return 0; } @@ -151,9 +153,10 @@ static void sg_close(struct inode * inode, struct file * filp) { int dev=MINOR(inode->i_rdev); scsi_generics[dev].users--; - if (scsi_generics[dev].device->host->hostt->usage_count) - (*scsi_generics[dev].device->host->hostt->usage_count)--; - if(sg_template.usage_count) (*sg_template.usage_count)--; + if (scsi_generics[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); + if(sg_template.module) + __MOD_DEC_USE_COUNT(sg_template.module); scsi_generics[dev].exclude=0; wake_up(&scsi_generics[dev].generic_wait); } @@ -174,11 +177,11 @@ static char *sg_malloc(int size) big_inuse=1; return big_buff; } -#endif +#endif return NULL; } -static void sg_free(char *buff,int size) +static void sg_free(char *buff,int size) { #ifdef SG_BIG_BUFF if (buff==big_buff) @@ -243,7 +246,7 @@ static long sg_read(struct inode *inode,struct file *filp,char *buf,unsigned lon } else count= device->header.result==0 ? 0 : -EIO; - + /* * Clean up, and release the device so that we can send another * command. @@ -283,14 +286,14 @@ static void sg_command_done(Scsi_Cmnd * SCpnt) break; case DID_NO_CONNECT: case DID_BUS_BUSY: - case DID_TIME_OUT: + case DID_TIME_OUT: device->header.result = EBUSY; break; - case DID_BAD_TARGET: - case DID_ABORT: - case DID_PARITY: + case DID_BAD_TARGET: + case DID_ABORT: + case DID_PARITY: case DID_RESET: - case DID_BAD_INTR: + case DID_BAD_INTR: device->header.result = EIO; break; case DID_ERROR: @@ -328,12 +331,12 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig int input_size; unsigned char opcode; Scsi_Cmnd * SCpnt; - + if ((i=verify_area(VERIFY_READ,buf,count))) return i; /* * The minimum scsi command length is 6 bytes. If we get anything - * less than this, it is clearly bogus. + * less than this, it is clearly bogus. */ if (count<(sizeof(struct sg_header) + 6)) return -EIO; @@ -349,7 +352,7 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig return -EAGAIN; #ifdef DEBUG printk("sg_write: sleeping on pending request\n"); -#endif +#endif interruptible_sleep_on(&device->write_wait); if (current->signal & ~current->blocked) return -ERESTARTSYS; @@ -382,7 +385,7 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig } else { bsize = device->header.reply_len; } - + /* * Don't include the command header itself in the size. */ @@ -398,7 +401,7 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig wake_up( &device->write_wait ); return -EIO; } - + /* * Allocate a buffer that is large enough to hold the data * that has been requested. Round up to an even number of sectors, @@ -434,10 +437,10 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig sg_free(device->buff,device->buff_len); device->buff = NULL; return -EAGAIN; - } + } #ifdef DEBUG printk("device allocated\n"); -#endif +#endif SCpnt->request.rq_dev = devt; SCpnt->request.rq_status = RQ_ACTIVE; @@ -456,7 +459,7 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig * so we need to subtract these off. */ if (input_size > 0) copy_from_user(device->buff, buf, input_size); - + /* * Set the LUN field in the command structure. */ @@ -477,36 +480,25 @@ static long sg_write(struct inode *inode,struct file *filp,const char *buf,unsig #ifdef DEBUG printk("done cmd\n"); -#endif +#endif return count; } -static int sg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +static unsigned int sg_poll(struct file *file, poll_table * wait) { - int dev=MINOR(inode->i_rdev); - int r = 0; - struct scsi_generic *device=&scsi_generics[dev]; + int dev = MINOR(file->f_inode->i_rdev); + struct scsi_generic *device = &scsi_generics[dev]; + unsigned int mask = 0; - if (sel_type == SEL_IN) { + poll_wait(&scsi_generics[dev].read_wait, wait); + poll_wait(&scsi_generics[dev].write_wait, wait); if(device->pending && device->complete) - { - r = 1; - } else { - select_wait(&scsi_generics[dev].read_wait, wait); - } - } - if (sel_type == SEL_OUT) { - if(!device->pending){ - r = 1; - } - else - { - select_wait(&scsi_generics[dev].write_wait, wait); - } - } + mask |= POLLIN | POLLRDNORM; + if(!device->pending) + mask |= POLLOUT | POLLWRNORM; - return(r); + return mask; } static struct file_operations sg_fops = { @@ -514,7 +506,7 @@ static struct file_operations sg_fops = { sg_read, /* read */ sg_write, /* write */ NULL, /* readdir */ - sg_select, /* select */ + sg_poll, /* poll */ sg_ioctl, /* ioctl */ NULL, /* mmap */ sg_open, /* open */ @@ -531,7 +523,7 @@ static int sg_detect(Scsi_Device * SDp){ case TYPE_ROM: case TYPE_WORM: case TYPE_TAPE: break; - default: + default: printk("Detected scsi generic sg%c at scsi%d, channel %d, id %d, lun %d\n", 'a'+sg_template.dev_noticed, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); @@ -544,11 +536,11 @@ static int sg_detect(Scsi_Device * SDp){ static int sg_init() { static int sg_registered = 0; - + if (sg_template.dev_noticed == 0) return 0; - + if(!sg_registered) { - if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk("Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); @@ -556,24 +548,24 @@ static int sg_init() } sg_registered++; } - + /* If we have already been through here, return */ if(scsi_generics) return 0; - + #ifdef DEBUG printk("sg: Init generic device.\n"); #endif - + #ifdef SG_BIG_BUFF big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); #endif - - scsi_generics = (struct scsi_generic *) - scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) + + scsi_generics = (struct scsi_generic *) + scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) * sizeof(struct scsi_generic), GFP_ATOMIC); memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS) * sizeof(struct scsi_generic)); - + sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } @@ -582,18 +574,18 @@ static int sg_attach(Scsi_Device * SDp) { struct scsi_generic * gpnt; int i; - - if(sg_template.nr_dev >= sg_template.dev_max) + + if(sg_template.nr_dev >= sg_template.dev_max) { SDp->attached--; return 1; } - - for(gpnt = scsi_generics, i=0; idevice) break; - + if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); - + scsi_generics[i].device=SDp; scsi_generics[i].users=0; scsi_generics[i].generic_wait=NULL; @@ -613,14 +605,14 @@ static void sg_detach(Scsi_Device * SDp) { struct scsi_generic * gpnt; int i; - - for(gpnt = scsi_generics, i=0; idevice == SDp) { gpnt->device = NULL; SDp->attached--; sg_template.nr_dev--; - /* - * avoid associated device /dev/sg? bying incremented + /* + * avoid associated device /dev/sg? bying incremented * each time module is inserted/removed , */ sg_template.dev_noticed--; @@ -632,18 +624,18 @@ static void sg_detach(Scsi_Device * SDp) #ifdef MODULE int init_module(void) { - sg_template.usage_count = &__this_module.usecount; + sg_template.module = &__this_module; return scsi_register_module(MODULE_SCSI_DEV, &sg_template); } -void cleanup_module( void) +void cleanup_module( void) { scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); - + if(scsi_generics != NULL) { scsi_init_free((char *) scsi_generics, - (sg_template.dev_noticed + SG_EXTRA_DEVS) + (sg_template.dev_noticed + SG_EXTRA_DEVS) * sizeof(struct scsi_generic)); } sg_template.dev_max = 0; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 22a7cc17c719..aabf418546a3 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -3,7 +3,7 @@ * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * adapted from: - * sd.c Copyright (C) 1992 Drew Eckhardt + * sd.c Copyright (C) 1992 Drew Eckhardt * Linux scsi disk driver by * Drew Eckhardt * @@ -54,7 +54,7 @@ static int sr_attach(Scsi_Device *); static int sr_detect(Scsi_Device *); static void sr_detach(Scsi_Device *); -struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, +struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, SCSI_CDROM_MAJOR, 0, 0, 0, 1, sr_detect, sr_init, sr_finish, sr_attach, sr_detach}; @@ -74,9 +74,10 @@ static void sr_release(struct cdrom_device_info *cdi) { sync_dev(cdi->dev); scsi_CDs[MINOR(cdi->dev)].device->access_count--; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count) - (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)--; - if(sr_template.usage_count) (*sr_template.usage_count)--; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + if(sr_template.module) + __MOD_DEC_USE_COUNT(sr_template.module); } static struct cdrom_device_ops sr_dops = { @@ -116,21 +117,21 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot){ /* no changer support */ return -EINVAL; } - + retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, SCSI_IOCTL_TEST_UNIT_READY, 0); - + if(retval){ /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ - + scsi_CDs[MINOR(cdi->dev)].device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ }; - + retval = scsi_CDs[MINOR(cdi->dev)].device->changed; scsi_CDs[MINOR(cdi->dev)].device->changed = 0; /* If the disk changed, the capacity will now be different, @@ -145,7 +146,7 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot){ } /* - * rw_intr is the interrupt routine for the device driver. It will be notified on the + * rw_intr is the interrupt routine for the device driver. It will be notified on the * end of a SCSI read / write, and will take on of several actions based on success or failure. */ @@ -155,7 +156,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt) int this_count = SCpnt->this_count; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 0; - + #ifdef DEBUG printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data); #endif @@ -203,24 +204,24 @@ static void rw_intr (Scsi_Cmnd * SCpnt) { int offset; offset = (SCpnt->request.sector % 4) << 9; - memcpy((char *)SCpnt->request.buffer, - (char *)SCpnt->buffer + offset, + memcpy((char *)SCpnt->request.buffer, + (char *)SCpnt->buffer + offset, good_sectors << 9); /* Even though we are not using scatter-gather, we look * ahead and see if there is a linked request for the * other half of this buffer. If there is, then satisfy * it. */ if((offset == 0) && good_sectors == 2 && - SCpnt->request.nr_sectors > good_sectors && + SCpnt->request.nr_sectors > good_sectors && SCpnt->request.bh && SCpnt->request.bh->b_reqnext && SCpnt->request.bh->b_reqnext->b_size == 1024) { - memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, - (char *)SCpnt->buffer + 1024, + memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, + (char *)SCpnt->buffer + 1024, 1024); good_sectors += 2; }; - + scsi_free(SCpnt->buffer, 2048); } } else { @@ -241,19 +242,19 @@ static void rw_intr (Scsi_Cmnd * SCpnt) if(good_sectors > SCpnt->request.nr_sectors) good_sectors -= 2; }; - + #ifdef DEBUG - printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, + printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, good_sectors); #endif if (SCpnt->request.nr_sectors > this_count) - { + { SCpnt->request.errors = 0; if (!SCpnt->request.bh) panic("sr.c: linked page request (%lx %x)", SCpnt->request.sector, this_count); } - + SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */ if (result == 0) { @@ -261,10 +262,10 @@ static void rw_intr (Scsi_Cmnd * SCpnt) return; } } - + if (good_sectors == 0) { /* We only come through here if no sectors were read successfully. */ - + /* Free up any indirection buffers we allocated for DMA purposes. */ if (SCpnt->use_sg) { struct scatterlist * sgpnt; @@ -280,22 +281,22 @@ static void rw_intr (Scsi_Cmnd * SCpnt) if (SCpnt->buffer != SCpnt->request.buffer) scsi_free(SCpnt->buffer, SCpnt->bufflen); } - + } if (driver_byte(result) != 0) { if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { - /* detected disc change. set a bit and quietly refuse + /* detected disc change. set a bit and quietly refuse * further access. */ - + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1; SCpnt = end_scsi_request(SCpnt, 0, this_count); requeue_sr_request(SCpnt); return; } } - + if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { printk("CD-ROM error: "); print_sense("sr", SCpnt); @@ -311,7 +312,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt) requeue_sr_request(SCpnt); /* Do next request */ return; } - + } if (SCpnt->sense_buffer[2] == NOT_READY) { @@ -324,7 +325,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt) if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) { printk("scsi%d: MEDIUM ERROR on " "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, + SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); print_command(SCpnt->cmnd); print_sense("sr", SCpnt); @@ -336,7 +337,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt) if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) { printk("scsi%d: VOLUME OVERFLOW on " "channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, + SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); print_command(SCpnt->cmnd); print_sense("sr", SCpnt); @@ -345,18 +346,18 @@ static void rw_intr (Scsi_Cmnd * SCpnt) return; } } - + /* We only get this far if we have an error we have not recognized */ if(result) { - printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", - scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, + printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", + scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id, scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result); - + if (status_byte(result) == CHECK_CONDITION) print_sense("sr", SCpnt); - + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); requeue_sr_request(SCpnt); } @@ -367,9 +368,10 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) check_disk_change(cdi->dev); scsi_CDs[MINOR(cdi->dev)].device->access_count++; - if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count) - (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)++; - if(sr_template.usage_count) (*sr_template.usage_count)++; + if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module); + if(sr_template.module) + __MOD_INC_USE_COUNT(sr_template.module); /* If this device did not have media in the drive at boot time, then * we would have been unable to get the sector size. Check to see if @@ -385,7 +387,7 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) /* * do_sr_request() is the request handler function for the sr driver. * Its function in life is to take block device requests, and - * translate them to SCSI commands. + * translate them to SCSI commands. */ static void do_sr_request (void) @@ -395,7 +397,7 @@ static void do_sr_request (void) Scsi_Device * SDev; unsigned long flags; int flag = 0; - + while (1==1){ save_flags(flags); cli(); @@ -403,11 +405,11 @@ static void do_sr_request (void) restore_flags(flags); return; }; - + INIT_SCSI_REQUEST; - + SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device; - + /* * I am not sure where the best place to do this is. We need * to hook in a place where we are likely to come if in user @@ -427,20 +429,20 @@ static void do_sr_request (void) } SDev->was_reset = 0; } - + if (flag++ == 0) SCpnt = allocate_device(&CURRENT, - scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); + scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); else SCpnt = NULL; restore_flags(flags); - + /* This is a performance enhancement. We dig down into the request list and * try to find a queueable request (i.e. device not busy, and host able to * accept another command. If we find one, then we queue it. This can * make a big difference on systems with more than one disk drive. We want * to have the interrupts off when monkeying with the request list, because * otherwise the kernel might try to slip in a request in between somewhere. */ - + if (!SCpnt && sr_template.nr_dev > 1){ struct request *req1; req1 = NULL; @@ -455,60 +457,60 @@ static void do_sr_request (void) req = req->next; }; if (SCpnt && req->rq_status == RQ_INACTIVE) { - if (req == CURRENT) + if (req == CURRENT) CURRENT = CURRENT->next; else req1->next = req->next; }; restore_flags(flags); }; - + if (!SCpnt) return; /* Could not find anything to do */ - + wake_up(&wait_for_request); /* Queue command */ requeue_sr_request(SCpnt); }; /* While */ -} +} void requeue_sr_request (Scsi_Cmnd * SCpnt) { unsigned int dev, block, realcount; unsigned char cmd[10], *buffer, tries; int this_count, start, end_rec; - + tries = 2; - + repeat: if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) { do_sr_request(); return; } - + dev = MINOR(SCpnt->request.rq_dev); - block = SCpnt->request.sector; + block = SCpnt->request.sector; buffer = NULL; this_count = 0; - + if (dev >= sr_template.nr_dev) { /* printk("CD-ROM request error: invalid device.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - + if (!scsi_CDs[dev].use) { /* printk("CD-ROM request error: device marked not in use.\n"); */ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); tries = 2; goto repeat; } - + if (scsi_CDs[dev].device->changed) { - /* - * quietly refuse to do anything to a changed disc + /* + * quietly refuse to do anything to a changed disc * until the changed bit has been reset */ /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ @@ -516,41 +518,41 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) tries = 2; goto repeat; } - + switch (SCpnt->request.cmd) { - case WRITE: + case WRITE: SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); goto repeat; break; - case READ : + case READ : cmd[0] = READ_6; break; - default : + default : panic ("Unknown sr command %d\n", SCpnt->request.cmd); } - + cmd[1] = (SCpnt->lun << 5) & 0xe0; - + /* * Now do the grungy work of figuring out which sectors we need, and * where in memory we are going to put them. - * + * * The variables we need are: - * - * this_count= number of 512 byte sectors being read + * + * this_count= number of 512 byte sectors being read * block = starting cdrom sector to read. * realcount = # of cdrom sectors to read - * + * * The major difference between a scsi disk and a scsi cdrom * is that we will always use scatter-gather if we can, because we can * work around the fact that the buffer cache has a block size of 1024, * and we have 2048 byte sectors. This code should work for buffers that * are any multiple of 512 bytes long. */ - + SCpnt->use_sg = 0; - + if (SCpnt->host->sg_tablesize > 0 && (!need_isa_buffer || dma_free_sectors >= 10)) { @@ -604,7 +606,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) if needed */ count++; }; - for(bh = SCpnt->request.bh; count < SCpnt->use_sg; + for(bh = SCpnt->request.bh; count < SCpnt->use_sg; count++, bh = bh->b_reqnext) { if (bh) { /* Need a placeholder at the end of the record? */ sgpnt[count].address = bh->b_data; @@ -637,7 +639,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) printk("Warning: Running low on SCSI DMA buffers"); /* Try switching back to a non scatter-gather operation. */ while(--count >= 0){ - if(sgpnt[count].alt_address) + if(sgpnt[count].alt_address) scsi_free(sgpnt[count].address, sgpnt[count].length); }; SCpnt->use_sg = 0; @@ -648,32 +650,32 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) }; /* for loop to fill list */ #ifdef DEBUG printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector, - this_count, + this_count, SCpnt->request.current_nr_sectors, SCpnt->request.nr_sectors); for(count=0; countuse_sg; count++) printk("SGlist: %d %x %x %x\n", count, - sgpnt[count].address, - sgpnt[count].alt_address, + sgpnt[count].address, + sgpnt[count].alt_address, sgpnt[count].length); #endif }; /* Able to allocate scatter-gather list */ }; - + if (SCpnt->use_sg == 0){ /* We cannot use scatter-gather. Do this the old fashion way */ - if (!SCpnt->request.bh) + if (!SCpnt->request.bh) this_count = SCpnt->request.nr_sectors; else this_count = (SCpnt->request.bh->b_size >> 9); - + start = block % 4; if (start) - { - this_count = ((this_count > 4 - start) ? + { + this_count = ((this_count > 4 - start) ? (4 - start) : (this_count)); buffer = (unsigned char *) scsi_malloc(2048); - } + } else if (this_count < 4) { buffer = (unsigned char *) scsi_malloc(2048); @@ -687,24 +689,24 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) buffer = (unsigned char *) scsi_malloc(this_count << 9); } }; - + if (scsi_CDs[dev].sector_size == 2048) block = block >> 2; /* These are the sectors that the cdrom uses */ else block = block & 0xfffffffc; - + realcount = (this_count + 3) / 4; - + if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; - - if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) + + if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) { if (realcount > 0xffff) { realcount = 0xffff; this_count = realcount * (scsi_CDs[dev].sector_size >> 9); } - + cmd[0] += READ_10 - READ_6 ; cmd[2] = (unsigned char) (block >> 24) & 0xff; cmd[3] = (unsigned char) (block >> 16) & 0xff; @@ -721,16 +723,16 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) realcount = 0xff; this_count = realcount * (scsi_CDs[dev].sector_size >> 9); } - + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); cmd[2] = (unsigned char) ((block >> 8) & 0xff); cmd[3] = (unsigned char) block & 0xff; cmd[4] = (unsigned char) realcount; cmd[5] = 0; - } - + } + #ifdef DEBUG - { + { int i; printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count); printk("Use sg: %d\n", SCpnt->use_sg); @@ -739,7 +741,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) printk("\n"); }; #endif - + /* Some dumb host adapters can speed transfers by knowing the * minimum transfersize in advance. * @@ -749,47 +751,47 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) * assume that we can at least transfer the minimum of the buffer * size (1024) and the sector size between each connect / disconnect. */ - + SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ? 1024 : scsi_CDs[dev].sector_size; - + SCpnt->this_count = this_count; - scsi_do_cmd (SCpnt, (void *) cmd, buffer, - realcount * scsi_CDs[dev].sector_size, + scsi_do_cmd (SCpnt, (void *) cmd, buffer, + realcount * scsi_CDs[dev].sector_size, rw_intr, SR_TIMEOUT, MAX_RETRIES); } static int sr_detect(Scsi_Device * SDp){ - + if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; - - printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", + + printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", sr_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + return 1; } static int sr_attach(Scsi_Device * SDp){ Scsi_CD * cpnt; int i; - + if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1; - + if (sr_template.nr_dev >= sr_template.dev_max) { SDp->attached--; return 1; } - - for(cpnt = scsi_CDs, i=0; idevice) break; - + if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); - + SDp->scsi_request_fn = do_sr_request; scsi_CDs[i].device = SDp; - + scsi_CDs[i].cdi.ops = &sr_dops; scsi_CDs[i].cdi.handle = &scsi_CDs[i]; scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i); @@ -797,7 +799,7 @@ static int sr_attach(Scsi_Device * SDp){ scsi_CDs[i].cdi.speed = 1; scsi_CDs[i].cdi.capacity = 1; register_cdrom(&scsi_CDs[i].cdi, "sr"); - + #ifdef CONFIG_BLK_DEV_SR_VENDOR sr_vendor_init(i); #endif @@ -812,10 +814,10 @@ static int sr_attach(Scsi_Device * SDp){ static void sr_init_done (Scsi_Cmnd * SCpnt) { struct request * req; - + req = &SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - + if (req->sem != NULL) { up(req->sem); } @@ -826,10 +828,10 @@ void get_sectorsize(int i){ unsigned char *buffer; int the_result, retries; Scsi_Cmnd * SCpnt; - + buffer = (unsigned char *) scsi_malloc(512); SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1); - + retries = 3; do { cmd[0] = READ_CAPACITY; @@ -837,7 +839,7 @@ void get_sectorsize(int i){ memset ((void *) &cmd[2], 0, 8); SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ SCpnt->cmd_len = 0; - + memset(buffer, 0, 8); /* Do the command and wait.. */ @@ -850,16 +852,16 @@ void get_sectorsize(int i){ MAX_RETRIES); down(&sem); } - + the_result = SCpnt->result; retries--; - + } while(the_result && retries); - + SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ - - wake_up(&SCpnt->device->device_wait); - + + wake_up(&SCpnt->device->device_wait); + if (the_result) { scsi_CDs[i].capacity = 0x1fffff; scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ @@ -914,7 +916,7 @@ static int sr_init() sr_registered++; } - + if (scsi_CDs) return 0; sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; @@ -924,7 +926,7 @@ static int sr_init() sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * + sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); for(i=0;i> (BLOCK_SIZE_BITS - 9); } - - + + /* If our host adapter is capable of scatter-gather, then we increase * the read-ahead to 16 blocks (32 sectors). If not, we use * a two block (4 sector) read ahead. */ @@ -968,14 +970,14 @@ void sr_finish() read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ return; -} +} static void sr_detach(Scsi_Device * SDp) { Scsi_CD * cpnt; int i; - - for(cpnt = scsi_CDs, i=0; idevice == SDp) { kdev_t devi = MKDEV(MAJOR_NR, i); @@ -985,7 +987,7 @@ static void sr_detach(Scsi_Device * SDp) */ invalidate_inodes(devi); invalidate_buffers(devi); - + /* * Reset things back to a sane state so that one can re-load a new * driver (perhaps the same one). @@ -1006,29 +1008,29 @@ static void sr_detach(Scsi_Device * SDp) #ifdef MODULE int init_module(void) { - sr_template.usage_count = &__this_module.usecount; + sr_template.module = &__this_module; return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } -void cleanup_module( void) +void cleanup_module( void) { scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); unregister_blkdev(MAJOR_NR, "sr"); sr_registered--; if(scsi_CDs != NULL) { scsi_init_free((char *) scsi_CDs, - (sr_template.dev_noticed + SR_EXTRA_DEVS) + (sr_template.dev_noticed + SR_EXTRA_DEVS) * sizeof(Scsi_CD)); - + scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); } - + blksize_size[MAJOR_NR] = NULL; blk_dev[MAJOR_NR].request_fn = NULL; - blk_size[MAJOR_NR] = NULL; + blk_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; - + sr_template.dev_max = 0; } #endif /* MODULE */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index f4cf17abfa2e..3bbc3e6a78ac 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -101,7 +101,7 @@ static int st_attach(Scsi_Device *); static int st_detect(Scsi_Device *); static void st_detach(Scsi_Device *); -struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE, +struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE, SCSI_TAPE_MAJOR, 0, 0, 0, 0, st_detect, st_init, NULL, st_attach, st_detach}; @@ -586,19 +586,21 @@ scsi_tape_open(struct inode * inode, struct file * filp) STp->nbr_waits = STp->nbr_finished = 0; #endif - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)++; - if(st_template.usage_count) (*st_template.usage_count)++; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_INC_USE_COUNT(st_template.module); memset ((void *) &cmd[0], 0, 10); cmd[0] = TEST_UNIT_READY; SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES); if (!SCpnt) { - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; - return (-EBUSY); + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); + return (-EBUSY); } if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && @@ -715,9 +717,10 @@ scsi_tape_open(struct inode * inode, struct file * filp) STp->block_size); (STp->buffer)->in_use = 0; STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); return (-EIO); } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; @@ -746,9 +749,10 @@ scsi_tape_open(struct inode * inode, struct file * filp) if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { (STp->buffer)->in_use = 0; STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); return (-EROFS); } } @@ -764,9 +768,10 @@ scsi_tape_open(struct inode * inode, struct file * filp) if ((STp->partition = find_partition(inode)) < 0) { (STp->buffer)->in_use = 0; STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); return STp->partition; } STp->new_partition = STp->partition; @@ -780,9 +785,10 @@ scsi_tape_open(struct inode * inode, struct file * filp) (i = set_mode_densblk(inode, STp, STm)) < 0) { (STp->buffer)->in_use = 0; STp->buffer = NULL; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); return i; } if (STp->default_drvbuffer != 0xff) { @@ -913,9 +919,10 @@ out: } STp->in_use = 0; - if (scsi_tapes[dev].device->host->hostt->usage_count) - (*scsi_tapes[dev].device->host->hostt->usage_count)--; - if(st_template.usage_count) (*st_template.usage_count)--; + if (scsi_tapes[dev].device->host->hostt->module) + __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); + if(st_template.module) + __MOD_DEC_USE_COUNT(st_template.module); return; } @@ -1215,7 +1222,7 @@ st_write(struct inode * inode, struct file * filp, const char * buf, STps->eof = ST_NOEOF; return( total); -} +} /* Read data from the tape. Returns zero in the normal case, one if the eof status has changed, and the negative error code in case of a @@ -1573,7 +1580,7 @@ st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev) #endif } - + static int st_set_options(struct inode * inode, long options) { @@ -1850,7 +1857,7 @@ st_int_ioctl(struct inode * inode, fileno += arg; blkno = 0; at_sm &= (arg == 0); - break; + break; case MTBSFM: chg_eof = FALSE; /* Changed from the FSF after this */ case MTBSF: @@ -1873,7 +1880,7 @@ st_int_ioctl(struct inode * inode, fileno -= arg; blkno = (-1); /* We can't know the block number */ at_sm &= (arg == 0); - break; + break; case MTFSR: cmd[0] = SPACE; cmd[1] = 0x00; /* Space Blocks */ @@ -1888,7 +1895,7 @@ st_int_ioctl(struct inode * inode, if (blkno >= 0) blkno += arg; at_sm &= (arg == 0); - break; + break; case MTBSR: cmd[0] = SPACE; cmd[1] = 0x00; /* Space Blocks */ @@ -1907,7 +1914,7 @@ st_int_ioctl(struct inode * inode, if (blkno >= 0) blkno -= arg; at_sm &= (arg == 0); - break; + break; case MTFSS: cmd[0] = SPACE; cmd[1] = 0x04; /* Space Setmarks */ @@ -1923,7 +1930,7 @@ st_int_ioctl(struct inode * inode, blkno = fileno = (-1); at_sm = 1; } - break; + break; case MTBSS: cmd[0] = SPACE; cmd[1] = 0x04; /* Space Setmarks */ @@ -1944,7 +1951,7 @@ st_int_ioctl(struct inode * inode, blkno = fileno = (-1); at_sm = 1; } - break; + break; case MTWEOF: case MTWSM: if (STp->write_prot) @@ -1970,7 +1977,7 @@ st_int_ioctl(struct inode * inode, fileno += arg; blkno = 0; at_sm = (cmd_in == MTWSM); - break; + break; case MTREW: cmd[0] = REZERO_UNIT; #if ST_NOWAIT @@ -1982,22 +1989,22 @@ st_int_ioctl(struct inode * inode, printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev); #endif fileno = blkno = at_sm = 0 ; - break; + break; case MTOFFL: case MTLOAD: case MTUNLOAD: cmd[0] = START_STOP; if (cmd_in == MTLOAD) cmd[4] |= 1; - /* - * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A + /* + * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A */ if (cmd_in != MTOFFL && arg >= 1 + MT_ST_HPLOADER_OFFSET && arg <= 6 + MT_ST_HPLOADER_OFFSET) { #if DEBUG if (debugging) { - printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", + printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", dev, (cmd[4]) ? "" : "un", arg - MT_ST_HPLOADER_OFFSET); } @@ -2019,7 +2026,7 @@ st_int_ioctl(struct inode * inode, } #endif fileno = blkno = at_sm = 0 ; - break; + break; case MTNOP: #if DEBUG if (debugging) @@ -2039,7 +2046,7 @@ st_int_ioctl(struct inode * inode, printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev); #endif fileno = blkno = at_sm = 0; - break; + break; case MTEOM: if (!STp->fast_mteom) { /* space to the end of tape */ @@ -2062,7 +2069,7 @@ st_int_ioctl(struct inode * inode, #endif blkno = 0; at_sm = 0; - break; + break; case MTERASE: if (STp->write_prot) return (-EACCES); @@ -2120,7 +2127,7 @@ st_int_ioctl(struct inode * inode, if (cmd_in == MTSETDRVBUFFER) (STp->buffer)->b_data[2] = (arg & 7) << 4; else - (STp->buffer)->b_data[2] = + (STp->buffer)->b_data[2] = STp->drv_buffer << 4; (STp->buffer)->b_data[3] = 8; /* block descriptor length */ if (cmd_in == MTSETDENSITY) { @@ -2349,15 +2356,15 @@ get_location(struct inode * inode, unsigned int *block, int *partition, else { result = 0; if ((STp->device)->scsi_level < SCSI_2) { - *block = ((STp->buffer)->b_data[0] << 16) - + ((STp->buffer)->b_data[1] << 8) + *block = ((STp->buffer)->b_data[0] << 16) + + ((STp->buffer)->b_data[1] << 8) + (STp->buffer)->b_data[2]; *partition = 0; } else { *block = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) + + ((STp->buffer)->b_data[5] << 16) + + ((STp->buffer)->b_data[6] << 8) + (STp->buffer)->b_data[7]; *partition = (STp->buffer)->b_data[1]; if (((STp->buffer)->b_data[0] & 0x80) && @@ -2711,9 +2718,9 @@ st_ioctl(struct inode * inode,struct file * file, * to this device. If the user wants to rewind the tape, * then reset the flag and allow access again. */ - if(mtc.mt_op != MTREW && + if(mtc.mt_op != MTREW && mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && + mtc.mt_op != MTRETEN && mtc.mt_op != MTERASE && mtc.mt_op != MTSEEK && mtc.mt_op != MTEOM) @@ -3008,13 +3015,13 @@ static int st_attach(Scsi_Device * SDp){ if(SDp->type != TYPE_TAPE) return 1; - if(st_template.nr_dev >= st_template.dev_max) + if(st_template.nr_dev >= st_template.dev_max) { SDp->attached--; return 1; } - for(tpnt = scsi_tapes, i=0; idevice) break; if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)"); @@ -3082,10 +3089,10 @@ static int st_detect(Scsi_Device * SDp) if(SDp->type != TYPE_TAPE) return 0; printk(KERN_INFO - "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", + "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", st_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + return 1; } @@ -3189,8 +3196,8 @@ static void st_detach(Scsi_Device * SDp) { Scsi_Tape * tpnt; int i; - - for(tpnt = scsi_tapes, i=0; idevice == SDp) { tpnt->device = NULL; SDp->attached--; @@ -3205,11 +3212,11 @@ static void st_detach(Scsi_Device * SDp) #ifdef MODULE int init_module(void) { - st_template.usage_count = &__this_module.usecount; + st_template.module = &__this_module; return scsi_register_module(MODULE_SCSI_DEV, &st_template); } -void cleanup_module( void) +void cleanup_module( void) { int i; diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 6bbeb5638718..c6eb980d0e79 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -508,9 +508,12 @@ struct sound_timer_operations { #if defined(MODULE) || (!defined(linux) && !defined(_AIX)) int trace_init = 0; -# else +#else int trace_init = 1; -# endif +#endif +#ifdef MODULE_PARM +MODULE_PARM(trace_init, "i"); +#endif #else extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 43b0c7a8bb58..6824f05261f9 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -444,11 +444,6 @@ cleanup_module (void) { int i; - if (MOD_IN_USE) - { - return; - } - if (chrdev_registered) unregister_chrdev (sound_major, "sound"); @@ -638,6 +633,9 @@ fatal_error__This_version_is_not_compatible_with_this_kernel; #endif static int dma_buffsize = DSP_BUFFSIZE; +#ifdef MODULE_PARM +MODULE_PARM(dma_buffsize, "i"); +#endif int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) diff --git a/fs/affs/dir.c b/fs/affs/dir.c index b82a17099a32..f7ec42edeb95 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -32,7 +32,7 @@ static struct file_operations affs_dir_operations = { affs_dir_read, /* read */ NULL, /* write - bad */ affs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/affs/file.c b/fs/affs/file.c index aa37f47a0bf0..da38dcc89425 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -49,7 +49,7 @@ static struct file_operations affs_file_operations = { generic_file_read, /* read */ affs_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ affs_open_file, /* special open is needed */ @@ -83,7 +83,7 @@ static struct file_operations affs_file_operations_ofs = { affs_file_read_ofs, /* read */ affs_file_write_ofs, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ affs_open_file, /* special open is needed */ diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 4f445764f31a..697f3cfd8976 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -37,7 +37,7 @@ static struct linux_binfmt aout_format = { #ifndef MODULE NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump #else - NULL, &__this_module.usecount, load_aout_binary, load_aout_library, aout_core_dump + NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump #endif }; @@ -63,7 +63,7 @@ while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_cor if (file.f_op->llseek) { \ if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \ goto close_coredump; \ -} else file.f_pos = (offset) +} else file.f_pos = (offset) /* * Routine writes a core dump image in the current directory. @@ -85,10 +85,17 @@ do_aout_core_dump(long signr, struct pt_regs * regs) char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; -#ifdef __alpha__ +#if defined(__alpha__) # define START_DATA(u) (u.start_data) -#else +#elif defined(__sparc__) +# define START_DATA(u) (u.u_tsize) +#elif defined(__i386__) # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) +#endif +#ifdef __sparc__ +# define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) +#else +# define START_STACK(u) (u.start_stack) #endif if (!current->dumpable || current->mm->count != 1) @@ -131,45 +138,76 @@ do_aout_core_dump(long signr, struct pt_regs * regs) has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); +#ifndef __sparc__ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); +#endif dump.signal = signr; dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ +#ifdef __sparc__ + if ((dump.u_dsize+dump.u_ssize) > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_dsize = 0; +#else if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; +#endif /* Make sure we have enough room to write the stack and data areas. */ +#ifdef __sparc__ + if ((dump.u_ssize) > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_ssize = 0; +#else if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; +#endif /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); +#ifdef __sparc__ + if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize)) + dump.u_dsize = 0; + if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize)) + dump.u_ssize = 0; +#else if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; - if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT)) + if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; +#endif set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); /* Now dump all of the user data. Include malloced stuff as well */ +#ifndef __sparc__ DUMP_SEEK(PAGE_SIZE); +#endif /* now we start writing out the user space info */ set_fs(USER_DS); /* Dump the data area */ if (dump.u_dsize != 0) { dump_start = START_DATA(dump); +#ifdef __sparc__ + dump_size = dump.u_dsize; +#else dump_size = dump.u_dsize << PAGE_SHIFT; +#endif DUMP_WRITE(dump_start,dump_size); } /* Now prepare to dump the stack area */ if (dump.u_ssize != 0) { - dump_start = dump.start_stack; + dump_start = START_STACK(dump); +#ifdef __sparc__ + dump_size = dump.u_ssize; +#else dump_size = dump.u_ssize << PAGE_SHIFT; +#endif DUMP_WRITE(dump_start,dump_size); } /* Finally dump the task struct. Not be used by gdb, but could be useful */ @@ -210,6 +248,11 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) int envc = bprm->envc; sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p); +#ifdef __sparc__ + /* This imposes the proper stack alignment for a new process. */ + sp = (unsigned long *) (((unsigned long) sp) & ~7); + if ((envc+argc+3)&1) --sp; +#endif #ifdef __alpha__ /* whee.. test-programs are so much fun. */ put_user(0, --sp); @@ -259,8 +302,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) * libraries. There is no binary dependent code anywhere else. */ -static inline int -do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) +static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct exec ex; struct file * file; @@ -271,8 +313,8 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) unsigned long rlim; ex = *((struct exec *) bprm->buf); /* exec-header */ - if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && - N_MAGIC(ex) != QMAGIC) || + if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && + N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; @@ -306,6 +348,9 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* OK, This is the point of no return */ flush_old_exec(bprm); +#ifdef __sparc__ + memcpy(¤t->tss.core_exec, &ex, sizeof(struct exec)); +#endif current->mm->end_code = ex.a_text + (current->mm->start_code = N_TXTADDR(ex)); @@ -319,8 +364,25 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; +#ifdef __sparc__ + if (N_MAGIC(ex) == NMAGIC) { + /* Fuck me plenty... */ + error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), + ex.a_text, 0); + error = do_mmap(NULL, N_DATADDR(ex), ex.a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex), + ex.a_data, 0); + goto beyond_if; + } +#endif + if (N_MAGIC(ex) == OMAGIC) { -#ifdef __alpha__ +#if defined(__alpha__) || defined(__sparc__) do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK, ex.a_text+ex.a_data + PAGE_SIZE - 1, PROT_READ|PROT_WRITE|PROT_EXEC, @@ -334,11 +396,12 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0); #endif } else { - if (ex.a_text & 0xfff || ex.a_data & 0xfff) + if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && + (N_MAGIC(ex) != NMAGIC)) printk(KERN_NOTICE "executable not page aligned\n"); - + fd = open_inode(bprm->inode, O_RDONLY); - + if (fd < 0) return fd; file = current->files->fd[fd]; @@ -362,7 +425,7 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) send_sig(SIGKILL, current, 0); return error; } - + error = do_mmap(file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, @@ -374,21 +437,21 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) } } beyond_if: - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); current->exec_domain = lookup_exec_domain(current->personality); current->binfmt = &aout_format; - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)++; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)++; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_INC_USE_COUNT(current->binfmt->module); set_brk(current->mm->start_brk, current->mm->brk); p = setup_arg_pages(p, bprm); - + p = (unsigned long) create_aout_tables((char *)p, bprm); current->mm->start_stack = p; #ifdef __alpha__ @@ -400,6 +463,7 @@ beyond_if: return 0; } + static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) { @@ -421,10 +485,10 @@ do_load_aout_library(int fd) unsigned int bss; unsigned int start_addr; unsigned long error; - + file = current->files->fd[fd]; inode = file->f_inode; - + if (!file || !file->f_op) return -EACCES; @@ -447,12 +511,12 @@ do_load_aout_library(int fd) inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } - if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && + if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); return -ENOEXEC; } - + if (N_FLAGS(ex)) return -ENOEXEC; /* For QMAGIC, the starting address is 0x20 into the page. We mask @@ -504,4 +568,3 @@ void cleanup_module( void) { unregister_binfmt(&aout_format); } #endif - diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b4bf43590901..f2ae27a7cd64 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -42,6 +42,10 @@ static int load_elf_library(int fd); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); extern void dump_thread(struct pt_regs *, struct user *); +#ifdef __sparc__ +extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); +#endif + /* * If we don't support core dumping, then supply a NULL so we * don't even try. @@ -59,7 +63,7 @@ static struct linux_binfmt elf_format = { #ifndef MODULE NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump #else - NULL, &__this_module.usecount, load_elf_binary, load_elf_library, elf_core_dump + NULL, &__this_module, load_elf_binary, load_elf_library, elf_core_dump #endif }; @@ -67,7 +71,7 @@ static void set_brk(unsigned long start, unsigned long end) { start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); - if (end <= start) + if (end <= start) return; do_mmap(NULL, start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC, @@ -84,7 +88,7 @@ static void set_brk(unsigned long start, unsigned long end) static void padzero(unsigned long elf_bss) { unsigned long nbyte; - + nbyte = elf_bss & (PAGE_SIZE-1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; @@ -92,7 +96,7 @@ static void padzero(unsigned long elf_bss) } } -unsigned long * create_elf_tables(char *p, int argc, int envc, +unsigned long * create_elf_tables(char *p, int argc, int envc, struct elfhdr * exec, unsigned long load_addr, unsigned long interp_load_addr, int ibcs) @@ -176,7 +180,7 @@ unsigned long * create_elf_tables(char *p, int argc, int envc, an ELF header */ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - struct inode * interpreter_inode, + struct inode * interpreter_inode, unsigned long *interp_load_addr) { struct file * file; @@ -189,31 +193,31 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, unsigned long last_bss, elf_bss; unsigned long error; int i; - + elf_bss = 0; last_bss = 0; error = load_addr = 0; - + /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine) || (!interpreter_inode->i_op || !interpreter_inode->i_op->default_file_ops->mmap)){ return ~0UL; } - + /* Now read in all of the header information */ - + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) return ~0UL; - - elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); if (!elf_phdata) return ~0UL; - + /* * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. @@ -224,10 +228,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, return ~0UL; } - retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); - + if (retval < 0) { kfree (elf_phdata); return retval; @@ -255,15 +259,20 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; +#ifdef __sparc__ + } else { + load_addr = get_unmapped_area(0, eppnt->p_filesz + + ELF_PAGEOFFSET(eppnt->p_vaddr)); +#endif } - - error = do_mmap(file, + + error = do_mmap(file, load_addr + ELF_PAGESTART(vaddr), eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), elf_prot, elf_type, eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - + if (error > -1024UL) { /* Real error */ sys_close(elf_exec_fileno); @@ -290,7 +299,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; if (k > last_bss) last_bss = k; } - + /* Now use mmap to map the library into memory. */ sys_close(elf_exec_fileno); @@ -320,18 +329,18 @@ static unsigned long load_aout_interp(struct exec * interp_ex, { int retval; unsigned long elf_entry; - + current->mm->brk = interp_ex->a_bss + (current->mm->end_data = interp_ex->a_data + (current->mm->end_code = interp_ex->a_text)); elf_entry = interp_ex->a_entry; - - + + if (N_MAGIC(*interp_ex) == OMAGIC) { do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, + retval = read_exec(interpreter_inode, 32, (char *) 0, interp_ex->a_text+interp_ex->a_data, 0); } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, @@ -343,7 +352,7 @@ static unsigned long load_aout_interp(struct exec * interp_ex, interp_ex->a_text+interp_ex->a_data, 0); } else retval = -1; - + if (retval >= 0) do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, @@ -388,62 +397,62 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) unsigned long start_code, end_code, end_data; unsigned long elf_stack; char passed_fileno[6]; - + ibcs2_interpreter = 0; status = 0; load_addr = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - + if (elf_ex.e_ident[0] != 0x7f || strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { return -ENOEXEC; } - - + + /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && - elf_ex.e_type != ET_DYN) || + elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine)) || (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || !bprm->inode->i_op->default_file_ops->mmap)){ return -ENOEXEC; } - + /* Now read in all of the header information */ - - elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * + + elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * elf_ex.e_phnum, GFP_KERNEL); if (elf_phdata == NULL) { return -ENOMEM; } - + retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum, 1); if (retval < 0) { kfree (elf_phdata); return retval; } - + elf_ppnt = elf_phdata; - + elf_bss = 0; elf_brk = 0; - + elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); if (elf_exec_fileno < 0) { kfree (elf_phdata); return elf_exec_fileno; } - + file = current->files->fd[elf_exec_fileno]; - + elf_stack = ~0UL; elf_interpreter = NULL; start_code = ~0UL; end_code = 0; end_data = 0; - + for(i=0;i < elf_ex.e_phnum; i++){ if (elf_ppnt->p_type == PT_INTERP) { if ( elf_interpreter != NULL ) @@ -456,17 +465,17 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* This is the program interpreter used for * shared libraries - for now assume that this - * is an a.out format binary + * is an a.out format binary */ - - elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, + + elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, GFP_KERNEL); if (elf_interpreter == NULL) { kfree (elf_phdata); sys_close(elf_exec_fileno); return -ENOMEM; } - + retval = read_exec(bprm->inode,elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); @@ -489,11 +498,11 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (retval >= 0) retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); - + if (retval >= 0) { interp_ex = *((struct exec *) bprm->buf); /* exec-header */ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ - + } if (retval < 0) { kfree (elf_phdata); @@ -510,9 +519,9 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ - if ((N_MAGIC(interp_ex) != OMAGIC) && + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) + (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || @@ -527,17 +536,17 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) return -ELIBBAD; } } - + /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ - + if (!bprm->sh_bang) { char * passed_p; - + if (interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; - + if (elf_interpreter) { bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); bprm->argc++; @@ -552,7 +561,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) return -E2BIG; } } - + /* OK, This is the point of no return */ flush_old_exec(bprm); @@ -561,18 +570,18 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; elf_entry = (unsigned long) elf_ex.e_entry; - + /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; bprm->p = setup_arg_pages(bprm->p, bprm); current->mm->start_stack = bprm->p; - + /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that the image should be loaded at fixed address, not at a variable address. */ - + old_fs = get_fs(); set_fs(get_ds()); for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { @@ -591,13 +600,13 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) MAP_DENYWRITE | MAP_EXECUTABLE), (elf_ppnt->p_offset - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - + #ifdef LOW_ELF_STACK - if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - - if (!load_addr_set) { + + if (!load_addr_set) { load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; load_addr_set = 1; } @@ -610,27 +619,27 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) #else if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) #endif - end_code = k; - if (end_data < k) end_data = k; + end_code = k; + if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; + if (k > elf_brk) elf_brk = k; } } set_fs(old_fs); if (elf_interpreter) { - if (interpreter_type & 1) + if (interpreter_type & 1) elf_entry = load_aout_interp(&interp_ex, interpreter_inode); - else if (interpreter_type & 2) - elf_entry = load_elf_interp(&interp_elf_ex, - interpreter_inode, + else if (interpreter_type & 2) + elf_entry = load_elf_interp(&interp_elf_ex, + interpreter_inode, &interp_load_addr); iput(interpreter_inode); kfree(elf_interpreter); - - if (elf_entry == ~0UL) { + + if (elf_entry == ~0UL) { printk("Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); @@ -639,20 +648,20 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) } kfree(elf_phdata); - + if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); current->exec_domain = lookup_exec_domain(current->personality); current->binfmt = &elf_format; - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)++; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)++; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_INC_USE_COUNT(current->binfmt->module); #ifndef VM_STACK_FLAGS current->executable = bprm->inode; @@ -664,7 +673,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; - bprm->p = (unsigned long) + bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, @@ -753,7 +762,7 @@ do_load_elf_library(int fd){ file = current->files->fd[fd]; inode = file->f_inode; elf_bss = 0; - + if (!file || !file->f_op) return -EACCES; @@ -779,31 +788,31 @@ do_load_elf_library(int fd){ !elf_check_arch(elf_ex.e_machine) || (!inode->i_op || !inode->i_op->default_file_ops->mmap)) return -ENOEXEC; - + /* Now read in all of the header information */ - + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) return -ENOEXEC; - - elf_phdata = (struct elf_phdr *) + + elf_phdata = (struct elf_phdr *) kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); if (elf_phdata == NULL) return -ENOMEM; - + retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); - + j = 0; for(i=0; ip_type == PT_LOAD) j++; - + if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } - + while(elf_phdata->p_type != PT_LOAD) elf_phdata++; - + /* Now use mmap to map the library into memory. */ error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), @@ -816,7 +825,7 @@ do_load_elf_library(int fd){ k = elf_phdata->p_vaddr + elf_phdata->p_filesz; if (k > elf_bss) elf_bss = k; - + if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { kfree(elf_phdata); return error; @@ -909,11 +918,11 @@ struct memelfnote static int notesize(struct memelfnote *en) { int sz; - + sz = sizeof(struct elf_note); sz += roundup(strlen(en->name), 4); sz += roundup(en->datasz, 4); - + return sz; } @@ -956,7 +965,7 @@ static int writenote(struct memelfnote *men, struct file *file) DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ DUMP_WRITE(men->data, men->datasz); DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ - + return 1; } #undef DUMP_WRITE @@ -994,7 +1003,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - + if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) return 0; current->dumpable = 0; @@ -1010,13 +1019,13 @@ static int elf_core_dump(long signr, struct pt_regs * regs) if (maydump(vma)) { int sz = vma->vm_end-vma->vm_start; - + if (size+sz >= limit) break; else size += sz; } - + segs++; } #ifdef DEBUG @@ -1029,7 +1038,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) elf.e_ident[EI_DATA] = ELF_DATA; elf.e_ident[EI_VERSION] = EV_CURRENT; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - + elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; @@ -1043,7 +1052,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; - + fs = get_fs(); set_fs(KERNEL_DS); memcpy(corefile,"core.",5); @@ -1121,7 +1130,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) else *(struct pt_regs *)&prstatus.pr_reg = *regs; #endif - + #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); @@ -1142,7 +1151,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) int i, len; set_fs(fs); - + len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; copy_from_user(&psinfo.pr_psargs, @@ -1160,7 +1169,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; - + /* Try to dump the fpu. */ prstatus.pr_fpvalid = dump_fpu (regs, &fpu); if (!prstatus.pr_fpvalid) @@ -1182,7 +1191,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) for(i = 0; i < numnote; i++) sz += notesize(¬es[i]); - + phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; @@ -1198,7 +1207,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) /* Page-align dumped data */ dataoff = offset = roundup(offset, PAGE_SIZE); - + /* Write program headers for segments dump */ for(vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { @@ -1208,7 +1217,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) i++; sz = vma->vm_end - vma->vm_start; - + phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; @@ -1227,17 +1236,17 @@ static int elf_core_dump(long signr, struct pt_regs * regs) for(i = 0; i < numnote; i++) if (!writenote(¬es[i], &file)) goto close_coredump; - + set_fs(fs); DUMP_SEEK(dataoff); - + for(i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; - + i++; if (!maydump(vma)) continue; @@ -1267,14 +1276,14 @@ static int elf_core_dump(long signr, struct pt_regs * regs) } #endif /* USE_ELF_CORE_DUMP */ -int init_elf_binfmt(void) +int init_elf_binfmt(void) { return register_binfmt(&elf_format); } #ifdef MODULE -int init_module(void) +int init_module(void) { /* Install the COFF, ELF and XOUT loaders. * N.B. We *rely* on the table being the right size with the @@ -1284,7 +1293,7 @@ int init_module(void) } -void cleanup_module( void) +void cleanup_module( void) { /* Remove the COFF and ELF loaders. */ unregister_binfmt(&elf_format); diff --git a/fs/binfmt_java.c b/fs/binfmt_java.c index 4192f6d66791..75b4eef03c66 100644 --- a/fs/binfmt_java.c +++ b/fs/binfmt_java.c @@ -144,7 +144,7 @@ static struct linux_binfmt java_format = { #ifndef MODULE NULL, 0, load_java, NULL, NULL #else - NULL, &__this_module.usecount, load_java, NULL, NULL + NULL, &__this_module, load_java, NULL, NULL #endif }; @@ -161,7 +161,7 @@ static struct linux_binfmt applet_format = { #ifndef MODULE NULL, 0, load_applet, NULL, NULL #else - NULL, &__this_module.usecount, load_applet, NULL, NULL + NULL, &__this_module, load_applet, NULL, NULL #endif }; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 864edfe08324..0ce19907af0c 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -100,7 +100,7 @@ struct linux_binfmt script_format = { #ifndef MODULE NULL, 0, load_script, NULL, NULL #else - NULL, &__this_module.usecount, load_script, NULL, NULL + NULL, &__this_module, load_script, NULL, NULL #endif }; diff --git a/fs/buffer.c b/fs/buffer.c index 55c06171a9c8..829afebec4b3 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -249,7 +249,9 @@ int fsync_dev(kdev_t dev) asmlinkage int sys_sync(void) { + lock_kernel(); fsync_dev(0); + unlock_kernel(); return 0; } @@ -262,29 +264,39 @@ asmlinkage int sys_fsync(unsigned int fd) { struct file * file; struct inode * inode; + int err = 0; + lock_kernel(); if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode)) - return -EBADF; - if (!file->f_op || !file->f_op->fsync) - return -EINVAL; - if (file->f_op->fsync(inode,file)) - return -EIO; - return 0; + err = -EBADF; + else if (!file->f_op || !file->f_op->fsync) + err = -EINVAL; + else if (file->f_op->fsync(inode,file)) + err = -EIO; + unlock_kernel(); + return err; } asmlinkage int sys_fdatasync(unsigned int fd) { struct file * file; struct inode * inode; + int err = -EBADF; + lock_kernel(); if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode)) - return -EBADF; + goto out; + err = -EINVAL; if (!file->f_op || !file->f_op->fsync) - return -EINVAL; + goto out; /* this needs further work, at the moment it is identical to fsync() */ if (file->f_op->fsync(inode,file)) - return -EIO; - return 0; + err = -EIO; + else + err = 0; +out: + unlock_kernel(); + return err; } void invalidate_buffers(kdev_t dev) @@ -1546,33 +1558,42 @@ asmlinkage int sync_old_buffers(void) asmlinkage int sys_bdflush(int func, long data) { - int i; + int i, error = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; - if (func == 1) - return sync_old_buffers(); + if (func == 1) { + error = sync_old_buffers(); + goto out; + } /* Basically func 1 means read param 1, 2 means write param 1, etc */ if (func >= 2) { i = (func-2) >> 1; + error = -EINVAL; if (i < 0 || i >= N_PARAM) - return -EINVAL; + goto out; if((func & 1) == 0) { - return put_user(bdf_prm.data[i], (int*)data); - }; + error = put_user(bdf_prm.data[i], (int*)data); + goto out; + } if (data < bdflush_min[i] || data > bdflush_max[i]) - return -EINVAL; + goto out; bdf_prm.data[i] = data; - return 0; + error = 0; + goto out; }; /* Having func 0 used to launch the actual bdflush and then never - return (unless explicitly killed). We return zero here to - remain semi-compatible with present update(8) programs. */ - - return 0; + * return (unless explicitly killed). We return zero here to + * remain semi-compatible with present update(8) programs. + */ + error = 0; +out: + unlock_kernel(); + return error; } /* This is the actual bdflush daemon itself. It used to be started from @@ -1613,11 +1634,7 @@ int bdflush(void * unused) * and other internals and thus be subject to the SMP locking * rules. (On a uniprocessor box this does nothing). */ - -#ifdef __SMP__ lock_kernel(); - syscall_count++; -#endif for (;;) { #ifdef DEBUG diff --git a/fs/dquot.c b/fs/dquot.c index 7720af505b2a..5236ed38e5f2 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -13,7 +13,7 @@ * diskquota system. This implementation is not based on any BSD * kernel sourcecode. * - * Version: $Id: dquot.c,v 5.6 1995/11/15 20:30:27 mvw Exp mvw $ + * Version: $Id: dquot.c,v 1.11 1997/01/06 06:53:02 davem Exp $ * * Author: Marco van Wieringen * @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include @@ -662,7 +664,7 @@ static int get_stats(caddr_t addr) dqstats.allocated_dquots = nr_dquots; dqstats.free_dquots = nr_free_dquots; return copy_to_user(addr, (caddr_t)&dqstats, sizeof(struct dqstats)) - ? -EFAULT : 0; + ? -EFAULT : 0; } /* @@ -1005,12 +1007,15 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) int cmds = 0, type = 0, flags = 0; struct inode *ino; kdev_t dev; + int ret = -EINVAL; + lock_kernel(); cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; if ((u_int) type >= MAXQUOTAS) - return(-EINVAL); + goto out; + ret = -EPERM; switch (cmds) { case Q_SYNC: case Q_GETSTATS: @@ -1018,33 +1023,39 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) case Q_GETQUOTA: if (((type == USRQUOTA && current->uid != id) || (type == GRPQUOTA && current->gid != id)) && !fsuser()) - return(-EPERM); + goto out; break; default: if (!fsuser()) - return(-EPERM); + goto out; } + ret = -EINVAL; if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS)) dev = 0; else { if (namei(special, &ino)) - return(-EINVAL); + goto out; dev = ino->i_rdev; + ret = -ENOTBLK; if (!S_ISBLK(ino->i_mode)) { iput(ino); - return(-ENOTBLK); + goto out; } iput(ino); } + ret = -EINVAL; switch (cmds) { case Q_QUOTAON: - return(quota_on(dev, type, (char *) addr)); + ret = quota_on(dev, type, (char *) addr); + goto out; case Q_QUOTAOFF: - return(quota_off(dev, type)); + ret = quota_off(dev, type); + goto out; case Q_GETQUOTA: - return(get_quota(dev, id, type, (struct dqblk *) addr)); + ret = get_quota(dev, id, type, (struct dqblk *) addr); + goto out; case Q_SETQUOTA: flags |= SET_QUOTA; break; @@ -1055,15 +1066,20 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr) flags |= SET_QLIMIT; break; case Q_SYNC: - return(sync_dquots(dev, type)); + ret = sync_dquots(dev, type); + goto out; case Q_GETSTATS: - return(get_stats(addr)); + ret = get_stats(addr); default: - return(-EINVAL); + goto out; } flags |= QUOTA_SYSCALL; if (has_quota_enabled(dev, type)) - return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr)); - return(-ESRCH); + ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr); + else + ret = -ESRCH; +out: + unlock_kernel(); + return ret; } diff --git a/fs/exec.c b/fs/exec.c index e8b8d176343c..487ecfd39eb4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -158,9 +161,11 @@ asmlinkage int sys_uselib(const char * library) struct file * file; struct linux_binfmt * fmt; + lock_kernel(); fd = sys_open(library, 0, 0); + retval = fd; if (fd < 0) - return fd; + goto out; file = current->files->fd[fd]; retval = -ENOEXEC; if (file && file->f_inode && file->f_op && file->f_op->read) { @@ -174,6 +179,8 @@ asmlinkage int sys_uselib(const char * library) } } sys_close(fd); +out: + unlock_kernel(); return retval; } @@ -286,7 +293,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm) bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (mpnt) { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) p; @@ -607,7 +614,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) printable(bprm->buf[2]) && printable(bprm->buf[3])) break; /* -ENOEXEC */ - sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf)); + sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bprm->buf[2])); request_module(modname); #endif } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index e235c46c6b60..fce6fc4c894a 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -39,7 +39,7 @@ static struct file_operations ext2_dir_operations = { ext2_dir_read, /* read */ NULL, /* write - bad */ ext2_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ ext2_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 12f1b24fa785..09639285da34 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -49,7 +49,7 @@ static struct file_operations ext2_file_operations = { generic_file_read, /* read */ ext2_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ ext2_ioctl, /* ioctl */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 6938b7b9e679..45b31836b6df 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -40,7 +40,7 @@ struct file_operations fat_dir_operations = { fat_dir_read, /* read */ NULL, /* write - bad */ fat_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ fat_dir_ioctl, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/fat/file.c b/fs/fat/file.c index b9162f7d904d..6dec1ba421c0 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -32,7 +32,7 @@ static struct file_operations fat_file_operations = { fat_file_read, /* read */ fat_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ @@ -71,7 +71,7 @@ static struct file_operations fat_file_operations_1024 = { fat_file_read, /* read */ fat_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ fat_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/fcntl.c b/fs/fcntl.c index e6b8c3cce327..bedc02e89036 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include @@ -35,20 +38,33 @@ static inline int dupfd(unsigned int fd, unsigned int arg) asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) { + int err = -EBADF; + + lock_kernel(); if (oldfd >= NR_OPEN || !current->files->fd[oldfd]) - return -EBADF; + goto out; + err = newfd; if (newfd == oldfd) - return newfd; + goto out; + err = -EBADF; if (newfd >= NR_OPEN) - return -EBADF; /* following POSIX.1 6.2.1 */ + goto out; /* following POSIX.1 6.2.1 */ sys_close(newfd); - return dupfd(oldfd,newfd); + err = dupfd(oldfd,newfd); +out: + unlock_kernel(); + return err; } asmlinkage int sys_dup(unsigned int fildes) { - return dupfd(fildes,0); + int ret; + + lock_kernel(); + ret = dupfd(fildes,0); + unlock_kernel(); + return ret; } asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -56,29 +72,37 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) struct file * filp; struct task_struct *p; int task_found = 0; + long err = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) - return -EBADF; + goto out; + err = 0; switch (cmd) { case F_DUPFD: - return dupfd(fd,arg); + err = dupfd(fd,arg); + break; case F_GETFD: - return FD_ISSET(fd, ¤t->files->close_on_exec); + err = FD_ISSET(fd, ¤t->files->close_on_exec); + break; case F_SETFD: if (arg&1) FD_SET(fd, ¤t->files->close_on_exec); else FD_CLR(fd, ¤t->files->close_on_exec); - return 0; + break; case F_GETFL: - return filp->f_flags; + err = filp->f_flags; + break; case F_SETFL: /* * In the case of an append-only file, O_APPEND * cannot be cleared */ + err = -EPERM; if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND)) - return -EPERM; + break; + err = 0; if ((arg & FASYNC) && !(filp->f_flags & FASYNC) && filp->f_op->fasync) filp->f_op->fasync(filp->f_inode, filp, 1); @@ -93,13 +117,16 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) O_NDELAY | FASYNC); filp->f_flags |= arg & (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC); - return 0; + break; case F_GETLK: - return fcntl_getlk(fd, (struct flock *) arg); + err = fcntl_getlk(fd, (struct flock *) arg); + break; case F_SETLK: - return fcntl_setlk(fd, cmd, (struct flock *) arg); + err = fcntl_setlk(fd, cmd, (struct flock *) arg); + break; case F_SETLKW: - return fcntl_setlk(fd, cmd, (struct flock *) arg); + err = fcntl_setlk(fd, cmd, (struct flock *) arg); + break; case F_GETOWN: /* * XXX If f_owner is a process group, the @@ -108,7 +135,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) * current syscall conventions, the only way * to fix this will be in libc. */ - return filp->f_owner; + err = filp->f_owner; + break; case F_SETOWN: /* * Add the security checks - AC. Without @@ -139,29 +167,35 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) if ((p->pid == arg) || (p->pid == -arg) || (p->pgrp == -arg)) { task_found++; + err = -EPERM; if ((p->session != current->session) && (p->uid != current->uid) && (p->euid != current->euid) && !suser()) - return -EPERM; + goto out; break; } } + err = -EINVAL; if ((task_found == 0) && !suser()) - return -EINVAL; + break; fasync_ok: + err = 0; filp->f_owner = arg; if (S_ISSOCK (filp->f_inode->i_mode)) - sock_fcntl (filp, F_SETOWN, arg); - return 0; + err = sock_fcntl (filp, F_SETOWN, arg); + break; default: /* sockets need a few special fcntls. */ if (S_ISSOCK (filp->f_inode->i_mode)) - { - return (sock_fcntl (filp, cmd, arg)); - } - return -EINVAL; + err = sock_fcntl (filp, cmd, arg); + else + err = -EINVAL; + break; } +out: + unlock_kernel(); + return err; } void kill_fasync(struct fasync_struct *fa, int sig) diff --git a/fs/filesystems.c b/fs/filesystems.c index 3a9e19127778..feb19e9d6a97 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -24,17 +24,22 @@ #include #include #include +#include +#include extern void device_setup(void); extern void binfmt_setup(void); +extern void free_initmem(void); /* This may be used only once, enforced by 'static int callable' */ asmlinkage int sys_setup(void) { static int callable = 1; + int err = -1; + lock_kernel(); if (!callable) - return -1; + goto out; callable = 0; device_setup(); @@ -106,6 +111,12 @@ asmlinkage int sys_setup(void) #endif mount_root(); - return 0; + + free_initmem(); + + err = 0; +out: + unlock_kernel(); + return err; } diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c index 3fdc59a1c5b8..f66a53f4abf4 100644 --- a/fs/hpfs/hpfs_fs.c +++ b/fs/hpfs/hpfs_fs.c @@ -153,7 +153,7 @@ static const struct file_operations hpfs_file_ops = hpfs_file_read, /* read */ NULL, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ @@ -197,7 +197,7 @@ static const struct file_operations hpfs_dir_ops = hpfs_dir_read, /* read */ NULL, /* write - bad */ hpfs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/ioctl.c b/fs/ioctl.c index 3660dd6b9787..6766506a86e9 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include /* for f_flags values */ #include @@ -48,22 +50,24 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; unsigned int flag; - int on, error; + int on, error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) - return -EBADF; + goto out; + error = 0; switch (cmd) { case FIOCLEX: FD_SET(fd, ¤t->files->close_on_exec); - return 0; + break; case FIONCLEX: FD_CLR(fd, ¤t->files->close_on_exec); - return 0; + break; case FIONBIO: if ((error = get_user(on, (int *)arg)) != 0) - return error; + break; flag = O_NONBLOCK; #ifdef __sparc__ /* SunOS compatability item. */ @@ -74,25 +78,27 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) filp->f_flags |= flag; else filp->f_flags &= ~flag; - return 0; + break; case FIOASYNC: /* O_SYNC is not yet implemented, but it's here for completeness. */ if ((error = get_user(on, (int *)arg)) != 0) - return error; + break; if (on) filp->f_flags |= O_SYNC; else filp->f_flags &= ~O_SYNC; - return 0; + break; default: if (filp->f_inode && S_ISREG(filp->f_inode->i_mode)) - return file_ioctl(filp, cmd, arg); - - if (filp->f_op && filp->f_op->ioctl) - return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); - - return -ENOTTY; + error = file_ioctl(filp, cmd, arg); + else if (filp->f_op && filp->f_op->ioctl) + error = filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); + else + error = -ENOTTY; } +out: + unlock_kernel(); + return error; } diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index ea193d7b4e61..24a252204069 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -31,7 +31,7 @@ static struct file_operations isofs_dir_operations = NULL, /* read */ NULL, /* write - bad */ isofs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* no special open code */ NULL, /* no special release code */ diff --git a/fs/isofs/file.c b/fs/isofs/file.c index 0d5c1ba5c554..d14a558a0475 100644 --- a/fs/isofs/file.c +++ b/fs/isofs/file.c @@ -27,7 +27,7 @@ static struct file_operations isofs_file_operations = { generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/locks.c b/fs/locks.c index 6fe7da42a074..e8e8ba64fce9 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -105,6 +105,8 @@ #include #include #include +#include +#include #include @@ -240,17 +242,20 @@ asmlinkage int sys_flock(unsigned int fd, unsigned int cmd) { struct file_lock file_lock; struct file *filp; + int err; + lock_kernel(); if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return (-EBADF); - - if (!flock_make_lock(filp, &file_lock, cmd)) - return (-EINVAL); - - if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) - return (-EBADF); - - return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1)); + err = -EBADF; + else if (!flock_make_lock(filp, &file_lock, cmd)) + err = -EINVAL; + else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) + err = -EBADF; + else + err = flock_lock_file(filp, &file_lock, + (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); + unlock_kernel(); + return err; } /* Report the first existing lock that would conflict with l. @@ -342,11 +347,23 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) break; case F_SHLCK: case F_EXLCK: +#ifdef __sparc__ +/* warn a bit for now, but don't overdo it */ +{ + static int count = 0; + if (!count) { + count=1; printk(KERN_WARNING - "fcntl_setlk(): process %d (%s) requested broken flock() emulation\n", + "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n", current->pid, current->comm); + } +} + if (!(filp->f_mode & 3)) + return (-EBADF); + break; +#endif default: - return (-EINVAL); + return -EINVAL; } return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 851d1f7da049..ec5113c4a67f 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -27,7 +27,7 @@ static struct file_operations minix_dir_operations = { minix_dir_read, /* read */ NULL, /* write - bad */ minix_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/minix/file.c b/fs/minix/file.c index 009bd09ed9a9..23aa70268a6a 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -38,7 +38,7 @@ static struct file_operations minix_file_operations = { generic_file_read, /* read */ minix_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/namei.c b/fs/namei.c index 3523ceaed2ec..827a0ab73d7e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -15,12 +15,16 @@ #include #include #include +#include +#include #include #include +#include #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) + /* * In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the @@ -265,6 +269,7 @@ static int _namei(const char * pathname, struct inode * base, int namelen,error; struct inode * inode; + translate_namei(pathname, base, follow_links, res_inode); *res_inode = NULL; error = dir_namei(pathname, &namelen, &basename, base, &base); if (error) @@ -331,13 +336,15 @@ int namei(const char *pathname, struct inode **res_inode) * which is a lot more logical, and also allows the "no perm" needed * for symlinks (where the permissions are checked later). */ -int open_namei(const char * pathname, int flag, int mode, +int +open_namei(const char * pathname, int flag, int mode, struct inode ** res_inode, struct inode * base) { const char * basename; int namelen,error; struct inode * dir, *inode; + translate_open_namei(pathname, flag, mode, res_inode, base); mode &= S_IALLUGO & ~current->fs->umask; mode |= S_IFREG; error = dir_namei(pathname, &namelen, &basename, base, &dir); @@ -499,8 +506,11 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) int error; char * tmp; + lock_kernel(); + error = -EPERM; if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser())) - return -EPERM; + goto out; + error = -EINVAL; switch (mode & S_IFMT) { case 0: mode |= S_IFREG; @@ -508,13 +518,15 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: break; default: - return -EINVAL; + goto out; } error = getname(filename,&tmp); if (!error) { error = do_mknod(tmp,mode,dev); putname(tmp); } +out: + unlock_kernel(); return error; } @@ -595,12 +607,14 @@ asmlinkage int sys_mkdir(const char * pathname, int mode) int error; char * tmp; + lock_kernel(); error = getname(pathname,&tmp); if (!error) { remove_trailing_slashes(tmp); error = do_mkdir(tmp,mode); putname(tmp); } + unlock_kernel(); return error; } @@ -646,12 +660,14 @@ asmlinkage int sys_rmdir(const char * pathname) int error; char * tmp; + lock_kernel(); error = getname(pathname,&tmp); if (!error) { remove_trailing_slashes(tmp); error = do_rmdir(tmp); putname(tmp); } + unlock_kernel(); return error; } @@ -697,11 +713,13 @@ asmlinkage int sys_unlink(const char * pathname) int error; char * tmp; + lock_kernel(); error = getname(pathname,&tmp); if (!error) { error = do_unlink(tmp); putname(tmp); } + unlock_kernel(); return error; } @@ -745,6 +763,7 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname) int error; char * from, * to; + lock_kernel(); error = getname(oldname,&from); if (!error) { error = getname(newname,&to); @@ -754,6 +773,7 @@ asmlinkage int sys_symlink(const char * oldname, const char * newname) } putname(from); } + unlock_kernel(); return error; } @@ -817,16 +837,19 @@ asmlinkage int sys_link(const char * oldname, const char * newname) char * to; struct inode * oldinode; + lock_kernel(); error = lnamei(oldname, &oldinode); if (error) - return error; + goto out; error = getname(newname,&to); if (error) { iput(oldinode); - return error; + goto out; } error = do_link(oldinode,to); putname(to); +out: + unlock_kernel(); return error; } @@ -905,6 +928,7 @@ asmlinkage int sys_rename(const char * oldname, const char * newname) int error; char * from, * to; + lock_kernel(); error = getname(oldname,&from); if (!error) { error = getname(newname,&to); @@ -916,5 +940,6 @@ asmlinkage int sys_rename(const char * oldname, const char * newname) } putname(from); } + unlock_kernel(); return error; } diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 00a43cabd7ea..4be6a719f34c 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -115,7 +115,7 @@ static struct file_operations ncp_dir_operations = { ncp_dir_read, /* read - bad */ NULL, /* write - bad */ ncp_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ ncp_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 12b646f91a5e..b913388772e5 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -255,7 +255,7 @@ static struct file_operations ncp_file_operations = { ncp_file_read, /* read */ ncp_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ ncp_ioctl, /* ioctl */ ncp_mmap, /* mmap */ NULL, /* open */ diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 3473f233cfb5..e388efdada7d 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -341,9 +341,9 @@ do_ncp_rpc_call(struct ncp_server *server, int size) unsigned short fs; int result; char *start = server->packet; - select_table wait_table; - struct select_table_entry entry; - int (*select) (struct inode *, struct file *, int, select_table *); + poll_table wait_table; + struct poll_table_entry entry; + int (*select) (struct inode *, poll_table *); int init_timeout, max_timeout; int timeout; int retrans; @@ -362,7 +362,7 @@ do_ncp_rpc_call(struct ncp_server *server, int size) file = server->ncp_filp; inode = file->f_inode; - select = file->f_op->select; + select = file->f_op->poll; sock = &inode->u.socket_i; if (!sock) { @@ -418,8 +418,7 @@ do_ncp_rpc_call(struct ncp_server *server, int size) wait_table.nr = 0; wait_table.entry = &entry; current->state = TASK_INTERRUPTIBLE; - if ( !select(inode, file, SEL_IN, &wait_table) - && !select(inode, file, SEL_IN, NULL)) + if (!select(inode, &wait_table)) { if (timeout > max_timeout) { diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 8f16dc7996f0..5d2ee71ba238 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -39,7 +39,7 @@ static struct file_operations nfs_dir_operations = { nfs_dir_read, /* read - bad */ NULL, /* write - bad */ nfs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ nfs_dir_open, /* open - revalidate */ diff --git a/fs/nfs/file.c b/fs/nfs/file.c index e6b02185cbf2..930dcc63cae5 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -39,7 +39,7 @@ static struct file_operations nfs_file_operations = { nfs_file_read, /* read */ nfs_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ nfs_file_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 052a328a4150..e8c13c4c43c2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -335,11 +335,7 @@ static int run_nfsiod(void *dummy) { int ret; -#ifdef __SMP__ lock_kernel(); - syscall_count++; -#endif - MOD_INC_USE_COUNT; exit_mm(current); current->session = 1; @@ -347,6 +343,7 @@ static int run_nfsiod(void *dummy) sprintf(current->comm, "nfsiod"); ret = nfsiod(); MOD_DEC_USE_COUNT; + unlock_kernel(); return ret; } diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e39a471d2ba3..82fe38e49340 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -172,7 +172,10 @@ static int root_dev_open(void) last = &open_base; for (dev = dev_base; dev != NULL; dev = dev->next) { - if (dev->type < ARPHRD_SLIP && + if ( +#if !CONFIG_AP1000 + dev->type < ARPHRD_SLIP && +#endif dev->family == AF_INET && !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) && (0 != strncmp(dev->name, "dummy", 5)) && @@ -1289,6 +1292,9 @@ static void root_nfs_addrs(char *addrs) num++; } rarp_serv = server; +#if CONFIG_AP1000 + ap_nfs_hook(server.sin_addr.s_addr); +#endif } static int root_nfs_add_default_route(struct in_addr gw, struct device *dev) diff --git a/fs/open.c b/fs/open.c index 7924c7cb173b..2f71468fa1f4 100644 --- a/fs/open.c +++ b/fs/open.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -27,19 +29,24 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf) struct inode * inode; int error; + lock_kernel(); error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); if (error) - return error; + goto out; error = namei(path,&inode); if (error) - return error; + goto out; + error = -ENOSYS; if (!inode->i_sb->s_op->statfs) { iput(inode); - return -ENOSYS; + goto out; } inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); iput(inode); - return 0; + error = 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) @@ -48,19 +55,23 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) struct file * file; int error; + lock_kernel(); error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); if (error) - return error; + goto out; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!(inode = file->f_inode)) - return -ENOENT; - if (!inode->i_sb) - return -ENODEV; - if (!inode->i_sb->s_op->statfs) - return -ENOSYS; - inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); - return 0; + error = -EBADF; + else if (!(inode = file->f_inode)) + error = -ENOENT; + else if (!inode->i_sb) + error = -ENODEV; + else if (!inode->i_sb->s_op->statfs) + error = -ENOSYS; + else + inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); +out: + unlock_kernel(); + return error; } int do_truncate(struct inode *inode, unsigned long length) @@ -87,29 +98,30 @@ asmlinkage int sys_truncate(const char * path, unsigned long length) struct inode * inode; int error; + lock_kernel(); error = namei(path,&inode); if (error) - return error; + goto out; error = -EACCES; if (S_ISDIR(inode->i_mode)) - goto out; + goto iput_and_out; error = permission(inode,MAY_WRITE); if (error) - goto out; + goto iput_and_out; error = -EROFS; if (IS_RDONLY(inode)) - goto out; + goto iput_and_out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out; + goto iput_and_out; error = get_write_access(inode); if (error) - goto out; + goto iput_and_out; error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL, length < inode->i_size ? length : inode->i_size, @@ -120,8 +132,10 @@ asmlinkage int sys_truncate(const char * path, unsigned long length) error = do_truncate(inode, length); } put_write_access(inode); -out: +iput_and_out: iput(inode); +out: + unlock_kernel(); return error; } @@ -131,19 +145,23 @@ asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length) struct file * file; int error; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!(inode = file->f_inode)) - return -ENOENT; - if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) - return -EACCES; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, - length < inode->i_size ? length : inode->i_size, - abs(inode->i_size - length)); - if (!error) - error = do_truncate(inode, length); + error = -EBADF; + else if (!(inode = file->f_inode)) + error = -ENOENT; + else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + error = -EACCES; + else if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + error = -EPERM; + else { + error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, + lengthi_size ? length : inode->i_size, + abs(inode->i_size - length)); + if (!error) + error = do_truncate(inode, length); + } + unlock_kernel(); return error; } @@ -166,12 +184,14 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times) struct inode * inode; struct iattr newattrs; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; + goto out; + error = -EROFS; if (IS_RDONLY(inode)) { iput(inode); - return -EROFS; + goto out; } /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; @@ -181,18 +201,20 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times) error = get_user(newattrs.ia_mtime, ×->modtime); if (error) { iput(inode); - return error; + goto out; } newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && (error = permission(inode,MAY_WRITE)) != 0) { iput(inode); - return error; + goto out; } } error = notify_change(inode, &newattrs); iput(inode); +out: + unlock_kernel(); return error; } @@ -208,32 +230,32 @@ asmlinkage int sys_utimes(char * filename, struct timeval * utimes) struct inode * inode; struct iattr newattrs; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; - if (IS_RDONLY(inode)) { - iput(inode); - return -EROFS; - } + goto out; + error = -EROFS; + if (IS_RDONLY(inode)) + goto iput_and_out; /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (utimes) { struct timeval times[2]; - if (copy_from_user(×, utimes, sizeof(times))) { - iput(inode); - return -EFAULT; - } + error = -EFAULT; + if (copy_from_user(×, utimes, sizeof(times))) + goto iput_and_out; newattrs.ia_atime = times[0].tv_sec; newattrs.ia_mtime = times[1].tv_sec; newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { - if ((error = permission(inode,MAY_WRITE)) != 0) { - iput(inode); - return error; - } + if ((error = permission(inode,MAY_WRITE)) != 0) + goto iput_and_out; } error = notify_change(inode, &newattrs); +iput_and_out: iput(inode); +out: + unlock_kernel(); return error; } @@ -245,10 +267,11 @@ asmlinkage int sys_access(const char * filename, int mode) { struct inode * inode; int old_fsuid, old_fsgid; - int res; + int res = -EINVAL; + lock_kernel(); if (mode != (mode & S_IRWXO)) /* where's F_OK, X_OK, W_OK, R_OK? */ - return -EINVAL; + goto out; old_fsuid = current->fsuid; old_fsgid = current->fsgid; current->fsuid = current->uid; @@ -260,6 +283,8 @@ asmlinkage int sys_access(const char * filename, int mode) } current->fsuid = old_fsuid; current->fsgid = old_fsgid; +out: + unlock_kernel(); return res; } @@ -268,40 +293,51 @@ asmlinkage int sys_chdir(const char * filename) struct inode * inode; int error; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; + goto out; + error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) { iput(inode); - return -ENOTDIR; + goto out; } if ((error = permission(inode,MAY_EXEC)) != 0) { iput(inode); - return error; + goto out; } iput(current->fs->pwd); current->fs->pwd = inode; - return (0); + error = 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_fchdir(unsigned int fd) { struct inode * inode; struct file * file; - int error; + int error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOENT; if (!(inode = file->f_inode)) - return -ENOENT; + goto out; + error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) - return -ENOTDIR; + goto out; if ((error = permission(inode,MAY_EXEC)) != 0) - return error; + goto out; iput(current->fs->pwd); current->fs->pwd = inode; inode->i_count++; - return (0); + error = 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_chroot(const char * filename) @@ -309,20 +345,26 @@ asmlinkage int sys_chroot(const char * filename) struct inode * inode; int error; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; + goto out; + error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) { iput(inode); - return -ENOTDIR; + goto out; } + error = -EPERM; if (!fsuser()) { iput(inode); - return -EPERM; + goto out; } iput(current->fs->root); current->fs->root = inode; - return (0); + error = 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) @@ -330,21 +372,29 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) struct inode * inode; struct file * file; struct iattr newattrs; + int err = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + err = -ENOENT; if (!(inode = file->f_inode)) - return -ENOENT; + goto out; + err = -EROFS; if (IS_RDONLY(inode)) - return -EROFS; + goto out; + err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; + goto out; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; inode->i_dirt = 1; - return notify_change(inode, &newattrs); + err = notify_change(inode, &newattrs); +out: + unlock_kernel(); + return err; } asmlinkage int sys_chmod(const char * filename, mode_t mode) @@ -353,24 +403,26 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode) int error; struct iattr newattrs; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; - if (IS_RDONLY(inode)) { - iput(inode); - return -EROFS; - } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - iput(inode); - return -EPERM; - } + goto out; + error = -EROFS; + if (IS_RDONLY(inode)) + goto iput_and_out; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto iput_and_out; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; inode->i_dirt = 1; error = notify_change(inode, &newattrs); +iput_and_out: iput(inode); +out: + unlock_kernel(); return error; } @@ -379,16 +431,20 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) struct inode * inode; struct file * file; struct iattr newattrs; - int error; + int error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOENT; if (!(inode = file->f_inode)) - return -ENOENT; + goto out; + error = -EROFS; if (IS_RDONLY(inode)) - return -EROFS; + goto out; + error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; + goto out; if (user == (uid_t) -1) user = inode->i_uid; if (group == (gid_t) -1) @@ -417,13 +473,16 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) inode->i_dirt = 1; if (inode->i_sb && inode->i_sb->dq_op) { inode->i_sb->dq_op->initialize(inode, -1); + error = -EDQUOT; if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) - return -EDQUOT; + goto out; error = notify_change(inode, &newattrs); if (error) inode->i_sb->dq_op->transfer(inode, &newattrs, 1); } else error = notify_change(inode, &newattrs); +out: + unlock_kernel(); return error; } @@ -433,17 +492,16 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) int error; struct iattr newattrs; + lock_kernel(); error = lnamei(filename,&inode); if (error) - return error; - if (IS_RDONLY(inode)) { - iput(inode); - return -EROFS; - } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - iput(inode); - return -EPERM; - } + goto out; + error = -EROFS; + if (IS_RDONLY(inode)) + goto iput_and_out; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto iput_and_out; if (user == (uid_t) -1) user = inode->i_uid; if (group == (gid_t) -1) @@ -472,14 +530,18 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) inode->i_dirt = 1; if (inode->i_sb->dq_op) { inode->i_sb->dq_op->initialize(inode, -1); + error = -EDQUOT; if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) - return -EDQUOT; + goto out; error = notify_change(inode, &newattrs); if (error) inode->i_sb->dq_op->transfer(inode, &newattrs, 1); } else error = notify_change(inode, &newattrs); +iput_and_out: iput(inode); +out: + unlock_kernel(); return(error); } @@ -574,17 +636,24 @@ asmlinkage int sys_open(const char * filename,int flags,int mode) char * tmp; int fd, error; + lock_kernel(); fd = get_unused_fd(); - if (fd < 0) - return fd; + if (fd < 0) { + error = fd; + goto out; + } error = getname(filename, &tmp); if (!error) { error = do_open(tmp,flags,mode, fd); putname(tmp); - if (!error) - return fd; + if (!error) { + error = fd; + goto out; + } } put_unused_fd(fd); +out: + unlock_kernel(); return error; } @@ -596,7 +665,12 @@ asmlinkage int sys_open(const char * filename,int flags,int mode) */ asmlinkage int sys_creat(const char * pathname, int mode) { - return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); + int ret; + + lock_kernel(); + ret = sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); + unlock_kernel(); + return ret; } #endif @@ -632,6 +706,7 @@ asmlinkage int sys_close(unsigned int fd) struct file * filp; struct files_struct * files; + lock_kernel(); files = current->files; error = -EBADF; if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) { @@ -640,6 +715,7 @@ asmlinkage int sys_close(unsigned int fd) files->fd[fd] = NULL; error = close_fp(filp); } + unlock_kernel(); return error; } @@ -649,10 +725,16 @@ asmlinkage int sys_close(unsigned int fd) */ asmlinkage int sys_vhangup(void) { + int ret = -EPERM; + + lock_kernel(); if (!suser()) - return -EPERM; + goto out; /* If there is a controlling tty, hang it up */ if (current->tty) tty_vhangup(current->tty); - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } diff --git a/fs/proc/Makefile b/fs/proc/Makefile index eb3c806616ae..e438f26f2638 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -10,6 +10,14 @@ O_TARGET := proc.o O_OBJS := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o OX_OBJS := procfs_syms.o -M_OBJS := $(O_TARGET) +M_OBJS := + +ifeq ($(CONFIG_SUN_OPENPROMFS),y) +O_OBJS += openpromfs.o +else + ifeq ($(CONFIG_SUN_OPENPROMFS),m) + M_OBJS += openpromfs.o + endif +endif include $(TOPDIR)/Rules.make diff --git a/fs/proc/array.c b/fs/proc/array.c index 99f9766e87b0..4f5c9e8acca0 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1057,6 +1058,9 @@ static long get_root_array(char * page, int type, char **start, case PROC_STAT: return get_kstat(page); + case PROC_SLABINFO: + return get_slabinfo(page); + case PROC_DEVICES: return get_device_list(page); @@ -1180,7 +1184,7 @@ static struct file_operations proc_array_operations = { array_read, NULL, /* array_write */ NULL, /* array_readdir */ - NULL, /* array_select */ + NULL, /* array_poll */ NULL, /* array_ioctl */ NULL, /* mmap */ NULL, /* no special open code */ @@ -1226,7 +1230,7 @@ static struct file_operations proc_arraylong_operations = { arraylong_read, NULL, /* array_write */ NULL, /* array_readdir */ - NULL, /* array_select */ + NULL, /* array_poll */ NULL, /* array_ioctl */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/proc/base.c b/fs/proc/base.c index 364cc58a034e..28cd61f5f995 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -19,7 +19,7 @@ static struct file_operations proc_base_operations = { NULL, /* read - bad */ NULL, /* write - bad */ proc_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8d4201844589..a0db8223a57b 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -21,7 +21,7 @@ static struct file_operations proc_fd_operations = { NULL, /* read - bad */ NULL, /* write - bad */ proc_readfd, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/proc/link.c b/fs/proc/link.c index cd79cce0734b..bbaab7c41ffc 100644 --- a/fs/proc/link.c +++ b/fs/proc/link.c @@ -33,7 +33,7 @@ static struct file_operations proc_fd_link_operations = { NULL, /* read - bad */ NULL, /* write - bad */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* very special open code */ diff --git a/fs/proc/mem.c b/fs/proc/mem.c index 0a0ac25e9abf..29080d69a23d 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -314,7 +314,7 @@ static struct file_operations proc_mem_operations = { mem_read, mem_write, NULL, /* mem_readdir */ - NULL, /* mem_select */ + NULL, /* mem_poll */ NULL, /* mem_ioctl */ mem_mmap, /* mmap */ NULL, /* no special open code */ diff --git a/fs/proc/net.c b/fs/proc/net.c index 7f11b86968c6..2574875697a9 100644 --- a/fs/proc/net.c +++ b/fs/proc/net.c @@ -88,7 +88,7 @@ static struct file_operations proc_net_operations = { proc_readnet, /* read - bad */ NULL, /* write - bad */ NULL, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c index 44f5979a3344..e41a430e7cd6 100644 --- a/fs/proc/openpromfs.c +++ b/fs/proc/openpromfs.c @@ -1,4 +1,4 @@ -/* $Id: openpromfs.c,v 1.9 1996/12/23 05:54:21 davem Exp $ +/* $Id: openpromfs.c,v 1.12 1997/01/26 07:14:18 davem Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -462,7 +463,7 @@ static struct file_operations openpromfs_prop_ops = { property_read, /* read */ property_write, /* write - bad */ NULL, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -495,7 +496,7 @@ static struct file_operations openpromfs_nodenum_ops = { nodenum_read, /* read */ NULL, /* write - bad */ NULL, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -528,7 +529,7 @@ static struct file_operations openprom_alias_operations = { NULL, /* read - bad */ NULL, /* write - bad */ openpromfs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -909,7 +910,11 @@ static int openpromfs_unlink (struct inode *dir, const char *name, int len) } /* {{{ init section */ +#ifndef MODULE +__initfunc(static int check_space (u16 n)) +#else static int check_space (u16 n) +#endif { unsigned long pages; @@ -929,7 +934,11 @@ static int check_space (u16 n) return 0; } +#ifndef MODULE +__initfunc(static u16 get_nodes (u16 parent, u32 node)) +#else static u16 get_nodes (u16 parent, u32 node) +#endif { char *p; u16 n = last_node++, i; @@ -1043,8 +1052,11 @@ void openpromfs_use (struct inode *inode, int inc) #ifndef MODULE #define RET(x) -void openpromfs_init (void) +__initfunc(void openpromfs_init (void)) #else + +EXPORT_NO_SYMBOLS; + #define RET(x) -x int init_module (void) #endif @@ -1062,7 +1074,9 @@ int init_module (void) } nodes[last_node].first_prop = first_prop; proc_openprom_iops = proc_openprom_register (openpromfs_readdir, - openpromfs_lookup, openpromfs_use, &devices); + openpromfs_lookup, + openpromfs_use, + &devices); return RET(0); } diff --git a/fs/proc/root.c b/fs/proc/root.c index 834362397b73..a3e4d541ab5c 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -41,7 +41,7 @@ static struct file_operations proc_dir_operations = { NULL, /* read - bad */ NULL, /* write - bad */ proc_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -82,7 +82,7 @@ static struct file_operations proc_root_operations = { NULL, /* read - bad */ NULL, /* write - bad */ proc_root_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -255,7 +255,7 @@ static struct file_operations proc_openprom_operations = { #else NULL, /* readdir */ #endif - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ @@ -514,6 +514,10 @@ static struct proc_dir_entry proc_root_profile = { PROC_PROFILE, 7, "profile", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, }; +static struct proc_dir_entry proc_root_slab = { + PROC_SLABINFO, 8, "slabinfo", + S_IFREG | S_IRUGO, 1, 0, 0, +}; void proc_root_init(void) { @@ -576,6 +580,8 @@ void proc_root_init(void) proc_register(&proc_root, &proc_openprom); #endif + proc_register(&proc_root, &proc_root_slab); + if (prof_shift) { proc_register(&proc_root, &proc_root_profile); } diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c index 447314eab3af..b1e77398c4a9 100644 --- a/fs/proc/scsi.c +++ b/fs/proc/scsi.c @@ -46,7 +46,7 @@ static struct file_operations proc_scsi_operations = { proc_readscsi, /* read */ proc_writescsi, /* write */ proc_readdir, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/read_write.c b/fs/read_write.c index 74b9e5824b5a..dd409230157f 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include @@ -60,6 +62,7 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin) struct file * file; struct inode * inode; + lock_kernel(); retval = -EBADF; if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || @@ -70,6 +73,7 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin) goto bad; retval = llseek(inode, file, offset, origin); bad: + unlock_kernel(); return retval; } @@ -82,6 +86,7 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, struct inode * inode; long long offset; + lock_kernel(); retval = -EBADF; if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || @@ -101,8 +106,8 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, if (retval) retval = -EFAULT; } - bad: + unlock_kernel(); return retval; } @@ -113,6 +118,7 @@ asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count) struct inode * inode; long (*read)(struct inode *, struct file *, char *, unsigned long); + lock_kernel(); error = -EBADF; file = fget(fd); if (!file) @@ -133,6 +139,7 @@ asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count) out: fput(file, inode); bad_file: + unlock_kernel(); return error; } @@ -143,6 +150,7 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count struct inode * inode; long (*write)(struct inode *, struct file *, const char *, unsigned long); + lock_kernel(); error = -EBADF; file = fget(fd); if (!file) @@ -164,6 +172,7 @@ asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count out: fput(file, inode); bad_file: + unlock_kernel(); return error; } @@ -259,26 +268,34 @@ asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigne { struct file * file; struct inode * inode; + long err = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode)) - return -EBADF; + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + goto out; if (!(file->f_mode & 1)) - return -EBADF; - return do_readv_writev(VERIFY_WRITE, inode, file, vector, count); + goto out; + err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count); +out: + unlock_kernel(); + return err; } asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count) { - int error; + int error = -EBADF; struct file * file; struct inode * inode; - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode)) - return -EBADF; + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + goto out; if (!(file->f_mode & 2)) - return -EBADF; + goto out; down(&inode->i_sem); error = do_readv_writev(VERIFY_READ, inode, file, vector, count); up(&inode->i_sem); +out: + unlock_kernel(); return error; } diff --git a/fs/readdir.c b/fs/readdir.c index e81415644cd5..aaea5b45fca2 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -55,23 +57,28 @@ static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count) { - int error; + int error = -EBADF; struct file * file; struct readdir_callback buf; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + goto out; error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent)); if (error) - return error; + goto out; buf.count = 0; buf.dirent = dirent; error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); if (error < 0) - return error; - return buf.count; + goto out; + error = buf.count; +out: + unlock_kernel(); + return error; } /* @@ -121,25 +128,32 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) struct file * file; struct linux_dirent * lastdirent; struct getdents_callback buf; - int error; + int error = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; + goto out; error = verify_area(VERIFY_WRITE, dirent, count); if (error) - return error; + goto out; buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = file->f_op->readdir(file->f_inode, file, &buf, filldir); if (error < 0) - return error; + goto out; lastdirent = buf.previous; - if (!lastdirent) - return buf.error; - put_user(file->f_pos, &lastdirent->d_off); - return count - buf.count; + if (!lastdirent) { + error = buf.error; + } else { + put_user(file->f_pos, &lastdirent->d_off); + error = count - buf.count; + } +out: + unlock_kernel(); + return error; } diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index a43b902cf7a3..1ea700538af0 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -476,7 +476,7 @@ static struct file_operations romfs_file_operations = { generic_file_read, /* read */ NULL, /* write - bad */ NULL, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl */ generic_file_mmap, /* mmap */ NULL, /* open */ @@ -513,7 +513,7 @@ static struct file_operations romfs_dir_operations = { NULL, /* read */ NULL, /* write - bad */ romfs_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ diff --git a/fs/select.c b/fs/select.c index 1528072f69b2..8ab7d229f4ab 100644 --- a/fs/select.c +++ b/fs/select.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -274,11 +276,11 @@ __zero_fd_set((nr)-1, (unsigned long *) (fdp)) */ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - int error; + int error = -EINVAL; fd_set_buffer fds; unsigned long timeout; - error = -EINVAL; + lock_kernel(); if (n < 0) goto out; if (n > NR_OPEN) @@ -328,6 +330,7 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct set_fd_set(n, outp, &fds.res_out); set_fd_set(n, exp, &fds.res_ex); out: + unlock_kernel(); return error; } @@ -373,27 +376,30 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait) asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout) { - int i, count, fdcount; + int i, count, fdcount, err = -EINVAL; struct pollfd * fds, *fds1; poll_table wait_table; struct poll_table_entry *entry; + lock_kernel(); if (nfds > NR_OPEN) - return -EINVAL; + goto out; + err = -ENOMEM; entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL); if (!entry) - return -ENOMEM; + goto out; fds = (struct pollfd *) kmalloc(nfds*sizeof(struct pollfd), GFP_KERNEL); if (!fds) { free_page((unsigned long) entry); - return -ENOMEM; + goto out; } + err = -EFAULT; if (copy_from_user(fds, ufds, nfds*sizeof(struct pollfd))) { free_page((unsigned long)entry); kfree(fds); - return -EFAULT; + goto out; } if (timeout < 0) @@ -419,6 +425,10 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout) } kfree(fds1); if (!fdcount && (current->signal & ~current->blocked)) - fdcount = -EINTR; - return fdcount; + err = -EINTR; + else + err = fdcount; +out: + unlock_kernel(); + return err; } diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index a07d135174e0..e23dbb9796a2 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -56,7 +56,7 @@ static struct file_operations smb_dir_operations = smb_dir_read, /* read - bad */ NULL, /* write - bad */ smb_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ smb_ioctl, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 525c78ab91cc..93c57e38f6f2 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -215,7 +215,7 @@ static struct file_operations smb_file_operations = smb_file_read, /* read */ smb_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ smb_ioctl, /* ioctl */ smb_mmap, /* mmap */ NULL, /* open */ diff --git a/fs/stat.c b/fs/stat.c index 612d4be40b57..4928baa8ab53 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include @@ -112,11 +114,14 @@ asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf) struct inode * inode; int error; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; + goto out; error = cp_old_stat(inode,statbuf); iput(inode); +out: + unlock_kernel(); return error; } #endif @@ -126,11 +131,14 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf) struct inode * inode; int error; + lock_kernel(); error = namei(filename,&inode); if (error) - return error; + goto out; error = cp_new_stat(inode,statbuf); iput(inode); +out: + unlock_kernel(); return error; } @@ -145,11 +153,14 @@ asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf) struct inode * inode; int error; + lock_kernel(); error = lnamei(filename,&inode); if (error) - return error; + goto out; error = cp_old_stat(inode,statbuf); iput(inode); +out: + unlock_kernel(); return error; } @@ -160,11 +171,14 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf) struct inode * inode; int error; + lock_kernel(); error = lnamei(filename,&inode); if (error) - return error; + goto out; error = cp_new_stat(inode,statbuf); iput(inode); +out: + unlock_kernel(); return error; } @@ -178,10 +192,15 @@ asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf) { struct file * f; struct inode * inode; + int ret = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode)) - return -EBADF; - return cp_old_stat(inode,statbuf); + goto out; + ret = cp_old_stat(inode,statbuf); +out: + unlock_kernel(); + return ret; } #endif @@ -190,28 +209,38 @@ asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf) { struct file * f; struct inode * inode; + int err = -EBADF; + lock_kernel(); if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode)) - return -EBADF; - return cp_new_stat(inode,statbuf); + goto out; + err = cp_new_stat(inode,statbuf); +out: + unlock_kernel(); + return err; } asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz) { struct inode * inode; - int error; + int error = -EINVAL; + lock_kernel(); if (bufsiz <= 0) - return -EINVAL; + goto out; error = verify_area(VERIFY_WRITE,buf,bufsiz); if (error) - return error; + goto out; error = lnamei(path,&inode); if (error) - return error; + goto out; + error = -EINVAL; if (!inode->i_op || !inode->i_op->readlink) { iput(inode); - return -EINVAL; + goto out; } - return inode->i_op->readlink(inode,buf,bufsiz); + error = inode->i_op->readlink(inode,buf,bufsiz); +out: + unlock_kernel(); + return error; } diff --git a/fs/super.c b/fs/super.c index b5b66b6c650e..f979c972a23f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -246,6 +248,7 @@ asmlinkage int sys_sysfs(int option, ...) int retval = -EINVAL; unsigned int index; + lock_kernel(); va_start(args, option); switch (option) { case 1: @@ -262,6 +265,7 @@ asmlinkage int sys_sysfs(int option, ...) break; } va_end(args); + unlock_kernel(); return retval; } @@ -473,13 +477,15 @@ asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf) struct ustat tmp; struct statfs sbuf; unsigned long old_fs; + int err = -EINVAL; + lock_kernel(); s = get_super(to_kdev_t(dev)); if (s == NULL) - return -EINVAL; - + goto out; + err = -ENOSYS; if (!(s->s_op->statfs)) - return -ENOSYS; + goto out; old_fs = get_fs(); set_fs(get_ds()); @@ -490,7 +496,10 @@ asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf) tmp.f_tfree = sbuf.f_bfree; tmp.f_tinode = sbuf.f_ffree; - return copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0; + err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0; +out: + unlock_kernel(); + return err; } static struct super_block * read_super(kdev_t dev,const char *name,int flags, @@ -625,27 +634,30 @@ asmlinkage int sys_umount(char * name) { struct inode * inode; kdev_t dev; - int retval; + int retval = -EPERM; struct inode dummy_inode; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; retval = namei(name, &inode); if (retval) { retval = lnamei(name, &inode); if (retval) - return retval; + goto out; } if (S_ISBLK(inode->i_mode)) { dev = inode->i_rdev; + retval = -EACCES; if (IS_NODEV(inode)) { iput(inode); - return -EACCES; + goto out; } } else { + retval = -EINVAL; if (!inode->i_sb || inode != inode->i_sb->s_mounted) { iput(inode); - return -EINVAL; + goto out; } dev = inode->i_sb->s_dev; iput(inode); @@ -653,9 +665,10 @@ asmlinkage int sys_umount(char * name) dummy_inode.i_rdev = dev; inode = &dummy_inode; } + retval = -ENXIO; if (MAJOR(dev) >= MAX_BLKDEV) { iput(inode); - return -ENXIO; + goto out; } retval = do_umount(dev,0); if (!retval) { @@ -667,10 +680,11 @@ asmlinkage int sys_umount(char * name) } if (inode != &dummy_inode) iput(inode); - if (retval) - return retval; - fsync_dev(dev); - return 0; + if (!retval) + fsync_dev(dev); +out: + unlock_kernel(); + return retval; } /* @@ -814,9 +828,9 @@ static int copy_mount_options (const void * data, unsigned long *where) * information (or be NULL). * * NOTE! As old versions of mount() didn't use this setup, the flags - * has to have a special 16-bit magic number in the hight word: + * have to have a special 16-bit magic number in the high word: * 0xC0ED. If this magic word isn't present, the flags and data info - * isn't used, as the syscall assumes we are talking to an older + * aren't used, as the syscall assumes we are talking to an older * version that didn't understand them. */ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, @@ -826,54 +840,60 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, struct inode * inode; struct file_operations * fops; kdev_t dev; - int retval; + int retval = -EPERM; const char * t; unsigned long flags = 0; unsigned long page = 0; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { retval = copy_mount_options (data, &page); if (retval < 0) - return retval; + goto out; retval = do_remount(dir_name, new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, (char *) page); free_page(page); - return retval; + goto out; } retval = copy_mount_options (type, &page); if (retval < 0) - return retval; + goto out; fstype = get_fs_type((char *) page); free_page(page); + retval = -ENODEV; if (!fstype) - return -ENODEV; + goto out; t = fstype->name; fops = NULL; if (fstype->requires_dev) { retval = namei(dev_name, &inode); if (retval) - return retval; + goto out; + retval = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) { iput(inode); - return -ENOTBLK; + goto out; } + retval = -EACCES; if (IS_NODEV(inode)) { iput(inode); - return -EACCES; + goto out; } dev = inode->i_rdev; + retval = -ENXIO; if (MAJOR(dev) >= MAX_BLKDEV) { iput(inode); - return -ENXIO; + goto out; } fops = get_blkfops(MAJOR(dev)); + retval = -ENOTBLK; if (!fops) { iput(inode); - return -ENOTBLK; + goto out; } if (fops->open) { struct file dummy; /* allows read-write or read-only flag */ @@ -883,13 +903,14 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, retval = fops->open(inode, &dummy); if (retval) { iput(inode); - return retval; + goto out; } } } else { + retval = -EMFILE; if (!(dev = get_unnamed_dev())) - return -EMFILE; + goto out; inode = NULL; } page = 0; @@ -899,7 +920,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, if (retval < 0) { put_unnamed_dev(dev); iput(inode); - return retval; + goto out; } } retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page); @@ -909,6 +930,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, put_unnamed_dev(dev); } iput(inode); +out: + unlock_kernel(); return retval; } diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 52515b4f9ba5..3dd0931cf1ef 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -34,7 +34,7 @@ static struct file_operations sysv_dir_operations = { sysv_dir_read, /* read */ NULL, /* write - bad */ sysv_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 6029051d8a4d..f3aadb509690 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -44,7 +44,7 @@ static struct file_operations sysv_file_operations = { sysv_file_read, /* read */ sysv_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c index 37595a9a0e8b..26ae02abe9d1 100644 --- a/fs/ufs/ufs_dir.c +++ b/fs/ufs/ufs_dir.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_dir.c,v 1.7 1996/05/21 19:01:45 davem Exp $ + * $Id: ufs_dir.c,v 1.8 1997/01/26 07:14:28 davem Exp $ * */ @@ -143,7 +143,7 @@ static struct file_operations ufs_dir_operations = { NULL, /* read */ NULL, /* write */ ufs_readdir, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c index 0fb55d86b9ca..4b479a65ea91 100644 --- a/fs/ufs/ufs_file.c +++ b/fs/ufs/ufs_file.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_file.c,v 1.6 1996/05/19 03:55:48 krioles Exp $ + * $Id: ufs_file.c,v 1.7 1997/01/26 07:14:28 davem Exp $ * */ @@ -18,7 +18,7 @@ static struct file_operations ufs_file_operations = { generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ generic_file_mmap, /* mmap */ NULL, /* open */ diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c index b2487abe4a34..695e243ac4fb 100644 --- a/fs/ufs/ufs_super.c +++ b/fs/ufs/ufs_super.c @@ -8,7 +8,7 @@ * * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * - * $Id: ufs_super.c,v 1.21 1996/12/29 20:48:55 davem Exp $ + * $Id: ufs_super.c,v 1.22 1997/01/16 14:17:41 davem Exp $ * */ diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c index ccfd6d1ae68e..13d2285e6ef4 100644 --- a/fs/ufs/ufs_symlink.c +++ b/fs/ufs/ufs_symlink.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_symlink.c,v 1.6 1996/10/30 06:00:36 davem Exp $ + * $Id: ufs_symlink.c,v 1.7 1997/01/26 07:14:29 davem Exp $ * */ @@ -139,7 +139,7 @@ static struct file_operations ufs_symlink_operations = { NULL, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* select */ + NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 9e0abf55af80..8f8a6bbb6e17 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -791,7 +791,7 @@ static struct file_operations umsdos_dir_operations = { UMSDOS_dir_read, /* read */ NULL, /* write - bad */ UMSDOS_readdir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ UMSDOS_ioctl_dir, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c index d01ef6f87136..cda0e4e8d029 100644 --- a/fs/umsdos/file.c +++ b/fs/umsdos/file.c @@ -66,7 +66,7 @@ struct file_operations umsdos_file_operations = { UMSDOS_file_read, /* read */ UMSDOS_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ NULL, /* no special open is needed */ @@ -100,7 +100,7 @@ struct file_operations umsdos_file_operations_no_bmap = { UMSDOS_file_read, /* read */ UMSDOS_file_write, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ fat_mmap, /* mmap */ NULL, /* no special open is needed */ diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index da07c0d6198d..a2a5364f61a7 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -240,7 +240,7 @@ static struct file_operations umsdos_rdir_operations = { UMSDOS_dir_read, /* read */ NULL, /* write - bad */ UMSDOS_rreaddir, /* readdir */ - NULL, /* select - default */ + NULL, /* poll - default */ UMSDOS_ioctl_dir, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open code */ diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index 7bbcc0ef0b1d..8b6678ae903e 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -116,7 +116,7 @@ static struct file_operations umsdos_symlink_operations = { NULL, /* read */ NULL, /* write */ NULL, /* readdir - bad */ - NULL, /* select - default */ + NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ NULL, /* no special open is needed */ diff --git a/include/asm-alpha/cache.h b/include/asm-alpha/cache.h new file mode 100644 index 000000000000..c1276cb1ec7f --- /dev/null +++ b/include/asm-alpha/cache.h @@ -0,0 +1,12 @@ +/* + * include/asm-alpha/cache.h + */ +#ifndef __ARCH_ALPHA_CACHE_H +#define __ARCH_ALPHA_CACHE_H + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES 32 /* a guess */ + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + +#endif diff --git a/include/asm-alpha/ipsum.h b/include/asm-alpha/ipsum.h deleted file mode 100644 index 8146cb73499e..000000000000 --- a/include/asm-alpha/ipsum.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __ASM_IPSUM_H -#define __ASM_IPSUM_H - -/* - * This routine computes a UDP checksum. - */ -extern inline unsigned short udp_check(struct udphdr *uh, int len, u32 saddr, u32 daddr) -{ - /* uhh.. eventually */ - return 0; -} - -/* - * This routine computes a TCP checksum. - */ -extern inline unsigned short tcp_check(struct tcphdr *th, int len, u32 saddr, u32 daddr) -{ - /* uhh.. eventually */ - return 0; -} - - -/* - * This routine does all the checksum computations that don't - * require anything special (like copying or special headers). - */ - -extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - /* uhh.. eventually */ - return 0; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, which - * always checksum on 4 octet boundaries. - */ - -static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen) -{ - /* uhh.. eventually */ - return 0; -} - -#endif diff --git a/include/asm-alpha/namei.h b/include/asm-alpha/namei.h new file mode 100644 index 000000000000..a03cc1e8b782 --- /dev/null +++ b/include/asm-alpha/namei.h @@ -0,0 +1,21 @@ +/* $Id: namei.h,v 1.1 1996/12/13 14:48:23 jj Exp $ + * linux/include/asm-alpha/namei.h + * + * Included from linux/fs/namei.c + */ + +#ifndef __ALPHA_NAMEI_H +#define __ALPHA_NAMEI_H + +/* These dummy routines maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define translate_namei(pathname, base, follow_links, res_inode) \ + do { } while (0) + +#define translate_open_namei(pathname, flag, mode, res_inode, base) \ + do { } while (0) + +#endif /* __ALPHA_NAMEI_H */ diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h index 3d4e33bdf45c..0e664bb536e1 100644 --- a/include/asm-alpha/processor.h +++ b/include/asm-alpha/processor.h @@ -58,9 +58,6 @@ struct thread_struct { 0 \ } -#define alloc_kernel_stack() __get_free_page(GFP_KERNEL) -#define free_kernel_stack(page) free_page((page)) - #include /* @@ -84,4 +81,13 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t) */ extern void start_thread(struct pt_regs *, unsigned long, unsigned long); +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + +/* Allocation and freeing of basic task resources. */ +#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL) +#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL) +#define free_task_struct(p) kfree(p) +#define free_kernel_stack(page) free_page((page)) + #endif /* __ASM_ALPHA_PROCESSOR_H */ diff --git a/include/asm-alpha/smp_lock.h b/include/asm-alpha/smp_lock.h new file mode 100644 index 000000000000..0a0182e6dde5 --- /dev/null +++ b/include/asm-alpha/smp_lock.h @@ -0,0 +1,15 @@ +#ifndef __ALPHA_SMPLOCK_H +#define __ALPHA_SMPLOCK_H + +#ifndef __SMP__ + +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) + +#else + +#error "We do not support SMP on alpha yet" + +#endif /* __SMP__ */ + +#endif /* __ALPHA_SMPLOCK_H */ diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h index b9bc4e77239f..2d595e20aded 100644 --- a/include/asm-alpha/uaccess.h +++ b/include/asm-alpha/uaccess.h @@ -71,6 +71,24 @@ extern inline int verify_area(int type, const void * addr, unsigned long size) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) #define __get_user(x,ptr) \ __get_user_nocheck((x),(ptr),sizeof(*(ptr))) + +/* + * The "xxx_ret" versions return constant specified in third argument, if + * something bad happens. These macros can be optimized for the + * case of just returning from the function xxx_ret is used. + */ + +#define put_user_ret(x,ptr,ret) ({ \ +if (put_user(x,ptr)) return ret; }) + +#define get_user_ret(x,ptr,ret) ({ \ +if (get_user(x,ptr)) return ret; }) + +#define __put_user_ret(x,ptr,ret) ({ \ +if (__put_user(x,ptr)) return ret; }) + +#define __get_user_ret(x,ptr,ret) ({ \ +if (__get_user(x,ptr)) return ret; }) /* * The "lda %1, 2b-1b(%0)" bits are magic to get the assembler to @@ -355,6 +373,16 @@ extern void __copy_user(void); __cu_len; \ }) +#define copy_to_user_ret(to,from,n,retval) ({ \ +if (copy_to_user(to,from,n)) \ + return retval; \ +}) + +#define copy_from_user_ret(to,from,n,retval) ({ \ +if (copy_from_user(to,from,n)) \ + return retval; \ +}) + extern void __clear_user(void); #define clear_user(to,n) \ diff --git a/include/asm-i386/cache.h b/include/asm-i386/cache.h new file mode 100644 index 000000000000..50c1dbe8fedc --- /dev/null +++ b/include/asm-i386/cache.h @@ -0,0 +1,16 @@ +/* + * include/asm-i386/cache.h + */ +#ifndef __ARCH_I386_CACHE_H +#define __ARCH_I386_CACHE_H + +/* bytes per L1 cache line */ +#if CPU==586 || CPU==686 +#define L1_CACHE_BYTES 32 +#else +#define L1_CACHE_BYTES 16 +#endif + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + +#endif diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index 030f59485b80..374b511bbb1d 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -126,20 +126,6 @@ extern void enable_irq(unsigned int); #ifdef __SMP__ -#ifndef __SMP_PROF__ -#define SMP_PROF_INT_SPINS -#define SMP_PROF_IPI_CNT -#else -#define SMP_PROF_INT_SPINS "incl "SYMBOL_NAME_STR(smp_spins)"(,%eax,4)\n\t" -#define SMP_PROF_IPI_CNT "incl "SYMBOL_NAME_STR(ipi_count)"\n\t" -#endif - -#define GET_PROCESSOR_ID \ - "movl "SYMBOL_NAME_STR(apic_reg)", %edx\n\t" \ - "movl 32(%edx), %eax\n\t" \ - "shrl $24,%eax\n\t" \ - "andb $0x0F,%al\n\t" - #define GET_CURRENT \ "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \ "movl 32(%ebx), %ebx\n\t" \ @@ -147,132 +133,15 @@ extern void enable_irq(unsigned int); "andl $0x3C,%ebx\n\t" \ "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t" -#define ENTER_KERNEL \ - "pushl %eax\n\t" \ - "pushl %edx\n\t" \ - "pushfl\n\t" \ - "cli\n\t" \ - GET_PROCESSOR_ID \ - "btsl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \ - "1: " \ - "lock\n\t" \ - "btsl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \ - "jnc 3f\n\t" \ - "cmpb "SYMBOL_NAME_STR(active_kernel_processor)", %al\n\t" \ - "je 4f\n\t" \ - "2: " \ - SMP_PROF_INT_SPINS \ - "btl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \ - "jnc 5f\n\t" \ - "lock\n\t" \ - "btrl %al, "SYMBOL_NAME_STR(smp_invalidate_needed)"\n\t" \ - "jnc 5f\n\t" \ - "movl %cr3,%edx\n\t" \ - "movl %edx,%cr3\n" \ - "5: btl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \ - "jc 2b\n\t" \ - "jmp 1b\n\t" \ - "3: " \ - "movb %al, "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \ - "4: " \ - "incl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \ - "popfl\n\t" \ - "popl %edx\n\t" \ - "popl %eax\n\t" +#else -#define LEAVE_KERNEL \ - GET_PROCESSOR_ID \ - "btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \ - "pushfl\n\t" \ - "cli\n\t" \ - "decl "SYMBOL_NAME_STR(kernel_counter)"\n\t" \ - "jnz 1f\n\t" \ - "movb $" STR (NO_PROC_ID) ", "SYMBOL_NAME_STR(active_kernel_processor)"\n\t" \ - "lock\n\t" \ - "btrl $0, "SYMBOL_NAME_STR(kernel_flag)"\n\t" \ - "1: " \ - "popfl\n\t" - - -/* - * the syscall count inc is a gross hack because ret_from_syscall is used by both irq and - * syscall return paths (urghh). - */ - -#define BUILD_IRQ(chip,nr,mask) \ -asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ -__asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ - SAVE_ALL \ - ENTER_KERNEL \ - ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ - "sti\n\t" \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ - GET_CURRENT \ - "jmp ret_from_sys_call\n" \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ENTER_KERNEL \ - ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ - "addl $4,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - LEAVE_KERNEL \ - RESTORE_MOST \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ENTER_KERNEL \ - ACK_##chip(mask,(nr&7)) \ - LEAVE_KERNEL \ - RESTORE_MOST); +#define GET_CURRENT \ + "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t" - -#define BUILD_TIMER_IRQ(chip,nr,mask) \ -asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ -__asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ -SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ - SAVE_ALL \ - ENTER_KERNEL \ - ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - "cli\n\t" \ - UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ - GET_CURRENT \ - "jmp ret_from_sys_call\n"); +#endif + +#ifdef __SMP__ - /* * Message pass must be a fast IRQ.. */ @@ -286,9 +155,7 @@ __asm__( \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ - ENTER_KERNEL \ ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ "sti\n\t" \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ @@ -297,17 +164,11 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - GET_PROCESSOR_ID \ - "btrl $" STR(SMP_FROM_INT) ","SYMBOL_NAME_STR(smp_proc_in_lock)"(,%eax,4)\n\t" \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ - GET_CURRENT \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ - SMP_PROF_IPI_CNT \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ "addl $4,%esp\n\t" \ @@ -327,8 +188,6 @@ __asm__( \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ - ENTER_KERNEL \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ "sti\n\t" \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ @@ -336,15 +195,10 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \ "addl $8,%esp\n\t" \ "cli\n\t" \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \ - GET_CURRENT \ "jmp ret_from_sys_call\n"); -#else -#define GET_CURRENT \ - "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t" - +#endif /* __SMP__ */ + #define BUILD_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ asmlinkage void FAST_IRQ_NAME(nr); \ @@ -355,7 +209,6 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ "sti\n\t" \ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ @@ -364,20 +217,16 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - GET_CURRENT \ "jmp ret_from_sys_call\n" \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ SAVE_MOST \ ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \ "pushl $" #nr "\n\t" \ "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ "addl $4,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ RESTORE_MOST \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ @@ -397,7 +246,6 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $-"#nr"-2\n\t" \ SAVE_ALL \ ACK_##chip(mask,(nr&7)) \ - "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ "movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "pushl $" #nr "\n\t" \ @@ -405,9 +253,6 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "addl $8,%esp\n\t" \ "cli\n\t" \ UNBLK_##chip(mask) \ - "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \ - GET_CURRENT \ "jmp ret_from_sys_call\n"); -#endif -#endif +#endif /* _ASM_IRQ_H */ diff --git a/include/asm-i386/namei.h b/include/asm-i386/namei.h new file mode 100644 index 000000000000..c0dc3b3f80dd --- /dev/null +++ b/include/asm-i386/namei.h @@ -0,0 +1,21 @@ +/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $ + * linux/include/asm-i386/namei.h + * + * Included from linux/fs/namei.c + */ + +#ifndef __I386_NAMEI_H +#define __I386_NAMEI_H + +/* These dummy routines maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define translate_namei(pathname, base, follow_links, res_inode) \ + do { } while (0) + +#define translate_open_namei(pathname, flag, mode, res_inode, base) \ + do { } while (0) + +#endif /* __I386_NAMEI_H */ diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index f3dc8ff762d9..d95291598a28 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -140,9 +140,6 @@ struct thread_struct { NULL, 0, 0, 0, 0 /* vm86_info */, \ } -#define alloc_kernel_stack() __get_free_page(GFP_KERNEL) -#define free_kernel_stack(page) free_page((page)) - #define start_thread(regs, new_eip, new_esp) do {\ unsigned long seg = USER_DS; \ __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); \ @@ -155,6 +152,9 @@ struct thread_struct { regs->esp = new_esp; \ } while (0) +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + /* * Return saved PC of a blocked thread. */ @@ -163,4 +163,10 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t) return ((unsigned long *)t->esp)[3]; } +/* Allocation and freeing of basic task resources. */ +#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL) +#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL) +#define free_task_struct(p) kfree(p) +#define free_kernel_stack(page) free_page((page)) + #endif /* __ASM_I386_PROCESSOR_H */ diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index ff0caafe07da..0eb579ebf69b 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -192,8 +192,6 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_reschedule_irq(int cpl, struct pt_regs *regs); extern unsigned long ipi_count; extern void smp_invalidate_rcv(void); /* Process an NMI */ -extern volatile unsigned long kernel_counter; -extern volatile unsigned long syscall_count; /* * General functions that each host system must provide. @@ -204,7 +202,7 @@ extern void smp_boot_cpus(void); extern void smp_store_cpu_info(int id); /* Store per cpu info (like the initial udelay numbers */ extern volatile unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */ -extern volatile unsigned long smp_process_available; +extern volatile int smp_process_available; /* * APIC handlers: Note according to the Intel specification update @@ -235,6 +233,52 @@ extern __inline int smp_processor_id(void) return GET_APIC_ID(apic_read(APIC_ID)); } +/* These read/change the "processes available" counter in the scheduler. */ +extern __inline__ __volatile__ void inc_smp_counter(volatile int *ctr) +{ + int cpu = smp_processor_id(); + while(set_bit(31, ctr)) + { + while(test_bit(31,ctr)) + { + if(clear_bit(cpu,&smp_invalidate_needed)) + { + unsigned long tmpreg; + __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3" + : "=r" (tmpreg) : : "memory"); + set_bit(cpu,&cpu_callin_map[0]); + } + } + } + *ctr = (*ctr + 1); + clear_bit(31, ctr); +} + +extern __inline__ __volatile__ void dec_smp_counter(volatile int *ctr) +{ + int cpu = smp_processor_id(); + while(set_bit(31, ctr)) + { + while(test_bit(31,ctr)) + { + if(clear_bit(cpu,&smp_invalidate_needed)) + { + unsigned long tmpreg; + __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3" + : "=r" (tmpreg) : : "memory"); + set_bit(cpu,&cpu_callin_map[0]); + } + } + } + *ctr = (*ctr - 1); + clear_bit(31, ctr); +} + +extern __inline__ __volatile__ int read_smp_counter(volatile int *ctr) +{ + return (*ctr & 0x7fffffff); +} + #endif /* !ASSEMBLY */ #define NO_PROC_ID 0xFF /* No processor magic marker */ diff --git a/include/asm-i386/smp_lock.h b/include/asm-i386/smp_lock.h index a736f0a6c8bd..8a660d6bf218 100644 --- a/include/asm-i386/smp_lock.h +++ b/include/asm-i386/smp_lock.h @@ -1,69 +1,50 @@ #ifndef __I386_SMPLOCK_H #define __I386_SMPLOCK_H -#ifdef __SMP__ +#ifndef __SMP__ -/* - * Locking the kernel - */ - -extern __inline void lock_kernel(void) +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) + +#else + +/* Locking the kernel */ +extern __inline__ void lock_kernel(void) { - unsigned long flags; - int proc = smp_processor_id(); + int cpu = smp_processor_id(); - save_flags(flags); - cli(); - /* set_bit works atomic in SMP machines */ - while(set_bit(0, (void *)&kernel_flag)) - { - /* - * We just start another level if we have the lock - */ - if (proc == active_kernel_processor) - break; - do - { -#ifdef __SMP_PROF__ - smp_spins[smp_processor_id()]++; -#endif - /* - * Doing test_bit here doesn't lock the bus - */ - if (test_bit(proc, (void *)&smp_invalidate_needed)) - if (clear_bit(proc, (void *)&smp_invalidate_needed)) - local_flush_tlb(); - } - while(test_bit(0, (void *)&kernel_flag)); - } - /* - * We got the lock, so tell the world we are here and increment - * the level counter - */ - active_kernel_processor = proc; - kernel_counter++; - restore_flags(flags); + __asm__ __volatile__(" + pushfl + cli + cmpl $0, %0 + jne 0f + movl $0f, %%eax + jmp __lock_kernel +0: + incl %0 + popfl +" : + : "m" (current_set[cpu]->lock_depth), "d" (cpu) + : "ax", "memory"); } -extern __inline void unlock_kernel(void) +extern __inline__ void unlock_kernel(void) { - unsigned long flags; - save_flags(flags); - cli(); - /* - * If it's the last level we have in the kernel, then - * free the lock - */ - if (kernel_counter == 0) - panic("Kernel counter wrong.\n"); /* FIXME: Why is kernel_counter sometimes 0 here? */ - - if(! --kernel_counter) - { - active_kernel_processor = NO_PROC_ID; - clear_bit(0, (void *)&kernel_flag); - } - restore_flags(flags); + __asm__ __volatile__(" + pushfl + cli + decl %0 + jnz 1f + movb %1, active_kernel_processor + lock + btrl $0, kernel_flag +1: + popfl +" : /* no outputs */ + : "m" (current->lock_depth), "i" (NO_PROC_ID) + : "ax", "memory"); } -#endif -#endif +#endif /* __SMP__ */ + +#endif /* __I386_SMPLOCK_H */ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index cef63f6fe0bd..ab5739be3d0a 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -74,9 +74,6 @@ __asm__("str %%ax\n\t" \ __asm__ __volatile__("fwait"); \ prev->flags&=~PF_USEDFPU; \ } \ - prev->lock_depth=syscall_count; \ - kernel_counter+=next->lock_depth-prev->lock_depth; \ - syscall_count=next->lock_depth; \ __asm__("pushl %%edx\n\t" \ "movl "SYMBOL_NAME_STR(apic_reg)",%%edx\n\t" \ "movl 0x20(%%edx), %%edx\n\t" \ diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 40a7956d8c9c..19a25ff75198 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -108,6 +108,25 @@ extern unsigned long search_exception_table(unsigned long); #define __put_user(x,ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +/* + * The "xxx_ret" versions return constant specified in third argument, if + * something bad happens. These macros can be optimized for the + * case of just returning from the function xxx_ret is used. + */ + +#define put_user_ret(x,ptr,ret) ({ \ +if (put_user(x,ptr)) return ret; }) + +#define get_user_ret(x,ptr,ret) ({ \ +if (get_user(x,ptr)) return ret; }) + +#define __put_user_ret(x,ptr,ret) ({ \ +if (__put_user(x,ptr)) return ret; }) + +#define __get_user_ret(x,ptr,ret) ({ \ +if (__get_user(x,ptr)) return ret; }) + + extern long __put_user_bad(void); @@ -387,6 +406,15 @@ __constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n) __constant_copy_from_user((to),(from),(n)) : \ __generic_copy_from_user((to),(from),(n))) +#define copy_to_user_ret(to,from,n,retval) ({ \ +if (copy_to_user(to,from,n)) \ + return retval; \ +}) + +#define copy_from_user_ret(to,from,n,retval) ({ \ +if (copy_from_user(to,from,n)) \ + return retval; \ +}) #define __copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ diff --git a/include/asm-m68k/cache.h b/include/asm-m68k/cache.h new file mode 100644 index 000000000000..25bd27687857 --- /dev/null +++ b/include/asm-m68k/cache.h @@ -0,0 +1,12 @@ +/* + * include/asm-m68k/cache.h + */ +#ifndef __ARCH_M68K_CACHE_H +#define __ARCH_M68K_CACHE_H + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES 32 /* a guess */ + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + +#endif diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h index 1add2d17ffb8..d96f693d4e0b 100644 --- a/include/asm-m68k/processor.h +++ b/include/asm-m68k/processor.h @@ -54,9 +54,6 @@ struct thread_struct { {0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \ } -#define alloc_kernel_stack() __get_free_page(GFP_KERNEL) -#define free_kernel_stack(page) free_page((page)) - /* * Do necessary setup to start up a newly executed thread. */ @@ -78,6 +75,9 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, wrusp(usp); } +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + /* * Return saved PC of a blocked thread. */ @@ -94,4 +94,10 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t) return sw->retpc; } +/* Allocation and freeing of basic task resources. */ +#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL) +#define alloc_kernel_stack(p) __get_free_page(GFP_KERNEL) +#define free_task_struct(p) kfree(p) +#define free_kernel_stack(page) free_page((page)) + #endif diff --git a/include/asm-mips/cache.h b/include/asm-mips/cache.h new file mode 100644 index 000000000000..604834774e61 --- /dev/null +++ b/include/asm-mips/cache.h @@ -0,0 +1,12 @@ +/* + * include/asm-mips/cache.h + */ +#ifndef __ARCH_MIPS_CACHE_H +#define __ARCH_MIPS_CACHE_H + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES 32 /* a guess */ + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + +#endif diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index d685ffb8d85f..9ccaea0e4f72 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -193,6 +193,9 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) regs->reg29 = sp; } +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + #ifdef __KERNEL__ /* diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h new file mode 100644 index 000000000000..da609f27153c --- /dev/null +++ b/include/asm-ppc/cache.h @@ -0,0 +1,12 @@ +/* + * include/asm-ppc/cache.h + */ +#ifndef __ARCH_PPC_CACHE_H +#define __ARCH_PPC_CACHE_H + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES 32 /* a guess */ + +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) + +#endif diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index 7ed8c73406f7..3632e318b1ee 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -118,15 +118,8 @@ struct thread_struct #define INIT_MMAP { &init_mm, 0, 0x40000000, \ PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC } -#ifdef KERNEL_STACK_BUFFER -/* give a 1 page buffer below the stack - if change then change ppc_machine.h */ -#define alloc_kernel_stack() \ - (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE) -#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1) -#else -#define alloc_kernel_stack() get_free_page(GFP_KERNEL) -#define free_kernel_stack(page) free_page((page)) -#endif +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); /* * Return saved PC of a blocked thread. For now, this is the "user" PC @@ -142,6 +135,20 @@ static inline unsigned long thread_saved_pc(struct thread_struct *t) int _Processor; +/* Allocation and freeing of basic task resources. */ +#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL) +#define free_task_struct(p) kfree(p) + +#ifdef KERNEL_STACK_BUFFER +/* give a 1 page buffer below the stack - if change then change ppc_machine.h */ +#define alloc_kernel_stack() \ + (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE) +#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1) +#else +#define alloc_kernel_stack() get_free_page(GFP_KERNEL) +#define free_kernel_stack(page) free_page((page)) +#endif + #endif /* ASSEMBLY*/ #endif diff --git a/include/asm-sparc/ap1000/DdvReqTable.h b/include/asm-sparc/ap1000/DdvReqTable.h new file mode 100644 index 000000000000..78ffacfd3f5f --- /dev/null +++ b/include/asm-sparc/ap1000/DdvReqTable.h @@ -0,0 +1,107 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * Request table size + */ + +#define TABLE_SIZE 200 + +/* + * Indirect memory address table size + */ + +#define MTABLE_SIZE 1000 + +static inline int INC_T(int a) +{ + return (++a == TABLE_SIZE?0:a); +} + +static inline int INC_ML(int a) +{ + return (++a == MTABLE_SIZE?0:a); +} + +/* + * Status of requiest table + */ + +#define DDV_ERROR_RETURN 0 +#define DDV_NORMAL_RETURN 1 +#define DDV_REQ_FREE 2 +#define DDV_DISKREAD_REQ 3 +#define DDV_DISKWRITE_REQ 4 +#define DDV_RAWREAD_REQ 5 +#define DDV_RAWWRITE_REQ 6 +#define DDV_CACHEPOSTALL_REQ 11 +#define DDV_CACHEFLUSHALL_REQ 12 +#define DDV_CAPACITY_REQ 13 + +/* + * Specify type of interrupt (set by opiu in PBUF1) + */ + +#define DDV_PRINTK_INTR 1 +#define DDV_MLIST_INTR 2 +#define DDV_READY_INTR 3 +#define DDV_REQCOMP_INTR 4 + +struct RequestInformation { + volatile int status; + int rtn; + unsigned bnum; + int argv[8]; +}; + +struct DiskInfo { + u_long blocks; + u_long blk_size; + int pad[8]; + unsigned ptrs[4]; +}; + +struct RequestTable{ + volatile unsigned cell_pointer; /* Cell requiest pointer */ + volatile unsigned ddv_pointer; /* DDV operation pointer */ + struct RequestInformation async_info[TABLE_SIZE]; + volatile unsigned start_mtable; + volatile unsigned end_mtable; + unsigned mtable[MTABLE_SIZE]; +}; + +#define PRINT_BUFS 32 + +struct OPrintBuf { + char *fmt; + int args[6]; +}; + +struct OPrintBufArray { + volatile unsigned option_counter; + volatile unsigned cell_counter; + struct OPrintBuf bufs[PRINT_BUFS]; +}; + +#define ALIGN_SIZE 16 +#define ALIGN_BUFS 128 +#define ALIGN_BUF_SIZE 1024 + +struct AlignBuf { + char *dest; + unsigned size; + int offset; + char buf[ALIGN_BUF_SIZE+2*ALIGN_SIZE]; +}; + +struct OAlignBufArray { + volatile unsigned option_counter; + volatile unsigned cell_counter; + struct AlignBuf bufs[ALIGN_BUFS]; +}; + + diff --git a/include/asm-sparc/ap1000/apbif.h b/include/asm-sparc/ap1000/apbif.h new file mode 100644 index 000000000000..6ef9bf0b6c2d --- /dev/null +++ b/include/asm-sparc/ap1000/apbif.h @@ -0,0 +1,205 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ + +/* +** BIF data registers (system mode) +*/ +#define BIF_DATA (BIF+0x0000) /* BIF send and receive data registe */ +#define BIF_EDATA (BIF+0x0004) /* BIF end data register */ +/* +** BIF data registers (user mode) +*/ +#define UBIF_DATA (UBIF+0x0000) /* BIF send and receive data registe */ +#define UBIF_EDATA (UBIF+0x0004) /* BIF end data register */ + +/* +** BIF scatter and gather parameter register (system mode) +*/ +#define BIF_X0SK (BIF+0x0010) /* initial X-skip register */ +#define BIF_XSK (BIF+0x0014) /* X-skip register */ +#define BIF_XSZ (BIF+0x0018) /* X-size register */ + +#define BIF_Y0SK (BIF+0x001c) /* initial Y-skip register */ +#define BIF_YSK (BIF+0x0020) /* Y-skip register */ +#define BIF_YSZ (BIF+0x0024) /* Y-size register */ + +#define BIF_CX0SK (BIF+0x0028) /* initial counter of X-skip */ +#define BIF_CXSK (BIF+0x002c) /* X-skip counter */ +#define BIF_CXSZ (BIF+0x0030) /* X-size counter */ + +#define BIF_CY0SK (BIF+0x0034) /* initial counter of Y-skip */ +#define BIF_CYSK (BIF+0x0038) /* Y-skip counter */ +#define BIF_CYSZ (BIF+0x003c) /* Y-size counter */ + +#define BIF_TTL (BIF+0x0040) /* number of data transfer register */ +#define BIF_CTTL (BIF+0x0044) /* number of data transfer counter */ + +/* +** BIF scatter and gather parameter register (user mode) +*/ +#define UBIF_X0SK (UBIF+0x0010) /* initial X-skip register */ +#define UBIF_XSK (UBIF+0x0014) /* X-skip register */ +#define UBIF_XSZ (UBIF+0x0018) /* X-size register */ + +#define UBIF_Y0SK (UBIF+0x001c) /* initial Y-skip register */ +#define UBIF_YSK (UBIF+0x0020) /* Y-skip register */ +#define UBIF_YSZ (UBIF+0x0024) /* Y-size register */ + +#define UBIF_CX0SK (UBIF+0x0028) /* initial counter of X-skip */ +#define UBIF_CXSK (UBIF+0x002c) /* X-skip counter */ +#define UBIF_CXSZ (UBIF+0x0030) /* X-size counter */ + +#define UBIF_CY0SK (UBIF+0x0034) /* initial counter of Y-skip */ +#define UBIF_CYSK (UBIF+0x0038) /* Y-skip counter */ +#define UBIF_CYSZ (UBIF+0x003c) /* Y-size counter */ + +#define UBIF_TTL (UBIF+0x0040) /* number of data transfer register */ +#define UBIF_CTTL (UBIF+0x0044) /* number of data transfer counter */ + +/* +** BIF control registers (system mode) +*/ +#define BIF_CIDR0 (BIF+0x0048) /* cell-id register 0 */ +#define BIF_CIDR1 (BIF+0x004c) /* cell-id register 1 (for cell mode) */ +#define BIF_CIDR2 (BIF+0x0050) /* cell-id register 2 */ +#define BIF_CIDR3 (BIF+0x0054) /* cell-id register 3 */ +#define BIF_HEADER (BIF+0x0058) /* header register */ +#define BIF_INTR (BIF+0x006c) /* BIF interrupt control register */ +#define BIF_SDCSR (BIF+0x0070) /* BIF data control set register */ +#define BIF_RDCSR (BIF+0x0074) /* BIF data control reset reregister */ +#define BIF_MHOCR (BIF+0x0078) /* BIF extentional control reregister */ + +/* +** BIF control registers (user mode) +*/ +#define UBIF_CIDR0 (UBIF+0x0048) /* cell-id register 0 */ +#define UBIF_CIDR1 (UBIF+0x004c) /* cell-id register 1 (for cell mode) */ +#define UBIF_CIDR2 (UBIF+0x0050) /* cell-id register 2 */ +#define UBIF_CIDR3 (UBIF+0x0054) /* cell-id register 3 */ +#define UBIF_HEADER (UBIF+0x0058) /* header register */ +#define UBIF_INTR (UBIF+0x006c) /* BIF interrupt control register */ +#define UBIF_SDCSR (UBIF+0x0070) /* BIF data control set register */ +#define UBIF_RDCSR (UBIF+0x0074) /* BIF data control reset reregister */ +#define UBIF_MHOCR (UBIF+0x0078) /* BIF extentional control reregister */ + +/* +** bit assignment +*/ +#define BIF_HEADER_ID 0xffff0000 /* cell-id */ +#define BIF_HEADER_BR 0x00008000 /* broad bit */ +#define BIF_HEADER_IS 0x00006000 /* ID select */ +#define BIF_HEADER_IS_00 0x00000000 +#define BIF_HEADER_IS_01 0x00002000 +#define BIF_HEADER_IS_10 0x00004000 +#define BIF_HEADER_IS_11 0x00006000 +#define BIF_HEADER_IN 0x00001000 /* interrupt bit */ +#define BIF_HEADER_LS 0x00000800 /* line send */ +#define BIF_HEADER_SC 0x00000400 /* scatter bit */ +#define BIF_HEADER_HS 0x00000200 /* header strip */ +#define BIF_HEADER_RS 0x00000100 /* bus release */ + +#define BIF_HEADER_ID_SHIFT 16 + +#define BIF_INTR_GS 0x00020000 /* grant interrupt select */ +#define BIF_INTR_GM 0x00010000 /* grant interrupt mask */ +#define BIF_INTR_GI 0x00008000 /* grant interrupt request */ +#define BIF_INTR_HS 0x00004000 /* header interrupt select */ +#define BIF_INTR_HM 0x00002000 /* header interrupt mask */ +#define BIF_INTR_HI 0x00001000 /* header interrupt request */ +#define BIF_INTR_SS 0x00000800 /* send interrupt select */ +#define BIF_INTR_SM 0x00000400 /* send interrupt mask */ +#define BIF_INTR_SI 0x00000200 /* send interrupt request */ +#define BIF_INTR_RS 0x00000100 /* receive interrupt select */ +#define BIF_INTR_RM 0x00000080 /* receive interrupt mask */ +#define BIF_INTR_RI 0x00000040 /* receive interrupt request */ +#define BIF_INTR_ES 0x00000020 /* error interrupt select */ +#define BIF_INTR_EM 0x00000010 /* error interrupt mask */ +#define BIF_INTR_EI 0x00000008 /* error interrupt request */ +#define BIF_INTR_AS 0x00000004 /* attention interrupt select */ +#define BIF_INTR_AM 0x00000002 /* attention interrupt mask */ +#define BIF_INTR_AI 0x00000001 /* attention interrupt request */ + +#define BIF_SDCSR_ER 0x7fffc000 /* error detected by BIF */ +#define BIF_SDCSR_PE 0x80000000 /* detect parity error in sync */ +#define BIF_SDCSR_SP 0x40000000 /* parity error in sync */ +#define BIF_SDCSR_LP 0x20000000 /* L-bus parity error */ +#define BIF_SDCSR_LR 0x10000000 /* */ +#define BIF_SDCSR_LW 0x08000000 /* */ +#define BIF_SDCSR_AL 0x04000000 /* specify end bit except of end data */ +#define BIF_SDCSR_SS 0x02000000 /* request bit but masked by slow sync */ +#define BIF_SDCSR_SC 0x01000000 /* clear bit but masked by slow sync */ +#define BIF_SDCSR_SY 0x00800000 /* set bit but masked by slow status */ +#define BIF_SDCSR_FS 0x00400000 /* request bit but masked by fast sync */ +#define BIF_SDCSR_FC 0x00200000 /* clear bit but masked by fast sync */ +#define BIF_SDCSR_FY 0x00100000 /* set bit but masked by fast status */ +#define BIF_SDCSR_CP 0x00080000 /* parity error in commnad bus */ +#define BIF_SDCSR_FP 0x00040000 /* execute scatter or gather but FN=0 */ +#define BIF_SDCSR_PS 0x00020000 /* header receive error */ +#define BIF_SDCSR_RA 0x00010000 /* change scatter,gather parameter */ +#define BIF_SDCSR_PA 0x00008000 /* check if send or receive error */ +#define BIF_SDCSR_DL 0x00004000 /* lost data */ +#define BIF_SDCSR_BB 0x00002000 /* check if some BIF use command bus */ +#define BIF_SDCSR_BG 0x00001000 /* check if command bus got */ +#define BIF_SDCSR_BR 0x00000800 /* request command bus */ +#define BIF_SDCSR_CN 0x00000400 /* release BIF from command bus */ +#define BIF_SDCSR_FN 0x00000200 /* scatter gather enable */ +#define BIF_SDCSR_EB 0x00000100 /* send data that have end bit */ +#define BIF_SDCSR_TB 0x000000E0 /* data in send FIFO */ +#define BIF_SDCSR_TB4 0x00000080 +#define BIF_SDCSR_TB2 0x00000040 +#define BIF_SDCSR_TB1 0x00000020 +#define BIF_SDCSR_RB 0x0000001c /* data in receive FIFO */ +#define BIF_SDCSR_RB4 0x00000010 +#define BIF_SDCSR_RB2 0x00000008 +#define BIF_SDCSR_RB1 0x00000004 +#define BIF_SDCSR_DE 0x00000002 /* DMA interface enable bitr */ +#define BIF_SDCSR_DR 0x00000001 /* data transfer direction */ + +#define BIF_RDCSR_ER BIF_SDCSR_ER /* error detected by BIF */ +#define BIF_RDCSR_PE BIF_SDCSR_PE /* detect parity error in sync */ +#define BIF_RDCSR_SP BIF_SDCSR_SP /* parity error in sync */ +#define BIF_RDCSR_LP BIF_SDCSR_LP /* L-bus parity error */ +#define BIF_RDCSR_LR BIF_SDCSR_LR /* */ +#define BIF_RDCSR_LW BIF_SDCSR_LW /* */ +#define BIF_RDCSR_AL BIF_SDCSR_AL /* specify end bit except of end data */ +#define BIF_RDCSR_SS BIF_SDCSR_SS /* request bit but masked by slow sync */ +#define BIF_RDCSR_SC BIF_SDCSR_SC /* clear bit but masked by slow sync */ +#define BIF_RDCSR_SY BIF_SDCSR_SY /* set bit but masked by slow status */ +#define BIF_RDCSR_FS BIF_SDCSR_FS /* request bit but masked by fast sync*/ +#define BIF_RDCSR_FC BIF_SDCSR_FC /* clear bit but masked by fast sync */ +#define BIF_RDCSR_FY BIF_SDCSR_FY /* set bit but masked by fast status */ +#define BIF_RDCSR_CP BIF_SDCSR_CP /* parity error in commnad bus */ +#define BIF_RDCSR_FP BIF_SDCSR_FP /* execute scatter or gather but FN=0 */ +#define BIF_RDCSR_PS BIF_SDCSR_PS /* header receive error */ +#define BIF_RDCSR_RA BIF_SDCSR_RA /* change scatter,gather parameter */ +#define BIF_RDCSR_DL BIF_SDCSR_DL /* lost data */ +#define BIF_RDCSR_PA BIF_SDCSR_PA /* check if send or receive error */ +#define BIF_RDCSR_BB BIF_SDCSR_BB /* check if some BIF use command bus */ +#define BIF_RDCSR_BG BIF_SDCSR_BG /* check if command bus got */ +#define BIF_RDCSR_BR BIF_SDCSR_BR /* request command bus */ +#define BIF_RDCSR_CN BIF_SDCSR_CN /* release BIF from command bus */ +#define BIF_RDCSR_EB BIF_SDCSR_EB /* send data that have end bit */ +#define BIF_RDCSR_TB BIF_SDCSR_TB /* data in send FIFO */ +#define BIF_RDCSR_RB BIF_SDCSR_RB /* data in receive FIFO */ +#define BIF_RDCSR_DE BIF_SDCSR_DE /* DMA interface enable bitr */ +#define BIF_RDCSR_DR BIF_SDCSR_DR /* data transfer direction */ +#define BIF_RDCSR_FN BIF_SDCSR_FN /* scatter gather enable */ + +#define BIF_MHOCR_RS 0x00000800 /* bif reset */ +#define BIF_MHOCR_RC 0x00000400 /* commnad bus circuit reset */ +#define BIF_MHOCR_RI 0x00000200 /* remove input buffer data */ +#define BIF_MHOCR_RO 0x00000100 /* remove output buffer data */ +#define BIF_MHOCR_BA 0x00000008 /* command bus arbitlater reset */ +#define BIF_MHOCR_MD 0x00000006 /* command bus mode */ +#define BIF_MHOCR_AT 0x00000001 /* command bus attention signal */ + +#define BIF_MHOCR_MD_NORMAL 0x00000006 /* command bus mode [normal] */ +#define BIF_MHOCR_MD_BUSWGR 0x00000004 /* command bus mode [bus gather] */ +#define BIF_MHOCR_MD_SETCID 0x00000002 /* command bus mode [set cid] */ + + diff --git a/include/asm-sparc/ap1000/aplib.h b/include/asm-sparc/ap1000/aplib.h new file mode 100644 index 000000000000..55e2f528dc42 --- /dev/null +++ b/include/asm-sparc/ap1000/aplib.h @@ -0,0 +1,119 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ + +/* aplib kernel interface definition */ + +#ifndef _APLIB_H_ +#define _APLIB_H_ + +struct aplib_struct { + unsigned *ringbuf; + unsigned write_pointer, read_pointer; /* in words */ + unsigned ringbuf_size; /* in words */ + unsigned rbuf_counter; /* read messages */ + unsigned rbuf_flag1, rbuf_flag2; /* received messages */ + unsigned *physical_cid; /* logical to physical mapping */ + unsigned *rel_cid; /* logical to relative (RTC) mapping */ + unsigned numcells; /* number of logical cells */ + unsigned numcells_x; /* number of logical cells in x direction */ + unsigned numcells_y; /* number of logical cells in y direction */ + unsigned cid, tid; /* this cells logical cell ID and task ID */ + unsigned cidx, cidy; /* logical cell id in x and y direction */ + unsigned ack_flag, ack_request; + unsigned ok_x, ok_y, ok_xy; /* whether hardware x, y and xy sends are allowed */ +}; + + +/* + * the system ringbuffer structure + * this is also the old way that tasks accessed the MSC hardware + */ +struct ringbuf_struct { + void *ringbuf; /* pointer to the ringbuf */ + void *shared; /* pointer to the shared page */ + int order; /* arg to __get_free_pages */ + unsigned write_ptr; /* write pointer into the ringbuf */ + unsigned vaddr; /* base virtual address of ringbuf for task */ + unsigned frag_count; /* how many words in the frag queue */ + unsigned frag_len; /* how many words expected in the frag queue */ + unsigned sq_fragment[16]; /* if the task switches part way through + an op then shove the partial op here */ +}; + + +#define APLIB_INIT 1 +#define APLIB_SYNC 2 +#define APLIB_GET 3 +#define APLIB_PUT 4 +#define APLIB_SEND 5 +#define APLIB_PROBE 6 +#define APLIB_POLL 7 +#define APLIB_XSEND 8 +#define APLIB_YSEND 9 +#define APLIB_XYSEND 10 +#define APLIB_XPUT 11 +#define APLIB_YPUT 12 +#define APLIB_XYPUT 13 + + +/* message kinds */ +#define RBUF_SYSTEM 0 +#define RBUF_SEND 1 +#define RBUF_X_BRD 2 +#define RBUF_Y_BRD 3 +#define RBUF_XY_BRD 4 +#define RBUF_RPC 5 +#define RBUF_GET 6 +#define RBUF_MPI 7 +#define RBUF_BIGSEND 8 +#define RBUF_SEEN 0xE +#define RBUF_READ 0xF + +#define APLIB_PAGE_BASE 0xd0000000 +#define APLIB_PAGE_LEN 8192 + +struct aplib_init { + unsigned numcells, cid; + unsigned numcells_x, numcells_y; + unsigned *phys_cells; /* physical cell list */ + unsigned *ringbuffer; /* pointer to user supplied ring buffer */ + unsigned ringbuf_size; /* in words */ +}; + + +struct aplib_putget { + unsigned cid; + unsigned *src_addr, *dest_addr; + unsigned size; /* in words */ + unsigned *dest_flag, *src_flag; + unsigned ack; +}; + + +struct aplib_send { + /* the ordering here is actually quite important - the parts to be + read by the bigrecv function must be in the first 24 bytes */ + unsigned src_addr; + unsigned size; + unsigned info1, info2; + unsigned flag_addr; + volatile unsigned flag; + unsigned type; + unsigned tag; + unsigned cid; +}; + +#ifdef __KERNEL__ +#define MAX_PUT_SIZE (1024*1024 - 1) /* in words */ +#define SMALL_SEND_THRESHOLD 128 + + +#endif + +#endif /* _APLIB_H_ */ + diff --git a/include/asm-sparc/ap1000/apreg.h b/include/asm-sparc/ap1000/apreg.h new file mode 100644 index 000000000000..11a7a866613b --- /dev/null +++ b/include/asm-sparc/ap1000/apreg.h @@ -0,0 +1,619 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* ap1000 register definitions needed for Linux/AP+ */ + +#ifndef _AP1000_APREG_H +#define _AP1000_APREG_H +#include +#include +#include +#include + +/* + * Macros for accessing I/O registers. + */ +#define BIF_IN(reg) (*(volatile unsigned *)(reg)) +#define BIF_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) +#define DMA_IN(reg) (*(volatile unsigned *)(reg)) +#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) +#define MC_IN(reg) (*(volatile unsigned *)(reg)) +#define MC_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) +#define MSC_IN(reg) (*(volatile unsigned *)(reg)) +#define MSC_OUT(reg,v) (*(volatile unsigned *)(reg) = (v)) +#define MSC_IO(reg) (*(volatile unsigned *)(reg)) +#define RTC_IO(reg) (*(volatile unsigned *)(reg)) +#define MC_IO(reg) (*(volatile unsigned *)(reg)) +#define OPT_IO(reg) (*(volatile unsigned *)(reg)) + +/* + * B-net interface register definitions. + */ +#define BIF 0xfff30000 +#define BIF_CIDR1 (BIF+0x004c) /* cell-id register 1 (for cell mode)*/ +#define BIF_SDCSR (BIF+0x0070) /* BIF data control set register */ +#define BIF_DATA (BIF+0x0000) /* BIF send and receive data registe */ +#define BIF_EDATA (BIF+0x0004) /* BIF end data register */ +#define BIF_INTR (BIF+0x006c) /* BIF interrupt control register */ + +#define SSTT_SET (BIF+0xe0) /* set SSTT */ +#define SSTT_CLR (BIF+0xe4) /* clear SSTT */ +#define SSTT_SMSK (BIF+0xe8) /* set SSTT mask */ +#define SSTT_CMSK (BIF+0xec) /* clear SSTT mask */ +#define SSTT_SMD (BIF+0xf0) /* set SSYN & SSTT mode */ +#define SSTT_CMD (BIF+0xf4) /* clear SSYN & SSTT mode */ + +/* +** FSTT registers +*/ +#define FSTT BIF /* FSTT only system mode */ +#define FSTT_SET (FSTT+0xa0) /* set FSTT */ +#define FSTT_CLR (FSTT+0xa4) /* clear FSTT */ +#define FSTT_SMSK (FSTT+0xa8) /* set FSTT mask */ +#define FSTT_CMSK (FSTT+0xac) /* clear FSTT mask */ +#define FSTT_SMD (FSTT+0xb0) /* set FSYN & FSTT mode */ +#define FSTT_CMD (FSTT+0xb4) /* clear FSYN & FSTT mode */ +#define FSTT_TIM (FSTT+0xb8) /* status timer */ + + +#define BIF_SDCSR_RB 0x0000001c /* data in receive FIFO */ +#define BIF_SDCSR_EB 0x00000100 /* send data that have end bit */ +#define BIF_SDCSR_BG 0x00001000 /* check if command bus got */ +#define BIF_SDCSR_BR 0x00000800 /* request command bus */ +#define BIF_SDCSR_TB 0x000000E0 /* data in send FIFO */ +#define BIF_SDCSR_PE 0x80000000 /* detect parity error in sync */ +#define BIF_SDCSR_BB 0x00002000 /* check if some BIF use command bus */ + +#define BIF_SDCSR_RB_SHIFT 2 +#define BIF_SDCSR_TB_SHIFT 5 + +#define BIF_INTR_GET_SH 15 /* get bus interrupt */ +#define BIF_INTR_HEADER_SH 12 /* header interrupt */ +#define BIF_INTR_SEND_SH 9 /* send interrupt */ +#define BIF_INTR_RECV_SH 6 /* receive interrupt */ +#define BIF_INTR_ERR_SH 3 /* error interrupt */ +#define BIF_INTR_ATTN_SH 0 /* attention interrupt */ + + +#define BIF_HEADER_HS 0x00000200 /* header strip */ +#define BIF_HEADER_RS 0x00000100 /* bus release */ +#define BIF_HEADER_IN 0x00001000 /* interrupt bit */ +#define BIF_HEADER_BR 0x00008000 /* broad bit */ +#define BIF_INTR_HS 0x00004000 /* header interrupt select */ +#define HOST_CID 0x1000 +#define MAKE_HEADER(cid) (BIF_HEADER_IN | \ + ((cid)==-1?BIF_HEADER_BR:((cid)<<16) | (1<<13))) + +#define BIF_RDCSR (BIF+0x0074) /* BIF data control reset reregister */ + +/* + * Interrupt levels for AP+ devices + */ +#define APBIFGET_IRQ 1 /* have acquired B-net */ +#define APOPT0_IRQ 2 /* option interrupt level 0 */ +#define APSYNC_IRQ 3 /* sync (S-net) interrupt */ +#define APDMA_IRQ 4 /* DMA complete interrupt */ +#define APRTC_IRQ 5 /* RTC data transfer interrupt */ +#define APIPORT_IRQ 6 /* Interrupt port interrupt */ +#define APOPT1_IRQ 7 /* option interrupt level 1 */ +#define APBIF_IRQ 8 /* B-net interface interrupt */ +#define APMAS_IRQ 9 /* Send/Recv mem acc. seq. intr */ +#define APTIM1_IRQ 10 /* Timer 1 interrupt */ +#define APMSC_IRQ 11 /* MSC+ ring buf/queue spill etc. */ +#define APLBUS_IRQ 12 /* LBUS error interrupt */ +#define APATTN_IRQ 13 /* Attention interrupt */ +#define APTIM0_IRQ 14 /* Timer 0 interrupt */ +#define APMEM_IRQ 15 /* Memory error interrupt */ + +/* + * LBUS DMA controller register definitions + */ +#define DMA 0xfff00000 /* dma controller address */ +#define DMA3 (DMA+0xc0) /* DMA channel 3 */ +#define DMA_DMST 0x04 +#define DMA_MADDR 0x10 +#define DMA_HSKIP 0x08 +#define DMA_HCNT 0x0a +#define DMA_VSKIP 0x0c +#define DMA_VCNT 0x0e +#define DMA_DCMD 0x00 +#define DMA_HDRP 0x28 +#define DMA_DSIZE 0x02 +#define DMA_CSIZE 0x06 +#define DMA_VCNT 0x0e + +#define DMA_BIF_BCMD (DMA+0x120) /* BIF receive command register */ +#define DMA_BIF_BRST (DMA+0x124) /* BIF receive status register */ +#define DMA_BCMD_SA 0x40000000 /* software abort */ +#define DMA_DMST_AC 0x80000000 /* channel active */ +#define DMA_DMST_RST 0xffe40000 /* reset bits and reqs */ +#define DMA_DCMD_ST 0x80000000 /* start operation */ +#define DMA_DCMD_TYP_AUTO 0x30000000 /* 11: auto */ + +#define DMA_DCMD_TD_MD 0x04000000 /* transfer mem->dev */ +#define DMA_DCMD_TD_DM 0x00000000 /* transfer direction dev->mem*/ + +#define DMA_CH2 (DMA+0x80) /* DMA channel 2 */ +#define DMA_CH3 (DMA+0xc0) /* DMA channel 3 */ +#define DMA2_DMST (DMA_CH2+0x04) /* DMA2 status register */ +#define DMA3_DMST (DMA_CH3+0x04) /* DMA3 status register */ +#define DMA2_DCMD (DMA_CH2+0x00) /* DMA2 command register */ + +#define DMA_INTR_NORMAL_SH 19 /* normal DMA interrupt */ +#define DMA_INTR_ERROR_SH 16 /* error DMA interrupt */ + +#define DMA_DCMD_SA 0x40000000 /* software abort */ + + +#define DMA_MAX_TRANS_SIZE (0xffff<<2) +#define DMA_TRANS_BLOCK_SIZE (64<<2) + +#define WORD_SIZE 4 +#define B2W(x) (((x) + WORD_SIZE - 1) / WORD_SIZE) +#define W2B(x) ((x) * WORD_SIZE) + +#define DMA_GEN 0xfff00180 /* DMA general control reg */ + +/* AP1000+ Message Controller (MSC+) */ + +#define MSC_BASE0 0xfa008000 + +#define MSC_SQCTRL (MSC_BASE0 + 0x0) /* Send Queue control */ + +/* bits in MSC_SQCTRL */ +#define MSC_SQC_STABLE 0x400 /* Send Queue stable */ +#define MSC_SQC_MODE 0x300 /* Send Queue mode: */ +#define MSC_SQC_MODE_BLOCK 0 /* blocking */ +#define MSC_SQC_MODE_THRU 0x100 /* through */ +#define MSC_SQC_MODE_NORMAL 0x200 /* or normal */ +#define MSC_SQC_SPLF_SH 3 /* bit# for spill flags */ +#define MSC_SQC_SPLF_M 0x1f /* 5 bits wide */ +#define MSC_SQC_REPLYF 0x080 /* Reply queue full */ +#define MSC_SQC_REMRF 0x040 /* Remote reply queue full */ +#define MSC_SQC_USERF 0x020 /* User queue full */ +#define MSC_SQC_REMAF 0x010 /* Remote access queue full */ +#define MSC_SQC_SYSF 0x008 /* System queue full */ +#define MSC_SQC_PAUSE 0x004 /* Send Queue pause */ +#define MSC_SQC_RMODE 0x003 /* Requested mode: */ +#define MSC_SQC_RMODE_BLOCK 0 /* blocking */ +#define MSC_SQC_RMODE_THRU 1 /* through */ +#define MSC_SQC_RMODE_NORMAL 2 /* or normal */ + +#define MSC_SQPTR0 (MSC_BASE0 + 0x8) /* Send Queue 0 pointers */ +#define MSC_SQPTR1 (MSC_BASE0 + 0x10) /* Send Queue 1 pointers */ +#define MSC_SQPTR2 (MSC_BASE0 + 0x18) /* Send Queue 2 pointers */ +#define MSC_SQPTR3 (MSC_BASE0 + 0x20) /* Send Queue 3 pointers */ +#define MSC_SQPTR4 (MSC_BASE0 + 0x28) /* Send Queue 4 pointers */ + +/* bits in MSC_SQPTR[0-4] */ +#define MSC_SQP_MODE (1 << 20) /* 64/32 word queue mode */ +#define MSC_SQP_BP_SH 17 /* bit no. for base ptr */ +#define MSC_SQP_BP_M 7 /* (it's 3 bits wide) */ +#define MSC_SQP_CNT_SH 12 /* bit no. for count */ +#define MSC_SQP_CNT_M 0x1f /* (it's 5 bits wide) */ +#define MSC_SQP_RP_SH 6 /* bit no. for read ptr */ +#define MSC_SQP_RP_M 0x3f /* (it's 6 bits wide() */ +#define MSC_SQP_WP_SH 0 /* bit no. for write ptr */ +#define MSC_SQP_WP_M 0x3f /* (it's 6 bits wide() */ + +#define MSC_OPTADR (MSC_BASE0 + 0x30) /* option memory address */ + +#define MSC_MASCTRL (MSC_BASE0 + 0x38) /* Mem Access Sequencer ctrl */ + +/* Bits in MSC_MASCTRL */ +#define MSC_MASC_SPAUSE 0x80 /* Send MAS pause */ +#define MSC_MASC_RPAUSE 0x40 /* Recv MAS pause */ +#define MSC_MASC_SFEXIT 0x20 /* Send MAS fault/exit */ +#define MSC_MASC_RFEXIT 0x10 /* Recv MAS fault/exit */ +#define MSC_MASC_SREADY 0x08 /* Send MAS ready */ +#define MSC_MASC_RREADY 0x04 /* Recv MAS ready */ +#define MSC_MASC_SSTOP 0x02 /* Send MAS is stopped */ +#define MSC_MASC_RSTOP 0x01 /* Recv MAS is stopped */ + +#define MSC_SMASADR (MSC_BASE0 + 0x40) /* Send Mem Acc Seq address */ +#define MSC_RMASADR (MSC_BASE0 + 0x48) /* Recv Mem Acc Seq address */ + +#define MSC_PID (MSC_BASE0 + 0x50) /* Context number (proc id) */ + +#define MSC_QWORDCNT (MSC_BASE0 + 0x60) /* Queue word counts */ + +/* Fields in MSC_QWORDCNT */ +#define MSC_QWDC_SYSCNT_SH 24 /* bit# for system count */ +#define MSC_QWDC_SYSCNT_M 0x3f /* 6 bits wide */ +#define MSC_QWDC_SYSLEN_SH 16 /* bit# for len of sys cmd */ +#define MSC_QWDC_SYSLEN_M 0x3f /* 6 bits wide */ +#define MSC_QWDC_USRCNT_SH 8 /* bit# for user count */ +#define MSC_QWDC_USRCNT_M 0x3f /* 6 bits wide */ +#define MSC_QWDC_USRLEN_SH 0 /* bit# for len of user cmd */ +#define MSC_QWDC_USRLEN_M 0x3f /* 6 bits wide */ + +#define MSC_INTR (MSC_BASE0 + 0x70) /* Interrupt control/status */ + +/* Bit offsets of interrupt fields in MSC_INTR */ +#define MSC_INTR_QBMFUL_SH 28 /* Queue buffer full intr */ +#define MSC_INTR_SQFILL_SH 24 /* Send queue fill intr */ +#define MSC_INTR_RBMISS_SH 20 /* Ring buffer miss intr */ +#define MSC_INTR_RBFULL_SH 16 /* Ring buffer full intr */ +#define MSC_INTR_RMASF_SH 12 /* Recv MAS fault intr */ +#define MSC_INTR_RMASE_SH 8 /* Recv MAS error intr */ +#define MSC_INTR_SMASF_SH 4 /* Send MAS fault intr */ +#define MSC_INTR_SMASE_SH 0 /* Send MAS error intr */ + +#define MSC_PPIO (MSC_BASE0 + 0x1000) /* PArallel port I/O */ +#define MSC_PACSELECT (MSC_BASE0 + 0x1008) /* Performance analyser sel. */ + +#define MSC_CIDRANGE (MSC_BASE0 + 0x1010) /* Rel. Cell-id range limits */ + +/* Fields in MSC_CIDRANGE */ +#define MSC_CIDR_LRX_SH 24 /* Rel. X lower limit bit# */ +#define MSC_CIDR_LRX_M 0xFF /* it's 8 bits wide */ +#define MSC_CIDR_HRX_SH 16 /* Rel. X upper limit bit# */ +#define MSC_CIDR_HRX_M 0xFF /* it's 8 bits wide */ +#define MSC_CIDR_LRY_SH 8 /* Rel. Y lower limit bit# */ +#define MSC_CIDR_LRY_M 0xFF /* it's 8 bits wide */ +#define MSC_CIDR_HRY_SH 0 /* Rel. Y upper limit bit# */ +#define MSC_CIDR_HRY_M 0xFF /* it's 8 bits wide */ + +#define MSC_QBMPTR (MSC_BASE0 + 0x1018) /* Queue buffer mgr. ptrs */ + +/* Fields in MSC_QBMPTR */ +#define MSC_QBMP_LIM_SH 24 /* Pointer limit bit# */ +#define MSC_QBMP_LIM_M 0x3F /* (6 bits wide) */ +#define MSC_QBMP_BP_SH 16 /* Base pointer bit# */ +#define MSC_QBMP_BP_M 0xFF /* (8 bits wide) */ +#define MSC_QBMP_WP_SH 0 /* Write pointer bit# */ +#define MSC_QBMP_WP_M 0xFFFF /* (16 bits wide) */ + +#define MSC_SMASTWP (MSC_BASE0 + 0x1030) /* Send MAS virt page etc. */ +#define MSC_SMASREG (MSC_BASE0 + 0x1038) /* Send MAS context etc. */ +#define MSC_RMASTWP (MSC_BASE0 + 0x1040) /* Recv MAS virt page etc. */ +#define MSC_RMASREG (MSC_BASE0 + 0x1048) /* Recv MAS context etc. */ + +/* Bits in MSC_[SR]MASREG */ +#define MSC_MASR_CONTEXT_SH 20 /* Context at bit 20 */ +#define MSC_MASR_CONTEXT_M 0xfff /* 12 bits wide */ +#define MSC_MASR_AVIO 8 /* Address violation bit */ +#define MSC_MASR_CMD 7 /* MAS command bits */ +#define MSC_MASR_CMD_XFER 0 /* transfer data cmd */ +#define MSC_MASR_CMD_FOP 5 /* fetch & operate cmd */ +#define MSC_MASR_CMD_INC 6 /* increment cmd (i.e. flag) */ +#define MSC_MASR_CMD_CSI 7 /* compare & swap cmd */ + +#define MSC_HDGERRPROC (MSC_BASE0 + 0x1050) /* Header gen. error process */ +#define MSC_RHDERRPROC (MSC_BASE0 + 0x1058) /* Recv. header decoder err. */ + +#define MSC_SMASCNT (MSC_BASE0 + 0x1060) /* Send MAS counters */ + +/* Bits in MSC_SMASCNT */ +#define MSC_SMCT_ACCSZ_SH 28 /* Access size at bit 28 */ +#define MSC_SMCT_ACCSZ_M 7 /* 3 bits wide */ +#define MSC_SMCT_MCNT_SH 8 /* M(?) count at bit 8 */ +#define MSC_SMCT_MCNT_M 0xfffff /* 20 bits wide */ +#define MSC_SMCT_ICNT_SH 0 /* I(?) count at bit 0 */ +#define MSC_SMCT_ICNT_M 0xff /* 8 bits wide */ + +#define MSC_IRL (MSC_BASE0 + 0x1070) /* highest current int req */ +#define MSC_SIMMCHK (MSC_BASE0 + 0x1078) /* DRAM type installed */ + +#define MSC_SIMMCHK_MASK 0x00000008 + +#define MSC_SQRAM (MSC_BASE0 + 0x2000) /* Send Queue RAM (to +23f8) */ + +#define MSC_VERSION (MSC_BASE0 + 0x3000) /* MSC+ version */ + +#define MSC_NR_RBUFS 3 + +#define MSC_RBMBWP0 (MSC_BASE0 + 0x4000) /* Ring buf 0 base/write ptr */ +#define MSC_RBMMODE0 (MSC_BASE0 + 0x4008) /* Ring buf 0 mode/context */ +#define MSC_RBMBWP1 (MSC_BASE0 + 0x4010) /* Ring buf 1 base/write ptr */ +#define MSC_RBMMODE1 (MSC_BASE0 + 0x4018) /* Ring buf 1 mode/context */ +#define MSC_RBMBWP2 (MSC_BASE0 + 0x4020) /* Ring buf 2 base/write ptr */ +#define MSC_RBMMODE2 (MSC_BASE0 + 0x4028) /* Ring buf 2 mode/context */ + +#define MSC_RBMRP0 (MSC_BASE0 + 0x5000) /* Ring buf 0 read pointer */ +#define MSC_RBMRP1 (MSC_BASE0 + 0x6000) /* Ring buf 1 read pointer */ +#define MSC_RBMRP2 (MSC_BASE0 + 0x7000) /* Ring buf 2 read pointer */ + +/* locations of queues in virtual memory */ +#define MSC_QUEUE_BASE 0xfa800000 +#define MSC_PUT_QUEUE_S (MSC_QUEUE_BASE + 0*PAGE_SIZE) +#define MSC_GET_QUEUE_S (MSC_QUEUE_BASE + 1*PAGE_SIZE) +#define MSC_XYG_QUEUE_S (MSC_QUEUE_BASE + 2*PAGE_SIZE) +#define MSC_SEND_QUEUE_S (MSC_QUEUE_BASE + 3*PAGE_SIZE) +#define MSC_CPUT_QUEUE_S (MSC_QUEUE_BASE + 4*PAGE_SIZE) +#define MSC_BSEND_QUEUE_S (MSC_QUEUE_BASE + 5*PAGE_SIZE) +#define MSC_CXYG_QUEUE_S (MSC_QUEUE_BASE + 6*PAGE_SIZE) +#define MSC_CGET_QUEUE_S (MSC_QUEUE_BASE + 7*PAGE_SIZE) + +/* the 4 interrupt ports - physical addresses (on bus 8) */ +#define MC_INTP_0 0x80004000 +#define MC_INTP_1 0x80005000 +#define MC_INTP_2 0x80006000 +#define MC_INTP_3 0x80007000 + +/* the address used to send a remote signal - note that 32 pages + are used here - none of them are mapped to anything though */ +#define MSC_REM_SIGNAL (MSC_QUEUE_BASE + 0x10 * PAGE_SIZE) + +#define MSC_PUT_QUEUE (MSC_QUEUE_BASE + 0x100*PAGE_SIZE) +#define MSC_GET_QUEUE (MSC_QUEUE_BASE + 0x101*PAGE_SIZE) +#define MSC_SEND_QUEUE (MSC_QUEUE_BASE + 0x102*PAGE_SIZE) +#define MSC_XY_QUEUE (MSC_QUEUE_BASE + 0x103*PAGE_SIZE) +#define MSC_X_QUEUE (MSC_QUEUE_BASE + 0x104*PAGE_SIZE) +#define MSC_Y_QUEUE (MSC_QUEUE_BASE + 0x105*PAGE_SIZE) +#define MSC_XYG_QUEUE (MSC_QUEUE_BASE + 0x106*PAGE_SIZE) +#define MSC_XG_QUEUE (MSC_QUEUE_BASE + 0x107*PAGE_SIZE) +#define MSC_YG_QUEUE (MSC_QUEUE_BASE + 0x108*PAGE_SIZE) +#define MSC_CSI_QUEUE (MSC_QUEUE_BASE + 0x109*PAGE_SIZE) +#define MSC_FOP_QUEUE (MSC_QUEUE_BASE + 0x10a*PAGE_SIZE) + +#define SYSTEM_RINGBUF_BASE (MSC_QUEUE_BASE + 0x200*PAGE_SIZE) +#define SYSTEM_RINGBUF_ORDER 5 +#define SYSTEM_RINGBUF_SIZE ((1<> fld ## _SH) & fld ## _M) +#define MKFIELD(val, fld) (((val) & fld ## _M) << fld ## _SH) +#define INSFIELD(dst, val, fld) (((dst) & ~(fld ## _M << fld ## _SH)) \ + | MKFIELD(val, fld)) + +/* + * RTC registers + */ +#define RTC 0xfff10000 /* RTC system mode */ +#define RTC_CSR (RTC+0x0010) /* RTC control register */ +#define RTC_STR (RTC+0x0020) /* RTC status register */ +#define RTC_ITRR (RTC+0x0030) /* RTC interrupt register */ +#define RTC_RSTR (RTC+0x0070) /* RTC reset register */ +#define RTC_RSTR_TR 0x00008000 /* RTC through mode */ +#define RTC_RSTR_TS 0x00004000 /* RTC test mode */ +#define RTC_RSTR_ED 0x00002000 /* RTC reverse mode */ +#define RTC_RSTR_AC 0x00001000 /* RTC long mode */ +#define RTC_RSTR_SN 0x00000800 /* SOUTH/NORTH direction */ +#define RTC_RSTR_EW 0x00000400 /* EAST/WEST direction */ +#define RTC_RSTR_NC 0x00000200 /* get NORTH channel */ +#define RTC_RSTR_SC 0x00000100 /* get SOUTH channel */ +#define RTC_RSTR_WC 0x00000080 /* get WEST channel */ +#define RTC_RSTR_EC 0x00000040 /* get EAST channel */ +#define RTC_RSTR_BM 0x00000020 /* broad also my cell */ +#define RTC_RSTR_RT 0x00000020 /* reset */ + + +#define RTC_ITRR_PA 0x00040000 /* parity error for LBUS */ +#define RTC_ITRR_LR 0x00020000 /* MSC read but FIFO is empty*/ +#define RTC_ITRR_LW 0x00010000 /* MSC write but FIFO is full*/ +#define RTC_ITRR_AL 0x00008000 /* specify end data in data transfer */ +#define RTC_ITRR_DN 0x00002000 /* parity error in NORTH channel */ +#define RTC_ITRR_DS 0x00001000 /* parity error in SOUTH channel */ +#define RTC_ITRR_DW 0x00000800 /* parity error in WEST channel */ +#define RTC_ITRR_DE 0x00000400 /* parity error in EAST channel */ +#define RTC_ITRR_BD 0x00000200 /* receive 2 kind of broad data */ +#define RTC_ITRR_EW 0x00000100 /* control to write error bits */ +#define RTC_ITRR_EM 0x00000080 /* mask error interrupt request */ +#define RTC_ITRR_ER 0x00000040 /* error interrput request */ +#define RTC_ITRR_SW 0x00000020 /* control to write SR, SM */ +#define RTC_ITRR_SM 0x00000010 /* mask send interrupt */ +#define RTC_ITRR_SR 0x00000008 /* send interrupt request */ +#define RTC_ITRR_RW 0x00000004 /* icontrol to read RR, RM */ +#define RTC_ITRR_RM 0x00000002 /* mask read interrupt */ +#define RTC_ITRR_RR 0x00000001 /* receive interrupt request */ + +#define RTC_ITRR_RWM (RTC_ITRR_RW|RTC_ITRR_RM) +#define RTC_ITRR_SWM (RTC_ITRR_SW|RTC_ITRR_SM) +#define RTC_ITRR_EWM (RTC_ITRR_EW|RTC_ITRR_EM) +#define RTC_ITRR_RWR (RTC_ITRR_RW|RTC_ITRR_RR) +#define RTC_ITRR_SWR (RTC_ITRR_SW|RTC_ITRR_SR) +#define RTC_ITRR_EWR (RTC_ITRR_EW|RTC_ITRR_ER) +#define RTC_ITRR_RRM (RTC_ITRR_RM|RTC_ITRR_RR) +#define RTC_ITRR_SRM (RTC_ITRR_SM|RTC_ITRR_SR) +#define RTC_ITRR_ERM (RTC_ITRR_EM|RTC_ITRR_ER) +#define RTC_ITRR_RWMR (RTC_ITRR_RW|RTC_ITRR_RM|RTC_ITRR_RR) +#define RTC_ITRR_SWMR (RTC_ITRR_SW|RTC_ITRR_SM|RTC_ITRR_SR) +#define RTC_ITRR_EWMR (RTC_ITRR_EW|RTC_ITRR_EM|RTC_ITRR_ER) + +#define RTC_ITRR_ALLMSK (RTC_ITRR_RWM|RTC_ITRR_SWM|RTC_ITRR_EWM) +#define RTC_ITRR_ALLCLR (RTC_ITRR_RW|RTC_ITRR_SW|RTC_ITRR_EW) +#define RTC_ITRR_ALLWR (RTC_ITRR_RWMR|RTC_ITRR_SWMR|RTC_ITRR_EWMR) +#define RTC_ITRR_ALLRD (RTC_ITRR_RRM|RTC_ITRR_SRM|RTC_ITRR_ERM) + + +/* + * macros to manipulate context/task/pid numbers for parallel programs + */ +#define MPP_CONTEXT_BASE (AP_NUM_CONTEXTS - (NR_TASKS - MPP_TASK_BASE)) +#define MPP_TASK_TO_CTX(taskid) (((taskid) - MPP_TASK_BASE)+MPP_CONTEXT_BASE) +#define MPP_CTX_TO_TASK(ctx) (((ctx)-MPP_CONTEXT_BASE)+MPP_TASK_BASE) +#define MPP_IS_PAR_TASK(taskid) ((taskid) >= MPP_TASK_BASE) +#define MPP_IS_PAR_CTX(ctx) ((ctx) >= MPP_CONTEXT_BASE) + + +/* + * ioctls available on the ring buffer + */ +#define CAP_GETINIT 1 +#define CAP_SYNC 2 +#define CAP_SETTASK 3 +#define CAP_SETGANG 4 +#define CAP_MAP 5 + +/* + * the structure shared by the kernel and the parallel tasks in the + * front of the cap_shared area + */ +#ifndef _ASM_ +#ifdef _APLIB_ +struct _kernel_cap_shared { + unsigned rbuf_read_ptr; + unsigned dummy[32]; /* for future expansion */ +}; +#endif +#endif + +/* + * the mmap'd ringbuffer region is layed out like this: + + shared page - one page + queue pages - 11 pages + ring buffer - xx pages + mirror of ring buffer - xx pages + */ +#define RBUF_VBASE 0xd0000000 +#define RBUF_SHARED_PAGE_OFF 0 +#define RBUF_PUT_QUEUE PAGE_SIZE +#define RBUF_GET_QUEUE 2*PAGE_SIZE +#define RBUF_SEND_QUEUE 3*PAGE_SIZE +#define RBUF_XY_QUEUE 4*PAGE_SIZE +#define RBUF_X_QUEUE 5*PAGE_SIZE +#define RBUF_Y_QUEUE 6*PAGE_SIZE +#define RBUF_XYG_QUEUE 7*PAGE_SIZE +#define RBUF_XG_QUEUE 8*PAGE_SIZE +#define RBUF_YG_QUEUE 9*PAGE_SIZE +#define RBUF_CSI_QUEUE 10*PAGE_SIZE +#define RBUF_FOP_QUEUE 11*PAGE_SIZE +#define RBUF_RING_BUFFER_OFFSET 15*PAGE_SIZE + + +/* + * number of MMU contexts to use + */ +#define AP_NUM_CONTEXTS 1024 +#define SYSTEM_CONTEXT 1 + +/* + * the default gang scheduling factor +*/ +#define DEF_GANG_FACTOR 15 + +/* + * useful for bypassing the cache +*/ +#ifdef _APLIB_ +#ifndef _ASM_ +static inline unsigned long phys_8_in(unsigned long paddr) +{ + unsigned long word; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (word) : + "r" (paddr), "i" (0x28) : + "memory"); + return word; +} + +/* + * useful for bypassing the cache +*/ +static inline unsigned long phys_9_in(unsigned long paddr) +{ + unsigned long word; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (word) : + "r" (paddr), "i" (0x29) : + "memory"); + return word; +} +#endif +#endif + +/* + * DDV definitions +*/ +#define OBASE (0xfff40010) +#define OPTION_BASE 0xfc000000 +#define _OPIBUS_BASE (OPTION_BASE + 0x800000) +#ifdef CAP2_OPTION +#define OPIBUS_BASE 0 +#else +#define OPIBUS_BASE _OPIBUS_BASE +#endif +#define PBUF0 (OPIBUS_BASE+0x7e0080) +#define PBUF1 (OPIBUS_BASE+0x7e0084) +#define PBUF2 (OPIBUS_BASE+0x7e0088) +#define PBUF3 (OPIBUS_BASE+0x7e008c) +#define PIRQ (OPIBUS_BASE+0x7e0090) +#define PRST (OPIBUS_BASE+0x7e0094) + +#define IRC0 (OPIBUS_BASE+0x7d00a0) +#define IRC1 (OPIBUS_BASE+0x7d00a4) + +#define PRST_IRST (0x00000001) + +#define OPIU_RESET (0x00000000) +#define OPIU_OP (PBUF0) + +#define LSTR(s) (_OPIBUS_BASE + (s)) + +#endif /* _AP1000_APREG_H */ + diff --git a/include/asm-sparc/ap1000/apservice.h b/include/asm-sparc/ap1000/apservice.h new file mode 100644 index 000000000000..902e774d6ff2 --- /dev/null +++ b/include/asm-sparc/ap1000/apservice.h @@ -0,0 +1,111 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* this defines service requests that can be made by the cells of the + front end "bootap" server + + tridge, March 1996 + */ +#ifndef _APSERVICE_H +#define _APSERVICE_H +#ifdef __KERNEL__ +#include +#endif + +#ifndef _ASM_ + +/* all requests start with this structure */ +struct cap_request { + unsigned header; /* for the hardware */ + int size; /* the total request size in bytes, including this header */ + int cid; /* the cell it came from */ + int type; /* the type of request */ + int data[4]; /* misc data */ +}; + +/* Initialisation data to be sent to boot cell program */ +struct cap_init { + int bootcid; /* base cid to boot */ + int numcells; /* number of cells */ + int physcells; /* physical number of cells */ + unsigned long baseIP; /* IP address of cell 0 */ + unsigned long netmask; /* netmask of cells net */ + int gdbcell; /* what cell is the debugger running on */ + unsigned init_time; /* time at startup */ +}; +#endif + +/* what fake host number to use for the aliased IP device */ +#define AP_ALIAS_IP 2 + +/* request types */ +#define REQ_WRITE 0 +#define REQ_SHUTDOWN 1 +#define REQ_LOAD_AOUT 2 +#define REQ_PUTCHAR 3 +#define REQ_GETBOOTARGS 4 +#define REQ_PUTDEBUGCHAR 5 +#define REQ_GETDEBUGCHAR 6 +#define REQ_OPENNET 7 +#define REQ_IP 8 +#define REQ_BREAK 9 +#define REQ_INIT 10 +#define REQ_PUTDEBUGSTRING 11 +#define REQ_BREAD 12 +#define REQ_BWRITE 13 +#define REQ_BOPEN 14 +#define REQ_BCLOSE 15 +#define REQ_DDVOPEN 16 +#define REQ_BIF_TOKEN 17 +#define REQ_KILL 18 +#define REQ_SCHEDULE 19 + +/* the bit used to indicate that the host wants the BIF */ +#define HOST_STATUS_BIT 2 + +#ifdef __KERNEL__ +/* some prototypes */ +extern int ap_dma_wait(int ch); +extern int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd); +extern int mpp_cid(void); +extern void ap_start_debugger(void); +extern int bif_queue(struct cap_request *req,char *buf,int bufsize); +extern void write_bif_polled(char *buf1,int len1,char *buf2,int len2); +extern void read_bif(char *buf,int size); +extern void ap_wait_request(struct cap_request *req,int type); +extern void bif_set_poll(int set); +extern void ap_led(unsigned char d); +extern void ap_xor_led(unsigned char d); +extern void ap_set_led(unsigned char d); +extern void ap_unset_led(unsigned char d); +extern void bif_toss(int size); +void ap_msc_init(void); +void mac_dma_complete(void); +void ap_dbg_flush(void); +void bif_queue_flush(void); +/* void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5); */ +void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm); +void async_fault(unsigned long address, int write, int taskid, + void (*callback)(int,unsigned long,int,int)); +void ap_bif_init(void); +void ap_tnet_init(void); +int wait_on_int(volatile int *p,int x,int interval); +void ap_put(int dest_cell,u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag); +void ap_bput(u_long local_addr,int size, + u_long remote_addr,u_long dest_flag,u_long local_flag); +void msc_switch_check(struct task_struct *tsk); +int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize); +void mpp_set_gang_factor(int factor); +void bif_register_request(int type,void (*fn)(struct cap_request *)); +void bif_add_debug_key(char key,void (*fn)(void),char *description); +void ap_complete(struct cap_request *creq); +void ap_reboot(char *bootstr); +#endif + + +#endif /* _APSERVICE_H */ diff --git a/include/asm-sparc/ap1000/pgtapmmu.h b/include/asm-sparc/ap1000/pgtapmmu.h new file mode 100644 index 000000000000..8a46b1df075a --- /dev/null +++ b/include/asm-sparc/ap1000/pgtapmmu.h @@ -0,0 +1,140 @@ + /* + * Copyright 1996 The Australian National University. + * Copyright 1996 Fujitsu Laboratories Limited + * + * This software may be distributed under the terms of the Gnu + * Public License version 2 or later + */ +/* + * based on pgtsrmmu.h + * + */ + +#ifndef _SPARC_PGTAPMMU_H +#define _SPARC_PGTAPMMU_H + +#include +#include + + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define APMMU_PMD_SHIFT 18 +#define APMMU_PMD_SIZE (1UL << APMMU_PMD_SHIFT) +#define APMMU_PMD_MASK (~(APMMU_PMD_SIZE-1)) +#define APMMU_PMD_ALIGN(addr) (((addr)+APMMU_PMD_SIZE-1)&APMMU_PMD_MASK) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define APMMU_PGDIR_SHIFT 24 +#define APMMU_PGDIR_SIZE (1UL << APMMU_PGDIR_SHIFT) +#define APMMU_PGDIR_MASK (~(APMMU_PGDIR_SIZE-1)) +#define APMMU_PGDIR_ALIGN(addr) (((addr)+APMMU_PGDIR_SIZE-1)&APMMU_PGDIR_MASK) + +#define APMMU_PTRS_PER_PTE 64 +#define APMMU_PTRS_PER_PMD 64 +#define APMMU_PTRS_PER_PGD 256 + +#define APMMU_PTE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */ +#define APMMU_PMD_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */ +#define APMMU_PGD_TABLE_SIZE 0x400 /* 256 entries, 4 bytes a piece */ + +#define APMMU_VMALLOC_START (0xfe300000) + +/* Definition of the values in the ET field of PTD's and PTE's */ +#define APMMU_ET_MASK 0x3 +#define APMMU_ET_INVALID 0x0 +#define APMMU_ET_PTD 0x1 +#define APMMU_ET_PTE 0x2 +#define APMMU_ET_REPTE 0x3 /* AIEEE, SuperSparc II reverse endian page! */ + +/* Physical page extraction from PTP's and PTE's. */ +#define APMMU_CTX_PMASK 0xfffffff0 +#define APMMU_PTD_PMASK 0xfffffff0 +#define APMMU_PTE_PMASK 0xffffff00 + +/* The pte non-page bits. Some notes: + * 1) cache, dirty, valid, and ref are frobbable + * for both supervisor and user pages. + * 2) exec and write will only give the desired effect + * on user pages + * 3) use priv and priv_readonly for changing the + * characteristics of supervisor ptes + */ +#define APMMU_CACHE 0x80 +#define APMMU_DIRTY 0x40 +#define APMMU_REF 0x20 +#define APMMU_EXEC 0x08 +#define APMMU_WRITE 0x04 +#define APMMU_VALID 0x02 /* APMMU_ET_PTE */ +#define APMMU_PRIV 0x1c +#define APMMU_PRIV_RDONLY 0x18 + +#define APMMU_CHG_MASK (0xffffff00 | APMMU_REF | APMMU_DIRTY) + +/* + * "normal" sun systems have their memory on bus 0. This means the top + * 4 bits of 36 bit physical addresses are 0. We use this define to + * determine if a piece of memory might be normal memory, or if its + * definately some sort of device memory. + * + * On the AP+ normal memory is on bus 8. Why? Ask Fujitsu :-) +*/ +#define MEM_BUS_SPACE 8 + +/* Some day I will implement true fine grained access bits for + * user pages because the APMMU gives us the capabilities to + * enforce all the protection levels that vma's can have. + * XXX But for now... + */ +#define APMMU_PAGE_NONE __pgprot((MEM_BUS_SPACE<<28) | \ + APMMU_VALID | APMMU_CACHE | \ + APMMU_PRIV | APMMU_REF) +#define APMMU_PAGE_SHARED __pgprot((MEM_BUS_SPACE<<28) | \ + APMMU_VALID | APMMU_CACHE | \ + APMMU_EXEC | APMMU_WRITE | APMMU_REF) +#define APMMU_PAGE_COPY __pgprot((MEM_BUS_SPACE<<28) | \ + APMMU_VALID | APMMU_CACHE | \ + APMMU_EXEC | APMMU_REF) +#define APMMU_PAGE_RDONLY __pgprot((MEM_BUS_SPACE<<28) | \ + APMMU_VALID | APMMU_CACHE | \ + APMMU_EXEC | APMMU_REF) +#define APMMU_PAGE_KERNEL __pgprot((MEM_BUS_SPACE<<28) | \ + APMMU_VALID | APMMU_CACHE | APMMU_PRIV | \ + APMMU_DIRTY | APMMU_REF) + +#define APMMU_CTXTBL_PTR 0x00000100 +#define APMMU_CTX_REG 0x00000200 + +extern __inline__ unsigned long apmmu_get_ctable_ptr(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (APMMU_CTXTBL_PTR), + "i" (ASI_M_MMUREGS)); + return (retval & APMMU_CTX_PMASK) << 4; +} + +extern __inline__ void apmmu_set_context(int context) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (context), "r" (APMMU_CTX_REG), + "i" (ASI_M_MMUREGS) : "memory"); + /* The AP1000+ message controller also needs to know + the current task's context. */ + MSC_OUT(MSC_PID, context); +} + +extern __inline__ int apmmu_get_context(void) +{ + register int retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (APMMU_CTX_REG), + "i" (ASI_M_MMUREGS)); + return retval; +} + +#endif /* !(_SPARC_PGTAPMMU_H) */ + + diff --git a/include/asm-sparc/asmmacro.h b/include/asm-sparc/asmmacro.h index 679927ff731b..25211c93f828 100644 --- a/include/asm-sparc/asmmacro.h +++ b/include/asm-sparc/asmmacro.h @@ -33,168 +33,14 @@ * lose. It makes sure the kernel has a proper window so that * c-code can be called. */ -#ifndef SMP_DEBUG #define SAVE_ALL_HEAD \ sethi %hi(trap_setup), %l4; \ jmpl %l4 + %lo(trap_setup), %l6; #define SAVE_ALL \ SAVE_ALL_HEAD \ nop; -#else -#define SAVE_ALL_HEAD \ - GET_PROCESSOR_ID(l4); \ - set C_LABEL(trap_log), %l5; \ - sll %l4, 11, %l6; \ - add %l5, %l6, %l5; \ - set C_LABEL(trap_log_ent), %l6; \ - sll %l4, 2, %l4; \ - add %l6, %l4, %l6; \ - ld [%l6], %l6; \ - sll %l6, 3, %l6; \ - st %l1, [%l5 + %l6]; \ - add %l5, 4, %l5; \ - st %l0, [%l5 + %l6]; \ - set C_LABEL(trap_log_ent), %l5; \ - add %l5, %l4, %l5; \ - srl %l6, 3, %l6; \ - add %l6, 1, %l6; \ - and %l6, 255, %l6; \ - st %l6, [%l5]; \ - sethi %hi(trap_setup), %l4; \ - jmpl %l4 + %lo(trap_setup), %l6; -#define SAVE_ALL \ - SAVE_ALL_HEAD \ - nop; -#endif -/* All traps low-level code here must end with this macro. - * For SMP configurations the ret_trap_entry routine will - * have to appropriate code to actually release the kernel - * entry lock. - */ +/* All traps low-level code here must end with this macro. */ #define RESTORE_ALL b ret_trap_entry; clr %l6; -#ifndef __SMP__ - -#define ENTER_SYSCALL -#define LEAVE_SYSCALL -#define ENTER_IRQ -#define LEAVE_IRQ - -#else - -#define INCREMENT_COUNTER(symbol, tmp1, tmp2) \ - set C_LABEL(symbol), %tmp1; \ - ld [%tmp1], %tmp2; \ - add %tmp2, 1, %tmp2; \ - st %tmp2, [%tmp1]; - -#define DECREMENT_COUNTER(symbol, tmp1, tmp2) \ - set C_LABEL(symbol), %tmp1; \ - ld [%tmp1], %tmp2; \ - sub %tmp2, 1, %tmp2; \ - st %tmp2, [%tmp1]; - - /* This is so complicated I suggest you don't look at it. */ -#define ENTER_MASK(mask) \ - GET_PROCESSOR_OFFSET(l4) \ - set C_LABEL(smp_proc_in_lock), %l5; \ - ld [%l5 + %l4], %l6; \ - or %l6, mask, %l6; \ - st %l6, [%l5 + %l4]; \ -1: \ - set C_LABEL(kernel_flag), %l5; \ - ldstub [%l5], %l6; \ - cmp %l6, 0; \ - be 3f; \ - nop; \ - set C_LABEL(active_kernel_processor), %l5; \ - GET_PROCESSOR_ID(l4) \ - ldub [%l5], %l6; \ - cmp %l6, %l4; \ - be 4f; \ - nop; \ -2: \ - GET_PROCESSOR_MID(l4, l5) \ - set C_LABEL(sun4m_interrupts), %l5; \ - ld [%l5], %l5; \ - sll %l4, 12, %l4; \ - add %l5, %l4, %l5; \ - ld [%l5], %l4; \ - sethi %hi(0x80000000), %l6; \ - andcc %l6, %l4, %g0; \ - be 5f; \ - nop; \ - st %l6, [%l5 + 4]; \ - nop; nop; nop; \ - ld [%l5], %g0; \ - nop; nop; nop; \ - or %l0, PSR_PIL, %l4; \ - wr %l4, 0x0, %psr; \ - nop; nop; nop; \ - wr %l4, PSR_ET, %psr; \ - nop; nop; nop; \ - call C_LABEL(smp_message_irq); \ - nop; \ - wr %l0, 0x0, %psr; \ - nop; nop; nop; \ -5: \ - set C_LABEL(kernel_flag), %l5; \ - ldub [%l5], %l6; \ - cmp %l6, 0; \ - bne 2b; \ - nop; \ - b 1b; \ - nop; \ -3: \ - GET_PROCESSOR_ID(l4) \ - set C_LABEL(active_kernel_processor), %l5; \ - stb %l4, [%l5]; \ - GET_PROCESSOR_MID(l4, l5) \ - set C_LABEL(irq_rcvreg), %l5; \ - ld [%l5], %l5; \ - st %l4, [%l5]; \ -4: \ - -#define ENTER_SYSCALL \ - ENTER_MASK(SMP_FROM_SYSCALL) \ - INCREMENT_COUNTER(kernel_counter, l6, l5) \ - INCREMENT_COUNTER(syscall_count, l6, l5) - -#define ENTER_IRQ \ - ENTER_MASK(SMP_FROM_INT) \ - INCREMENT_COUNTER(kernel_counter, l6, l5) - -#define LEAVE_MASK(mask) \ - GET_PROCESSOR_OFFSET(l4) \ - set C_LABEL(smp_proc_in_lock), %l5; \ - ld [%l5 + %l4], %l6; \ - andn %l6, mask, %l6; \ - st %l6, [%l5 + %l4]; - -#define LEAVE_SYSCALL \ - LEAVE_MASK(SMP_FROM_SYSCALL) \ - DECREMENT_COUNTER(syscall_count, l6, l5) \ - set C_LABEL(kernel_counter), %l6; \ - ld [%l6], %l5; \ - subcc %l5, 1, %l5; \ - st %l5, [%l6]; \ - bne 1f; \ - nop; \ - set C_LABEL(active_kernel_processor), %l6; \ - mov NO_PROC_ID, %l5; \ - stb %l5, [%l6]; \ - set C_LABEL(kernel_flag), %l6; \ - stb %g0, [%l6]; \ -1: - -#define LEAVE_IRQ \ - LEAVE_MASK(SMP_FROM_INT) \ - INCREMENT_COUNTER(syscall_count, l6, l5) - - -#define RESTORE_ALL_FASTIRQ b,a ret_irq_entry; - -#endif /* !(__SMP__) */ - #endif /* !(_SPARC_ASMMACRO_H) */ diff --git a/include/asm-sparc/atomic.h b/include/asm-sparc/atomic.h index 9bf9e8ccd781..8629aa50f93c 100644 --- a/include/asm-sparc/atomic.h +++ b/include/asm-sparc/atomic.h @@ -1,4 +1,4 @@ -/* atomic.h: These really suck for now. +/* atomic.h: These still suck, but the I-cache hit rate is higher. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ @@ -12,8 +12,12 @@ typedef int atomic_t; #include #include -/* - * Make sure gcc doesn't try to be clever and move things around +/* We do the bulk of the actual work out of line in two common + * routines in assembler, see arch/sparc/lib/atomic.S for the + * "fun" details. + */ + +/* Make sure gcc doesn't try to be clever and move things around * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ @@ -21,118 +25,74 @@ typedef int atomic_t; static __inline__ void atomic_add(atomic_t i, atomic_t *v) { + register atomic_t *ptr asm("g1"); + register atomic_t increment asm("g2"); + + ptr = (atomic_t *) __atomic_fool_gcc(v); + increment = i; + __asm__ __volatile__(" - rd %%psr, %%g2 - andcc %%g2, %2, %%g0 - bne 1f - nop - wr %%g2, %2, %%psr - nop - nop - nop -1: - ld [%0], %%g3 - add %%g3, %1, %%g3 - andcc %%g2, %2, %%g0 - st %%g3, [%0] - bne 1f - nop - wr %%g2, 0x0, %%psr - nop - nop - nop -1: -" : /* no outputs */ - : "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL) - : "g2", "g3"); + mov %%o7, %%g4 + call ___atomic_add + add %%o7, 8, %%o7 +" : "=&r" (increment) + : "0" (increment), "r" (ptr) + : "g3", "g4", "g7", "memory"); } static __inline__ void atomic_sub(atomic_t i, atomic_t *v) { + register atomic_t *ptr asm("g1"); + register atomic_t increment asm("g2"); + + ptr = (atomic_t *) __atomic_fool_gcc(v); + increment = i; + __asm__ __volatile__(" - rd %%psr, %%g2 - andcc %%g2, %2, %%g0 - bne 1f - nop - wr %%g2, %2, %%psr - nop - nop - nop -1: - ld [%0], %%g3 - sub %%g3, %1, %%g3 - andcc %%g2, %2, %%g0 - st %%g3, [%0] - bne 1f - nop - wr %%g2, 0x0, %%psr - nop - nop - nop -1: -" : /* no outputs */ - : "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL) - : "g2", "g3"); + mov %%o7, %%g4 + call ___atomic_sub + add %%o7, 8, %%o7 +" : "=&r" (increment) + : "0" (increment), "r" (ptr) + : "g3", "g4", "g7", "memory"); } static __inline__ int atomic_add_return(atomic_t i, atomic_t *v) { + register atomic_t *ptr asm("g1"); + register atomic_t increment asm("g2"); + + ptr = (atomic_t *) __atomic_fool_gcc(v); + increment = i; + __asm__ __volatile__(" - rd %%psr, %%g2 - andcc %%g2, %3, %%g0 - bne 1f - nop - wr %%g2, %3, %%psr - nop - nop - nop -1: - ld [%1], %%g3 - add %%g3, %2, %0 - andcc %%g2, %3, %%g0 - st %0, [%1] - bne 1f - nop - wr %%g2, 0x0, %%psr - nop - nop - nop -1: -" : "=&r" (i) - : "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL) - : "g2", "g3"); - - return i; + mov %%o7, %%g4 + call ___atomic_add + add %%o7, 8, %%o7 +" : "=&r" (increment) + : "0" (increment), "r" (ptr) + : "g3", "g4", "g7", "memory"); + + return increment; } static __inline__ int atomic_sub_return(atomic_t i, atomic_t *v) { + register atomic_t *ptr asm("g1"); + register atomic_t increment asm("g2"); + + ptr = (atomic_t *) __atomic_fool_gcc(v); + increment = i; + __asm__ __volatile__(" - rd %%psr, %%g2 - andcc %%g2, %3, %%g0 - bne 1f - nop - wr %%g2, %3, %%psr - nop - nop - nop -1: - ld [%1], %%g3 - sub %%g3, %2, %0 - andcc %%g2, %3, %%g0 - st %0, [%1] - bne 1f - nop - wr %%g2, 0x0, %%psr - nop - nop - nop -1: -" : "=&r" (i) - : "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL) - : "g2", "g3"); - - return i; + mov %%o7, %%g4 + call ___atomic_sub + add %%o7, 8, %%o7 +" : "=&r" (increment) + : "0" (increment), "r" (ptr) + : "g3", "g4", "g7", "memory"); + + return increment; } #define atomic_dec_return(v) atomic_sub_return(1,(v)) diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h index ccdd92246def..5bed92e46749 100644 --- a/include/asm-sparc/bitops.h +++ b/include/asm-sparc/bitops.h @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.41 1996/12/28 18:14:25 davem Exp $ +/* $Id: bitops.h,v 1.43 1997/01/25 04:42:51 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -97,110 +97,56 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr) extern __inline__ unsigned long set_bit(unsigned long nr, __SMPVOL void *addr) { - int mask; - unsigned long *ADDR = (unsigned long *) addr; + register unsigned long mask asm("g2"); + register unsigned long *ADDR asm("g1"); - ADDR += nr >> 5; + ADDR = ((unsigned long *) addr) + (nr >> 5); mask = 1 << (nr & 31); __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ld [%0], %%g4 - or %%g4, %2, %%g2 - andcc %%g3, %3, %%g0 - st %%g2, [%0] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - and %%g4, %2, %0 -" : "=&r" (ADDR) - : "0" (ADDR), "r" (mask), "i" (PSR_PIL) - : "g2", "g3", "g4"); - - return (unsigned long) ADDR; + mov %%o7, %%g4 + call ___set_bit + add %%o7, 8, %%o7 +" : "=&r" (mask) + : "0" (mask), "r" (ADDR) + : "g3", "g4", "g5", "g7"); + + return mask; } extern __inline__ unsigned long clear_bit(unsigned long nr, __SMPVOL void *addr) { - int mask; - unsigned long *ADDR = (unsigned long *) addr; + register unsigned long mask asm("g2"); + register unsigned long *ADDR asm("g1"); - ADDR += nr >> 5; + ADDR = ((unsigned long *) addr) + (nr >> 5); mask = 1 << (nr & 31); __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ld [%0], %%g4 - andn %%g4, %2, %%g2 - andcc %%g3, %3, %%g0 - st %%g2, [%0] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - and %%g4, %2, %0 -" : "=&r" (ADDR) - : "0" (ADDR), "r" (mask), "i" (PSR_PIL) - : "g2", "g3", "g4"); - - return (unsigned long) ADDR; + mov %%o7, %%g4 + call ___clear_bit + add %%o7, 8, %%o7 +" : "=&r" (mask) + : "0" (mask), "r" (ADDR) + : "g3", "g4", "g5", "g7"); + + return mask; } extern __inline__ unsigned long change_bit(unsigned long nr, __SMPVOL void *addr) { - int mask; - unsigned long *ADDR = (unsigned long *) addr; + register unsigned long mask asm("g2"); + register unsigned long *ADDR asm("g1"); - ADDR += nr >> 5; + ADDR = ((unsigned long *) addr) + (nr >> 5); mask = 1 << (nr & 31); __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ld [%0], %%g4 - xor %%g4, %2, %%g2 - andcc %%g3, %3, %%g0 - st %%g2, [%0] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - and %%g4, %2, %0 -" : "=&r" (ADDR) - : "0" (ADDR), "r" (mask), "i" (PSR_PIL) - : "g2", "g3", "g4"); - - return (unsigned long) ADDR; + mov %%o7, %%g4 + call ___change_bit + add %%o7, 8, %%o7 +" : "=&r" (mask) + : "0" (mask), "r" (ADDR) + : "g3", "g4", "g5", "g7"); + + return mask; } #endif /* __KERNEL__ */ @@ -319,74 +265,38 @@ extern __inline__ int clear_le_bit(int nr, void *addr) extern __inline__ int set_le_bit(int nr,void * addr) { - int mask; - unsigned char *ADDR = (unsigned char *) addr; + register int mask asm("g2"); + register unsigned char *ADDR asm("g1"); - ADDR += nr >> 3; + ADDR = ((unsigned char *) addr) + (nr >> 3); mask = 1 << (nr & 0x07); __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ldub [%0], %%g4 - or %%g4, %2, %%g2 - andcc %%g3, %3, %%g0 - stb %%g2, [%0] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - and %%g4, %2, %0 -" : "=&r" (ADDR) - : "0" (ADDR), "r" (mask), "i" (PSR_PIL) - : "g2", "g3", "g4"); - - return (int) ADDR; + mov %%o7, %%g4 + call ___set_le_bit + add %%o7, 8, %%o7 +" : "=&r" (mask) + : "0" (mask), "r" (ADDR) + : "g3", "g4", "g5", "g7"); + + return mask; } extern __inline__ int clear_le_bit(int nr, void * addr) { - int mask; - unsigned char *ADDR = (unsigned char *) addr; + register int mask asm("g2"); + register unsigned char *ADDR asm("g1"); - ADDR += nr >> 3; + ADDR = ((unsigned char *) addr) + (nr >> 3); mask = 1 << (nr & 0x07); __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ldub [%0], %%g4 - andn %%g4, %2, %%g2 - andcc %%g3, %3, %%g0 - stb %%g2, [%0] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - and %%g4, %2, %0 -" : "=&r" (ADDR) - : "0" (ADDR), "r" (mask), "i" (PSR_PIL) - : "g2", "g3", "g4"); - - return (int) ADDR; + mov %%o7, %%g4 + call ___clear_le_bit + add %%o7, 8, %%o7 +" : "=&r" (mask) + : "0" (mask), "r" (ADDR) + : "g3", "g4", "g5", "g7"); + + return mask; } #endif /* __KERNEL__ */ diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index ed7f7903d839..c82063df28e1 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -1,4 +1,4 @@ -/* $Id: ptrace.h,v 1.23 1996/11/25 03:30:24 ecd Exp $ */ +/* $Id: ptrace.h,v 1.24 1997/01/06 06:53:23 davem Exp $ */ #ifndef _SPARC_PTRACE_H #define _SPARC_PTRACE_H @@ -73,7 +73,7 @@ extern void show_regs(struct pt_regs *); #define REGWIN_SZ 0x40 #endif -/* First generic task_struct offsets. sizeof(task_struct)=1552 */ +/* First generic task_struct offsets. sizeof(task_struct)=1568 */ #define TASK_STATE 0x000 #define TASK_PRIORITY 0x008 #define TASK_SIGNAL 0x00c @@ -81,6 +81,7 @@ extern void show_regs(struct pt_regs *); #define TASK_FLAGS 0x014 #define TASK_SAVED_KSTACK 0x054 #define TASK_KSTACK_PG 0x058 +#define TASK_LOCK_DEPTH 0x618 /* Thread stuff. */ #define THREAD_UMASK 0x1e0 @@ -99,10 +100,6 @@ extern void show_regs(struct pt_regs *); #define THREAD_FSR 0x530 #define THREAD_SIGSTK 0x5b8 #define THREAD_FLAGS 0x5c0 -#define THREAD_EX_COUNT 0x5c8 -#define THREAD_EX_PC 0x5cc -#define THREAD_EX_EXPC 0x5d0 -#define THREAD_EX_ADDR 0x5d4 #define THREAD_DS 0x5d8 #define THREAD_MM 0x608 #define THREAD_MM_CTX 0x008 diff --git a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h index 4892ccb268b3..577c4b4a2aab 100644 --- a/include/asm-sparc/semaphore.h +++ b/include/asm-sparc/semaphore.h @@ -1,16 +1,13 @@ #ifndef _SPARC_SEMAPHORE_H #define _SPARC_SEMAPHORE_H -/* Dinky, good for nothing, just barely irq safe, Sparc semaphores. - * - * I'll write better ones later. - */ +/* Dinky, good for nothing, just barely irq safe, Sparc semaphores. */ #include struct semaphore { atomic_t count; - atomic_t waiting; + atomic_t waking; struct wait_queue * wait; }; @@ -18,19 +15,24 @@ struct semaphore { #define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL }) extern void __down(struct semaphore * sem); +extern int __down_interruptible(struct semaphore * sem); extern void __up(struct semaphore * sem); -/* - * This isn't quite as clever as the x86 side, but the gp register - * makes things a bit more complicated on the alpha.. +/* This isn't quite as clever as the x86 side, I'll be fixing this + * soon enough. */ extern inline void down(struct semaphore * sem) { - for (;;) { - if (atomic_dec_return(&sem->count) >= 0) - break; + if (atomic_dec_return(&sem->count) < 0) __down(sem); - } +} + +extern inline int down_interruptible(struct semaphore * sem) +{ + int ret = 0; + if(atomic_dec_return(&sem->count) < 0) + ret = __down_interruptible(sem); + return ret; } extern inline void up(struct semaphore * sem) diff --git a/include/asm-sparc/sigcontext.h b/include/asm-sparc/sigcontext.h index fc2edfecf279..aea2861d7b2b 100644 --- a/include/asm-sparc/sigcontext.h +++ b/include/asm-sparc/sigcontext.h @@ -1,4 +1,4 @@ -/* $Id: sigcontext.h,v 1.10 1996/11/27 01:46:51 miguel Exp $ */ +/* $Id: sigcontext.h,v 1.11 1997/01/19 22:32:07 ecd Exp $ */ #ifndef _ASMsparc_SIGCONTEXT_H #define _ASMsparc_SIGCONTEXT_H @@ -38,7 +38,11 @@ struct sigcontext { }; typedef struct { - struct pt_regs si_regs; + struct pt_regs si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { unsigned long si_float_regs [64]; unsigned long si_fsr; unsigned long si_fpqdepth; @@ -46,8 +50,7 @@ typedef struct { unsigned long *insn_addr; unsigned long insn; } si_fpqueue [16]; - int si_mask; -} __siginfo_t; +} __siginfo_fpu_t; #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index 0d1cab1eb463..56e1f2f5f06f 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -15,6 +15,8 @@ struct prom_cpuinfo { int prom_node; int mid; }; +extern int linux_num_cpus; /* number of CPUs probed */ + #endif /* !(__ASSEMBLY__) */ #ifdef __SMP__ @@ -31,8 +33,13 @@ struct cpuinfo_sparc { extern struct cpuinfo_sparc cpu_data[NR_CPUS]; -typedef __volatile__ unsigned char klock_t; -extern klock_t kernel_flag; +struct klock_info { + unsigned char kernel_flag; + unsigned char akp; + unsigned char irq_udt; +}; + +extern struct klock_info klock_info; #define KLOCK_HELD 0xff #define KLOCK_CLEAR 0x00 @@ -45,12 +52,8 @@ extern int smp_found_cpus; extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS]; -extern __volatile__ unsigned long kernel_counter; -extern __volatile__ unsigned char active_kernel_processor; extern void smp_message_irq(void); extern unsigned long ipi_count; -extern __volatile__ unsigned long kernel_counter; -extern __volatile__ unsigned long syscall_count; extern void print_lock_state(void); @@ -167,6 +170,11 @@ extern __inline__ __volatile__ int read_smp_counter(volatile int *ctr) #define SMP_FROM_INT 1 #define SMP_FROM_SYSCALL 2 +#else /* !(__SMP__) */ + +#define smp_capture() do { } while(0) +#define smp_release() do { } while(0) + #endif /* !(__SMP__) */ #endif /* !(_SPARC_SMP_H) */ diff --git a/include/asm-sparc/smp_lock.h b/include/asm-sparc/smp_lock.h index 7ce71d8ff62c..55820ffd635a 100644 --- a/include/asm-sparc/smp_lock.h +++ b/include/asm-sparc/smp_lock.h @@ -1,4 +1,4 @@ -/* smp_lock.h: Locking and unlocking the kernel on the Sparc. +/* smp_lock.h: SMP locking primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ @@ -7,52 +7,142 @@ #define __SPARC_SMPLOCK_H #include -#include -#include -#include +#include -#ifdef __SMP__ +#ifndef __SMP__ +#define lock_kernel() do { } while(0) +#define unlock_kernel() do { } while(0) -/* - * Locking the kernel +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED + +#define spin_lock_init(lock) do { } while(0) +#define spin_lock(lock) do { } while(0) +#define spin_trylock(lock) do { } while(0) +#define spin_unlock(lock) do { } while(0) + +#define spin_lock_cli(lock) \ +({ unsigned long flags; \ + save_flags(flags); cli(); \ + return flags; \ +}) + +#define spin_unlock_restore(lock, flags) restore_flags(flags) +#else + +/* The following acquire and release the master kernel global lock, + * the idea is that the usage of this mechanmism becomes less and less + * as time goes on, to the point where they are no longer needed at all + * and can thus disappear. */ -/* Knock knock... */ +/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */ extern __inline__ void lock_kernel(void) { - unsigned long flags; - int proc = smp_processor_id(); - - save_flags(flags); cli(); /* need this on sparc? */ - while(ldstub(&kernel_flag)) { - if(proc == active_kernel_processor) - break; - do { -#ifdef __SMP_PROF__ - smp_spins[smp_processor_id()]++; -#endif - barrier(); - } while(kernel_flag); /* Don't lock the bus more than we have to. */ - } - active_kernel_processor = proc; - kernel_counter++; - restore_flags(flags); -} - -/* I want out... */ + register struct klock_info *klip asm("g1"); + register int proc asm("g5"); + klip = &klock_info; proc = smp_processor_id(); + __asm__ __volatile__(" + mov %%o7, %%g4 + call ___lock_kernel + ld [%%g6 + %0], %%g2 +" : : "i" (TASK_LOCK_DEPTH), "r" (klip), "r" (proc) + : "g2", "g3", "g4", "g7", "memory"); +} + +/* Release kernel global lock. */ extern __inline__ void unlock_kernel(void) { - unsigned long flags; + register struct klock_info *klip asm("g1"); + klip = &klock_info; + __asm__ __volatile__(" + mov %%o7, %%g4 + call ___unlock_kernel + ld [%%g6 + %0], %%g2 +" : : "i" (TASK_LOCK_DEPTH), "r" (klip) + : "g2", "g3", "g4", "memory"); +} + +/* Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + */ + +typedef unsigned char spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 + +extern __inline__ void spin_lock_init(spinlock_t *lock) +{ + *lock = 0; +} + +extern __inline__ void spin_lock(spinlock_t *lock) +{ + register spinlock_t *lp asm("g1"); + lp = lock; + __asm__ __volatile__(" + ldstub [%%g1], %%g2 + orcc %%g2, 0x0, %%g0 + be 1f + mov %%o7, %%g4 + call ___spinlock_waitfor + ldub [%%g1], %%g2 +1:" : /* no outputs */ + : "r" (lp) + : "g2", "g4", "memory"); +} + +extern __inline__ int spin_trylock(spinlock_t *lock) +{ + unsigned int result; + + __asm__ __volatile__(" + ldstub [%1], %0 +" : "=r" (result) : "r" (lock) : "memory"); + + return (result == 0); +} + +extern __inline__ void spin_unlock(spinlock_t *lock) +{ + __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); +} - save_flags(flags); cli(); /* need this on sparc? */ - if(kernel_counter == 0) - panic("Bogus kernel counter.\n"); +/* These variants clear interrupts and return save_flags() style flags + * to the caller when acquiring a lock. To release the lock you must + * pass the lock pointer as well as the flags returned from the acquisition + * routine when releasing the lock. + */ +extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock) +{ + register spinlock_t *lp asm("g1"); + register unsigned long flags asm("g3"); + lp = lock; + __asm__ __volatile__(" + rd %%psr, %%g3 + or %%g3, %1, %%g4 + wr %%g4, 0, %%psr + nop; nop; nop; + ldstub [%%g1], %%g2 + orcc %%g2, 0x0, %%g0 + be 1f + mov %%o7, %%g4 + call ___spinlock_waitfor + ldub [%%g1], %%g2 +1:" : "=r" (flags) + : "i" (PSR_PIL), "r" (lp) + : "g2", "g4", "memory"); + return flags; +} - if(!--kernel_counter) { - active_kernel_processor = NO_PROC_ID; - kernel_flag = KLOCK_CLEAR; - } - restore_flags(flags); +extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags) +{ + __asm__ __volatile__(" + stb %%g0, [%0] + wr %1, 0, %%psr + nop; nop; nop; +" : /* no outputs */ + : "r" (lock), "r" (flags) + : "memory"); } #endif /* !(__SPARC_SMPLOCK_H) */ diff --git a/include/asm-sparc/string.h b/include/asm-sparc/string.h index 856e96f6dca6..ecc4c0b3e98f 100644 --- a/include/asm-sparc/string.h +++ b/include/asm-sparc/string.h @@ -1,4 +1,4 @@ -/* $Id: string.h,v 1.27 1996/10/27 08:55:50 davem Exp $ +/* $Id: string.h,v 1.28 1997/01/15 16:01:54 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * @@ -15,8 +15,17 @@ /* First the mem*() things. */ #define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMMOVE +extern void __memmove(void *,const void *,__kernel_size_t); + +#undef memmove +#define memmove(_to, _from, _n) \ +({ \ + __memmove(_to, _from, _n); \ + _to; \ +}) + #define __HAVE_ARCH_MEMCPY -extern void *__memcpy(void *,const void *,__kernel_size_t); +extern void __memcpy(void *,const void *,__kernel_size_t); extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) { diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 88621c1c481d..8965ffb51715 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.47 1996/12/30 00:31:12 davem Exp $ */ +/* $Id: system.h,v 1.51 1997/01/25 01:33:05 davem Exp $ */ #ifndef __SPARC_SYSTEM_H #define __SPARC_SYSTEM_H @@ -55,14 +55,12 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, #define SWITCH_ENTER \ cli(); \ if(prev->flags & PF_USEDFPU) { \ + put_psr(get_psr() | PSR_EF); \ fpsave(&prev->tss.float_regs[0], &prev->tss.fsr, \ &prev->tss.fpqueue[0], &prev->tss.fpqdepth); \ prev->flags &= ~PF_USEDFPU; \ prev->tss.kregs->psr &= ~PSR_EF; \ - } \ - prev->lock_depth = syscall_count; \ - kernel_counter += (next->lock_depth - prev->lock_depth); \ - syscall_count = next->lock_depth; + } #define SWITCH_EXIT sti(); #define SWITCH_DO_LAZY_FPU @@ -235,33 +233,21 @@ extern char spdeb_buf[256]; extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) { - __asm__ __volatile__(" - rd %%psr, %%g3 - andcc %%g3, %3, %%g0 - bne 1f - nop - wr %%g3, %3, %%psr - nop - nop - nop -1: - ld [%1], %%g2 - andcc %%g3, %3, %%g0 - st %2, [%1] - bne 1f - nop - wr %%g3, 0x0, %%psr - nop - nop - nop -1: - mov %%g2, %0 - " - : "=&r" (val) - : "r" (m), "0" (val), "i" (PSR_PIL) - : "g2", "g3"); + register unsigned long *ptr asm("g1"); + register unsigned long ret asm("g2"); - return val; + ptr = (unsigned long *) m; + ret = val; + + __asm__ __volatile__(" + mov %%o7, %%g4 + call ___xchg32 + add %%o7, 8, %%o7 +" : "=&r" (ret) + : "0" (ret), "r" (ptr) + : "g3", "g4", "g7", "memory"); + + return ret; } #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) diff --git a/include/asm-sparc/termios.h b/include/asm-sparc/termios.h index c893cf32143b..72a4b807c95f 100644 --- a/include/asm-sparc/termios.h +++ b/include/asm-sparc/termios.h @@ -1,4 +1,4 @@ -/* $Id: termios.h,v 1.23 1996/12/30 06:17:03 davem Exp $ */ +/* $Id: termios.h,v 1.24 1996/12/31 22:35:45 davem Exp $ */ #ifndef _SPARC_TERMIOS_H #define _SPARC_TERMIOS_H diff --git a/include/asm-sparc/uaccess.h b/include/asm-sparc/uaccess.h index face5b42c318..157a3256e9e1 100644 --- a/include/asm-sparc/uaccess.h +++ b/include/asm-sparc/uaccess.h @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.9 1996/12/03 08:44:54 jj Exp $ */ +/* $Id: uaccess.h,v 1.10 1997/01/16 14:19:03 davem Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 8c1658e7481c..921d7463e8dc 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.26 1996/12/29 20:49:14 davem Exp $ */ +/* $Id: unistd.h,v 1.28 1997/01/26 07:12:06 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -169,7 +169,7 @@ #define __NR_getsockname 150 /* SunOS Specific */ #define __NR_getmsg 151 /* SunOS Specific */ #define __NR_putmsg 152 /* SunOS Specific */ -#define __NR_poll 153 /* SunOS Specific */ +#define __NR_poll 153 /* Common */ /* #define __NR_ni_syscall 154 ENOSYS under SunOS */ #define __NR_nfssvc 155 /* SunOS Specific */ #define __NR_getdirentries 156 /* SunOS Specific */ @@ -286,7 +286,7 @@ __asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \ : "=r" (__res)\ : "0" (__NR_##name) \ : "g1", "o0"); \ -if (__res >= 0) \ +if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ @@ -306,7 +306,7 @@ __asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \ : "=r" (__res), "=r" ((long)(arg1)) \ : "0" (__NR_##name),"1" ((long)(arg1)) \ : "g1", "o0"); \ -if (__res >= 0) \ +if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ @@ -327,7 +327,7 @@ __asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \ : "g1", "o0", "o1"); \ -if (__res >= 0) \ +if (__res < -255 || __res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ @@ -351,7 +351,7 @@ __asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \ : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \ "3" ((long)(arg3)) \ : "g1", "o0", "o1", "o2"); \ -if (__res>=0) \ +if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ return -1; \ @@ -376,7 +376,7 @@ __asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ "3" ((long)(arg3)),"4" ((long)(arg4)) \ : "g1", "o0", "o1", "o2", "o3"); \ -if (__res>=0) \ +if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ return -1; \ @@ -404,7 +404,7 @@ __asm__ __volatile__ ("or %%g0, %1, %%o0\n\t" \ "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \ "i" (__NR_##name) \ : "g1", "o0", "o1", "o2", "o3", "o4"); \ -if (__res>=0) \ +if (__res < -255 || __res>=0) \ return (type) __res; \ errno = -__res; \ return -1; \ diff --git a/include/asm-sparc64/sigcontext.h b/include/asm-sparc64/sigcontext.h index 418d4fa37aa8..eaefcd093abf 100644 --- a/include/asm-sparc64/sigcontext.h +++ b/include/asm-sparc64/sigcontext.h @@ -1,4 +1,4 @@ -/* $Id: sigcontext.h,v 1.1 1996/12/26 14:22:36 davem Exp $ */ +/* $Id: sigcontext.h,v 1.2 1997/01/19 22:32:15 ecd Exp $ */ #ifndef _ASMsparc64_SIGCONTEXT_H #define _ASMsparc64_SIGCONTEXT_H @@ -39,19 +39,27 @@ struct sigcontext { }; typedef struct { - struct pt_regs32 si_regs; - unsigned int si_float_regs [64]; - unsigned int si_fsr; - unsigned int si_fpqdepth; + struct pt_regs32 si_regs; + int si_mask; +} __siginfo32_t; + +typedef struct { + unsigned int si_float_regs [64]; + unsigned int si_fsr; + unsigned int si_fpqdepth; struct { unsigned int *insn_addr; unsigned int insn; } si_fpqueue [16]; - int si_mask; -} __siginfo32_t; +} __siginfo_fpu32_t; + typedef struct { struct pt_regs si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { unsigned long si_float_regs [64]; unsigned long si_fsr; unsigned int si_fpqdepth; @@ -59,8 +67,7 @@ typedef struct { unsigned int *insn_addr; unsigned int insn; } si_fpqueue [16]; - int si_mask; -} __siginfo_t; +} __siginfo_fpu_t; #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc64/termios.h b/include/asm-sparc64/termios.h index 2696e4391e3e..f56f0d159589 100644 --- a/include/asm-sparc64/termios.h +++ b/include/asm-sparc64/termios.h @@ -1,4 +1,4 @@ -/* $Id: termios.h,v 1.2 1996/12/30 03:31:12 davem Exp $ */ +/* $Id: termios.h,v 1.3 1996/12/31 22:35:49 davem Exp $ */ #ifndef _SPARC64_TERMIOS_H #define _SPARC64_TERMIOS_H diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h index 938b6cc073d2..0b86c27eebf4 100644 --- a/include/asm-sparc64/uaccess.h +++ b/include/asm-sparc64/uaccess.h @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.2 1996/12/26 15:36:53 davem Exp $ */ +/* $Id: uaccess.h,v 1.3 1997/01/16 14:19:08 davem Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 6c424fbe9b1a..de8f05598ffe 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -33,7 +33,7 @@ struct linux_binprm{ */ struct linux_binfmt { struct linux_binfmt * next; - long *use_count; + struct module *module; int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(int fd); int (*core_dump)(long signr, struct pt_regs * regs); diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 0f6d0283bbcf..59da08849b92 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -24,7 +24,7 @@ #ifndef _LINUX_ETHERDEVICE_H #define _LINUX_ETHERDEVICE_H - +#include #include #ifdef __KERNEL__ @@ -37,9 +37,17 @@ extern void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr); extern int eth_header_cache(struct dst_entry *dst, struct dst_entry *neigh, struct hh_cache *hh); +extern struct device * init_etherdev(struct device *, int); + +#ifdef CONFIG_IP_ROUTER +static void inline eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base) +{ + memcpy (dest->data, src, len); +} +#else extern void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base); -extern struct device * init_etherdev(struct device *, int); +#endif #endif diff --git a/include/linux/init.h b/include/linux/init.h new file mode 100644 index 000000000000..a5d4b04e0aa6 --- /dev/null +++ b/include/linux/init.h @@ -0,0 +1,55 @@ +#ifndef _LINUX_INIT_H +#define _LINUX_INIT_H + +/* These macros are used to mark some functions or + * initialized data (doesn't apply to uninitialized data) + * as `initialization' functions. The kernel can take this + * as hint that the function is used only during the initialization + * phase and free up used memory resources after + * + * Usage: + * For functions: + * you can surround the whole function declaration + * just before function body into __initfunc() macro, like: + * + * __initfunc (static void initme(int x, int y)) + * { + * extern int z; z = x * y; + * } + * + * if the function has a prototype somewhere, you can also add + * __init between closing brace of the prototype and semicolon: + * + * extern int initialize_foobar_device(int, int, int) __init; + * + * For initialized data: + * you should insert __initdata between the variable name and equal + * sign followed by value, e.g.: + * + * static int init_variable __initdata = 0; + * static char linux_logo[] __initdata = { 0x32, 0x36, ... }; + */ + +#ifndef __init +#if (defined (__svr4__) || defined (__ELF__)) && !defined (MODULE) +#define __init __attribute__ ((__section__ (".text.init"))) +#define __initdata __attribute__ ((__section__ (".data.init"))) +#define __initfunc(__arginit) \ + __arginit __init; \ + __arginit +/* For assembly routines */ +#define __INIT .section ".text.init",#alloc,#execinstr +#define __FINIT .previous +#define __INITDATA .section ".data.init",#alloc,#write +#else +#define __init +#define __initdata +#define __initfunc(__arginit) __arginit +/* For assembly routines */ +#define __INIT +#define __FINIT +#define __INITDATA +#endif +#endif + +#endif diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 335e3b65f763..0edaf80c7bec 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -22,6 +22,11 @@ extern void request_region(unsigned int from, unsigned int extent,const char *na extern void release_region(unsigned int from, unsigned int extent); extern int get_ioport_list(char *); +#ifdef __sparc__ +extern unsigned int occupy_region(unsigned int base, unsigned int end, + unsigned int num, unsigned int align, + const char *name); +#endif #define HAVE_AUTOIRQ extern void *irq2dev_map[16]; /* Use only if you own the IRQ. */ diff --git a/include/linux/locks.h b/include/linux/locks.h index 9735bc630ee9..37933f63e112 100644 --- a/include/linux/locks.h +++ b/include/linux/locks.h @@ -8,12 +8,6 @@ #include #endif -/* - * Unlocked, temporary IO buffer_heads gets moved to the reuse_list - * once their page becomes unlocked. - */ -extern struct buffer_head *reuse_list; - /* * Buffer cache locking - note that interrupts may only unlock, not * lock buffers. diff --git a/include/linux/mm.h b/include/linux/mm.h index aa13c7773e20..64c5c344f1de 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -75,6 +75,7 @@ struct vm_area_struct { #define VM_EXECUTABLE 0x1000 #define VM_LOCKED 0x2000 +#define VM_IO 0x4000 /* Memory mapped I/O or similar */ #define VM_STACK_FLAGS 0x0177 @@ -273,6 +274,7 @@ extern void oom(struct task_struct * tsk); extern void si_meminfo(struct sysinfo * val); /* mmap.c */ +extern void vma_init(void); extern unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long off); extern void merge_segments(struct mm_struct *, unsigned long, unsigned long); diff --git a/include/linux/module.h b/include/linux/module.h index 853acca8f59d..48fc78e60c9b 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -7,6 +7,8 @@ #ifndef _LINUX_MODULE_H #define _LINUX_MODULE_H +#include + #ifdef __GENKSYMS__ # define _set_ver(sym) sym # undef MODVERSIONS @@ -22,7 +24,7 @@ /* Don't need to bring in all of uaccess.h just for this decl. */ struct exception_table_entry; -/* Used by get_kernel_syms, which is depreciated. */ +/* Used by get_kernel_syms, which is obsolete. */ struct kernel_sym { unsigned long value; @@ -73,6 +75,7 @@ struct module to examine them. */ const struct module_persist *persist_start; const struct module_persist *persist_end; + int (*can_unload)(void); }; struct module_info @@ -80,6 +83,7 @@ struct module_info unsigned long addr; unsigned long size; unsigned long flags; + long usecount; }; /* Bits of module.flags. */ @@ -99,20 +103,27 @@ struct module_info #define QM_SYMBOLS 4 #define QM_INFO 5 +/* When struct module is extended, we must test whether the new member + is present in the header received from insmod before we can use it. + This function returns true if the member is present. */ + +#define mod_member_present(mod,member) \ + ((unsigned long)(&((struct module *)0L)->member + 1) \ + <= (mod)->size_of_struct) + /* Backwards compatibility definition. */ #define GET_USE_COUNT(module) ((module)->usecount) -/* When the struct module is extended, new values must be examined using - this macro. It returns a pointer to the member if available, NULL - otherwise. */ +/* Poke the use count of a module. */ -#define mod_opt_member(mod,member) \ - ({ struct module *_mod = (mod); \ - __typeof__(_mod->member) *_mem = &_mod->member; \ - ((char *)(_mem+1) > (char *)_mod + _mod->size_of_struct \ - ? (__typeof__(_mod->member) *)NULL : _mem); \ - }) +#define __MOD_INC_USE_COUNT(mod) \ + ((mod)->usecount++, (mod)->flags |= MOD_VISITED|MOD_USED_ONCE) +#define __MOD_DEC_USE_COUNT(mod) \ + ((mod)->usecount--, (mod)->flags |= MOD_VISITED) +#define __MOD_IN_USE(mod) \ + (mod_member_present((mod), can_unload) && (mod)->can_unload \ + ? (mod)->can_unload() : (mod)->usecount) /* Indirect stringification. */ @@ -170,13 +181,9 @@ __asm__(".section .modinfo\n\t.previous"); /* Define the module variable, and usage macros. */ extern struct module __this_module; -#define MOD_INC_USE_COUNT \ - (__this_module.usecount++, \ - __this_module.flags |= MOD_VISITED|MOD_USED_ONCE) -#define MOD_DEC_USE_COUNT \ - (__this_module.usecount--, __this_module.flags |= MOD_VISITED) -#define MOD_IN_USE \ - (__this_module.usecount != 0) +#define MOD_INC_USE_COUNT __MOD_INC_USE_COUNT(&__this_module) +#define MOD_DEC_USE_COUNT __MOD_DEC_USE_COUNT(&__this_module) +#define MOD_IN_USE __MOD_IN_USE(&__this_module) #ifndef __NO_VERSION__ #include @@ -221,12 +228,6 @@ extern struct module *module_list; /* We want the EXPORT_SYMBOL tag left intact for recognition. */ -#elif !defined(EXPORT_SYMTAB) && defined(CONFIG_MODULES) - -#define __EXPORT_SYMBOL(sym,str) error EXPORT_SYMTAB_not_defined -#define EXPORT_SYMBOL(var) error EXPORT_SYMTAB_not_defined -#define EXPORT_SYMBOL_NOVERS(var) error EXPORT_SYMTAB_not_defined - #elif !defined(AUTOCONF_INCLUDED) #define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module @@ -239,6 +240,14 @@ extern struct module *module_list; #define EXPORT_SYMBOL(var) #define EXPORT_SYMBOL_NOVERS(var) +#elif !defined(EXPORT_SYMTAB) + +/* If things weren't set up in the Makefiles to get EXPORT_SYMTAB defined, + then they weren't set up to run genksyms properly so MODVERSIONS breaks. */ +#define __EXPORT_SYMBOL(sym,str) error EXPORT_SYMTAB_not_defined +#define EXPORT_SYMBOL(var) error EXPORT_SYMTAB_not_defined +#define EXPORT_SYMBOL_NOVERS(var) error EXPORT_SYMTAB_not_defined + #else #define __EXPORT_SYMBOL(sym, str) \ diff --git a/include/linux/mpp.h b/include/linux/mpp.h new file mode 100644 index 000000000000..2dd02ff4e9a3 --- /dev/null +++ b/include/linux/mpp.h @@ -0,0 +1,18 @@ +#ifndef _LINUX_MPP_H +#define _LINUX_MPP_H + +/* + * Definitions related to Massively Parallel Processing support. + */ + +/* All mpp implementations must supply these functions */ + +extern void mpp_init(void); +extern void mpp_hw_init(void); +extern void mpp_procfs_init(void); + +extern int mpp_num_cells(void); +extern int mpp_cid(void); +extern int get_mppinfo(char *buffer); + +#endif diff --git a/include/linux/personality.h b/include/linux/personality.h index 91538d2bde3c..d6803d151eb2 100644 --- a/include/linux/personality.h +++ b/include/linux/personality.h @@ -37,7 +37,7 @@ struct exec_domain { unsigned char pers_low, pers_high; unsigned long * signal_map; unsigned long * signal_invmap; - long *use_count; + struct module * module; struct exec_domain *next; }; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index b41aa9463db7..11c22b726308 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -46,7 +46,8 @@ enum root_directory_inos { PROC_MD, PROC_RTC, PROC_LOCKS, - PROC_ZORRO + PROC_ZORRO, + PROC_SLABINFO }; enum pid_directory_inos { diff --git a/include/linux/sched.h b/include/linux/sched.h index 4fe6eece3cf8..7b3938ba1d78 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -154,7 +154,7 @@ struct mm_struct { #define INIT_MM { \ 1, \ swapper_pg_dir, \ - 0, \ + -1, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ 0, 0, 0, 0, \ @@ -167,6 +167,7 @@ struct signal_struct { struct sigaction action[32]; }; + #define INIT_SIGNALS { \ 1, \ { {0,}, } } @@ -245,11 +246,10 @@ struct task_struct { struct mm_struct *mm; /* signal handlers */ struct signal_struct *sig; -#ifdef __SMP__ +/* SMP state */ int processor; int last_processor; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ -#endif }; /* @@ -311,6 +311,7 @@ struct task_struct { /* files */ &init_files, \ /* mm */ &init_mm, \ /* signals */ &init_signals, \ +/* SMP */ 0,0,0, \ } extern struct mm_struct init_mm; @@ -376,12 +377,10 @@ extern void exit_mm(struct task_struct *); extern void exit_fs(struct task_struct *); extern void exit_files(struct task_struct *); extern void exit_sighand(struct task_struct *); -extern void release_thread(struct task_struct *); extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *); - /* See if we have a valid user level fd. * If it makes sense, return the file structure it references. * Otherwise return NULL. diff --git a/include/linux/slab.h b/include/linux/slab.h new file mode 100644 index 000000000000..ccd2ba1d376a --- /dev/null +++ b/include/linux/slab.h @@ -0,0 +1,60 @@ +/* + * linux/mm/slab.h + * Written by Mark Hemment, 1996. + * (markhe@nextd.demon.co.uk) + */ + +#if !defined(_LINUX_SLAB_H) +#define _LINUX_SLAB_H + +#if defined(__KERNEL__) + +typedef struct kmem_cache_s kmem_cache_t; + +#include + +/* flags for kmem_cache_alloc() */ +#define SLAB_BUFFER GFP_BUFFER /* 0x00 */ +#define SLAB_ATOMIC GFP_ATOMIC /* 0x01 */ +#define SLAB_USER GFP_USER /* 0x02 */ +#define SLAB_KERNEL GFP_KERNEL /* 0x03 */ +#define SLAB_NOBUFFER GFP_NOBUFFER /* 0x04 */ +#define SLAB_NFS GFP_NFS /* 0x05 */ +#define SLAB_DMA GFP_DMA /* 0x08 */ +#define SLAB_LEVEL_MASK GFP_LEVEL_MASK /* 0x0f */ +#define SLAB_NO_GROW 0x00001000UL /* don't add another slab during an alloc */ + +/* flags to pass to kmem_cache_create(). + * The first 3 are only valid when the allocator has been build + * SLAB_DEBUG_SUPPORT. + */ +#define SLAB_DEBUG_FREE 0x00000100UL /* Peform time consuming ptr checks on free */ +#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor, on release, to conform state */ +#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */ +#define SLAB_HWCACHE_ALIGN 0x00000800UL /* align objs on an hw cache line */ + +/* flags passed to a constructor func */ +#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */ +#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */ +#define SLAB_DTOR_ATOMIC 0x002UL /* tell deconstructor it can't sleep */ +#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */ + +/* prototypes */ +extern long kmem_cache_init(long, long); +extern void kmem_cache_sizes_init(void); +extern struct kmem_cache_s *kmem_cache_create(const char *, unsigned long, unsigned long, unsigned long, void (*)(void *, int, unsigned long), void (*)(void *, int, unsigned long)); +extern int kmem_cache_destroy(struct kmem_cache_s *); +extern int kmem_cache_shrink(struct kmem_cache_s *, int); +extern void *kmem_cache_alloc(struct kmem_cache_s *, unsigned long); +extern void kmem_cache_free(struct kmem_cache_s *, void *); +extern void *kmem_alloc(unsigned long, unsigned long); +extern void kmem_free(void *, unsigned long); +extern int kmem_cache_reap(int, int, int); +extern int get_slabinfo(char *); + +/* System wide slabs. */ +extern kmem_cache_t *vm_area_cachep; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SLAB_H */ diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 14c9f5b472c3..f49013267efd 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h @@ -1,9 +1,6 @@ #ifndef __LINUX_SMPLOCK_H #define __LINUX_SMPLOCK_H -#ifdef __SMP__ -#include #include -#endif #endif diff --git a/include/linux/tasks.h b/include/linux/tasks.h index 4540e34f0f44..4a82ad4e0491 100644 --- a/include/linux/tasks.h +++ b/include/linux/tasks.h @@ -16,4 +16,10 @@ #define MAX_TASKS_PER_USER (NR_TASKS/2) #define MIN_TASKS_LEFT_FOR_ROOT 4 + +/* + * This controls the maximum pid allocated to a process + */ +#define PID_MAX 0x8000 + #endif diff --git a/init/main.c b/init/main.c index d3b746e6c0ba..aeeffdc6967d 100644 --- a/init/main.c +++ b/init/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_ROOT_NFS @@ -67,6 +68,7 @@ extern long kmalloc_init(long,long); extern void sock_init(void); extern unsigned long pci_init(unsigned long, unsigned long); extern long mca_init(long, long); +extern long sbus_init(long, long); extern void sysctl_init(void); extern void smp_setup(char *str, int *ints); @@ -200,6 +202,10 @@ extern void wdt_setup(char *str, int *ints); extern void ipc_init(void); #endif +#ifdef __sparc__ +extern int serial_console; +#endif + /* * Boot command-line arguments */ @@ -607,6 +613,12 @@ static void parse_root_dev(char * line) { "sonycd", 0x1800 }, { "eza", 0x2800 }, { "bpcd", 0x2900 }, +#if CONFIG_APBLOCK + { "apblock", APBLOCK_MAJOR << 8}, +#endif +#if CONFIG_DDV + { "ddv", DDV_MAJOR << 8}, +#endif { NULL, 0 } }; @@ -753,45 +765,28 @@ asmlinkage void start_secondary(void) -/* - * Called by CPU#0 to activate the rest. - */ - +/* Called by boot processor to activate the rest. */ static void smp_init(void) { int i, j; + + /* Get other processors into their bootup holding patterns. */ smp_boot_cpus(); - - /* - * Create the slave init tasks as sharing pid 0. - * - * This should only happen if we have virtual CPU numbers - * higher than 0. - */ + /* Create the slave init tasks as sharing pid 0. This should only + * happen if we have virtual CPU numbers higher than 0. + */ for (i=1; iprocessor=j; - cli(); - n = task[i]->next_run; - p = task[i]->prev_run; - nr_running--; - n->prev_run = p; - p->next_run = n; - task[i]->next_run = task[i]->prev_run = task[i]; - sti(); } } @@ -859,6 +854,9 @@ asmlinkage void start_kernel(void) memory_start += prof_len * sizeof(unsigned int); memset(prof_buffer, 0, prof_len * sizeof(unsigned int)); } +#ifdef CONFIG_SBUS + memory_start = sbus_init(memory_start,memory_end); +#endif memory_start = console_init(memory_start,memory_end); #ifdef CONFIG_PCI memory_start = pci_init(memory_start,memory_end); @@ -867,19 +865,22 @@ asmlinkage void start_kernel(void) memory_start = mca_init(memory_start,memory_end); #endif memory_start = kmalloc_init(memory_start,memory_end); + memory_start = kmem_cache_init(memory_start, memory_end); sti(); calibrate_delay(); memory_start = inode_init(memory_start,memory_end); memory_start = file_table_init(memory_start,memory_end); memory_start = name_cache_init(memory_start,memory_end); #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start && initrd_start < memory_start) { + if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it.\n",initrd_start,memory_start); initrd_start = 0; } #endif mem_init(memory_start,memory_end); + kmem_cache_sizes_init(); + vma_init(); buffer_init(); sock_init(); #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) @@ -943,6 +944,14 @@ static int init(void * unused) /* Start the background pageout daemon. */ kernel_thread(kswapd, NULL, 0); +#if CONFIG_AP1000 + /* Start the async paging daemon. */ + { + extern int asyncd(void *); + kernel_thread(asyncd, NULL, 0); + } +#endif + #ifdef CONFIG_BLK_DEV_INITRD real_root_dev = ROOT_DEV; real_root_mountflags = root_mountflags; @@ -979,8 +988,8 @@ static int init(void * unused) root_mountflags = real_root_mountflags; if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) { int error; - int pid,i; - + int i, pid; + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid>0) while (pid != wait(&i)); @@ -992,17 +1001,18 @@ static int init(void * unused) } } #endif - - /* - * This keeps serial console MUCH cleaner, but does assume - * the console driver checks there really is a video device - * attached (Sparc effectively does). - */ - if ((open("/dev/tty1",O_RDWR,0) < 0) && - (open("/dev/ttyS0",O_RDWR,0) < 0)) - printk("Unable to open an initial console.\n"); - +#ifdef __sparc__ + if (serial_console == 1) { + (void) open("/dev/cua0", O_RDWR, 0); + } else if (serial_console == 2) { + (void) open("/dev/cua1", O_RDWR, 0); + } else { +#endif + (void) open("/dev/tty1", O_RDWR, 0); +#ifdef __sparc__ + } +#endif (void) dup(0); (void) dup(0); @@ -1013,7 +1023,7 @@ static int init(void * unused) * trying to recover a really broken machine. */ - if (execute_command) + if(execute_command) execve(execute_command,argv_init,envp_init); execve("/sbin/init",argv_init,envp_init); execve("/etc/init",argv_init,envp_init); diff --git a/ipc/msg.c b/ipc/msg.c index 0ed1eb6a6ba0..ec83ac7725ef 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include @@ -393,15 +395,25 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { + int ret; + /* IPC_KERNELD is used as a marker for kernel level calls */ - return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD); + lock_kernel(); + ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD); + unlock_kernel(); + return ret; } asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { + int ret; + /* IPC_KERNELD is used as a marker for kernel level calls */ - return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD); + lock_kernel(); + ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD); + unlock_kernel(); + return ret; } static int findkey (key_t key) @@ -463,51 +475,60 @@ found: asmlinkage int sys_msgget (key_t key, int msgflg) { - int id; + int id, ret = -EPERM; struct msqid_ds *msq; /* * If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE, * and a designated kerneld message queue is created/referred to */ + lock_kernel(); if ((msgflg & IPC_KERNELD)) { int i; if (!suser()) - return -EPERM; + goto out; #ifdef NEW_KERNELD_PROTOCOL if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) { printk(KERN_ALERT "Please recompile your kerneld daemons!\n"); - return -EPERM; + goto out; } #endif + ret = -ENOSPC; if ((kerneld_msqid == -1) && (kerneld_msqid = newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0) - return -ENOSPC; + goto out; for (i = 0; i < MAX_KERNELDS; ++i) { if (kerneld_arr[i] == 0) { kerneld_arr[i] = current->pid; ++n_kernelds; - return kerneld_msqid; + ret = kerneld_msqid; + goto out; } } - return -ENOSPC; + goto out; } /* else it is a "normal" request */ if (key == IPC_PRIVATE) - return newque(key, msgflg); - if ((id = findkey (key)) == -1) { /* key not used */ + ret = newque(key, msgflg); + else if ((id = findkey (key)) == -1) { /* key not used */ if (!(msgflg & IPC_CREAT)) - return -ENOENT; - return newque(key, msgflg); + ret = -ENOENT; + else + ret = newque(key, msgflg); + } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { + ret = -EEXIST; + } else { + msq = msgque[id]; + if (msq == IPC_UNUSED || msq == IPC_NOID) + ret = -EIDRM; + else if (ipcperms(&msq->msg_perm, msgflg)) + ret = -EACCES; + else + ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id; } - if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) - return -EEXIST; - msq = msgque[id]; - if (msq == IPC_UNUSED || msq == IPC_NOID) - return -EIDRM; - if (ipcperms(&msq->msg_perm, msgflg)) - return -EACCES; - return (unsigned int) msq->msg_perm.seq * MSGMNI + id; +out: + unlock_kernel(); + return ret; } static void freeque (int id) @@ -537,18 +558,20 @@ static void freeque (int id) asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { - int id, err; + int id, err = -EINVAL; struct msqid_ds *msq; struct msqid_ds tbuf; struct ipc_perm *ipcp; + lock_kernel(); if (msqid < 0 || cmd < 0) - return -EINVAL; + goto out; + err = -EFAULT; switch (cmd) { case IPC_INFO: case MSG_INFO: if (!buf) - return -EFAULT; + goto out; { struct msginfo msginfo; msginfo.msgmni = MSGMNI; @@ -566,23 +589,26 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) } err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo)); if (err) - return err; + goto out; copy_to_user (buf, &msginfo, sizeof(struct msginfo)); - return max_msqid; + err = max_msqid; + goto out; } case MSG_STAT: if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (err) - return err; + goto out; + err = -EINVAL; if (msqid > max_msqid) - return -EINVAL; + goto out; msq = msgque[msqid]; if (msq == IPC_UNUSED || msq == IPC_NOID) - return -EINVAL; + goto out; + err = -EACCES; if (ipcperms (&msq->msg_perm, S_IRUGO)) - return -EACCES; + goto out; id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid; tbuf.msg_perm = msq->msg_perm; tbuf.msg_stime = msq->msg_stime; @@ -594,36 +620,40 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; copy_to_user (buf, &tbuf, sizeof(*buf)); - return id; + err = id; + goto out; case IPC_SET: if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_READ, buf, sizeof (*buf)); if (err) - return err; + goto out; copy_from_user (&tbuf, buf, sizeof (*buf)); break; case IPC_STAT: if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_WRITE, buf, sizeof(*buf)); if (err) - return err; + goto out; break; } id = (unsigned int) msqid % MSGMNI; msq = msgque [id]; + err = -EINVAL; if (msq == IPC_UNUSED || msq == IPC_NOID) - return -EINVAL; + goto out; + err = -EIDRM; if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) - return -EIDRM; + goto out; ipcp = &msq->msg_perm; switch (cmd) { case IPC_STAT: + err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) - return -EACCES; + goto out; tbuf.msg_perm = msq->msg_perm; tbuf.msg_stime = msq->msg_stime; tbuf.msg_rtime = msq->msg_rtime; @@ -634,24 +664,28 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; copy_to_user (buf, &tbuf, sizeof (*buf)); - return 0; + err = 0; + goto out; case IPC_SET: + err = -EPERM; if (!suser() && current->euid != ipcp->cuid && current->euid != ipcp->uid) - return -EPERM; + goto out; if (tbuf.msg_qbytes > MSGMNB && !suser()) - return -EPERM; + goto out; msq->msg_qbytes = tbuf.msg_qbytes; ipcp->uid = tbuf.msg_perm.uid; ipcp->gid = tbuf.msg_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (S_IRWXUGO & tbuf.msg_perm.mode); msq->msg_ctime = CURRENT_TIME; - return 0; + err = 0; + goto out; case IPC_RMID: + err = -EPERM; if (!suser() && current->euid != ipcp->cuid && current->euid != ipcp->uid) - return -EPERM; + goto out; /* * There is only one kerneld message queue, * mark it as non-existent @@ -659,10 +693,15 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid)) kerneld_msqid = -1; freeque (id); - return 0; + err = 0; + goto out; default: - return -EINVAL; + err = -EINVAL; + goto out; } +out: + unlock_kernel(); + return err; } /* diff --git a/ipc/sem.c b/ipc/sem.c index fb79d6004d34..8aecbfb48a4c 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include @@ -130,26 +132,33 @@ found: asmlinkage int sys_semget (key_t key, int nsems, int semflg) { - int id; + int id, err = -EINVAL; struct semid_ds *sma; + lock_kernel(); if (nsems < 0 || nsems > SEMMSL) - return -EINVAL; - if (key == IPC_PRIVATE) - return newary(key, nsems, semflg); - if ((id = findkey (key)) == -1) { /* key not used */ + goto out; + if (key == IPC_PRIVATE) { + err = newary(key, nsems, semflg); + } else if ((id = findkey (key)) == -1) { /* key not used */ if (!(semflg & IPC_CREAT)) - return -ENOENT; - return newary(key, nsems, semflg); + err = -ENOENT; + else + err = newary(key, nsems, semflg); + } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { + err = -EEXIST; + } else { + sma = semary[id]; + if (nsems > sma->sem_nsems) + err = -EINVAL; + else if (ipcperms(&sma->sem_perm, semflg)) + err = -EACCES; + else + err = (int) sma->sem_perm.seq * SEMMNI + id; } - if (semflg & IPC_CREAT && semflg & IPC_EXCL) - return -EEXIST; - sma = semary[id]; - if (nsems > sma->sem_nsems) - return -EINVAL; - if (ipcperms(&sma->sem_perm, semflg)) - return -EACCES; - return (unsigned int) sma->sem_perm.seq * SEMMNI + id; +out: + unlock_kernel(); + return err; } /* Manage the doubly linked list sma->sem_pending as a FIFO: @@ -368,9 +377,11 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) unsigned int nsems; ushort *array = NULL; ushort sem_io[SEMMSL]; + int err = -EINVAL; + lock_kernel(); if (semid < 0 || semnum < 0 || cmd < 0) - return -EINVAL; + goto out; switch (cmd) { case IPC_INFO: @@ -391,42 +402,48 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) seminfo.semusz = used_semids; seminfo.semaem = used_sems; } - i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); - if (i) - return i; + err = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); + if (err) + goto out; copy_to_user (tmp, &seminfo, sizeof(struct seminfo)); - return max_semid; + err = max_semid; + goto out; } case SEM_STAT: buf = arg.buf; - i = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); - if (i) - return i; + err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); + if (err) + goto out; + err = -EINVAL; if (semid > max_semid) - return -EINVAL; + goto out; sma = semary[semid]; if (sma == IPC_UNUSED || sma == IPC_NOID) - return -EINVAL; + goto out; + err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) - return -EACCES; + goto out; id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid; tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; copy_to_user (buf, &tbuf, sizeof(*buf)); - return id; + err = id; + goto out; } id = (unsigned int) semid % SEMMNI; sma = semary [id]; + err = -EINVAL; if (sma == IPC_UNUSED || sma == IPC_NOID) - return -EINVAL; + goto out; ipcp = &sma->sem_perm; nsems = sma->sem_nsems; + err = -EIDRM; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) - return -EIDRM; + goto out; switch (cmd) { case GETVAL: @@ -434,8 +451,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) case GETNCNT: case GETZCNT: case SETVAL: + err = -EINVAL; if (semnum >= nsems) - return -EINVAL; + goto out; curr = &sma->sem_base[semnum]; break; } @@ -446,8 +464,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) case GETNCNT: case GETZCNT: case GETALL: + err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) - return -EACCES; + goto out; switch (cmd) { case GETVAL : return curr->semval; case GETPID : return curr->sempid; @@ -455,60 +474,68 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) case GETZCNT: return count_semzcnt(sma,semnum); case GETALL: array = arg.array; - i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort)); - if (i) - return i; + err = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort)); + if (err) + goto out; } break; case SETVAL: val = arg.val; + err = -ERANGE; if (val > SEMVMX || val < 0) - return -ERANGE; + goto out; break; case IPC_RMID: if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { freeary (id); - return 0; + err = 0; + goto out; } - return -EPERM; + err = -EPERM; + goto out; case SETALL: /* arg is a pointer to an array of ushort */ array = arg.array; - if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort)))) - return i; + if ((err = verify_area (VERIFY_READ, array, nsems*sizeof(ushort)))) + goto out; copy_from_user (sem_io, array, nsems*sizeof(ushort)); for (i = 0; i < nsems; i++) - if (sem_io[i] > SEMVMX) - return -ERANGE; + if (sem_io[i] > SEMVMX) { + err = -ERANGE; + goto out; + } break; case IPC_STAT: buf = arg.buf; - if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf)))) - return i; + if ((err = verify_area (VERIFY_WRITE, buf, sizeof(*buf)))) + goto out; break; case IPC_SET: buf = arg.buf; - if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf)))) - return i; + if ((err = verify_area (VERIFY_READ, buf, sizeof (*buf)))) + goto out; copy_from_user (&tbuf, buf, sizeof (*buf)); break; } + err = -EIDRM; if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID) - return -EIDRM; + goto out; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) - return -EIDRM; + goto out; switch (cmd) { case GETALL: + err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) - return -EACCES; + goto out; for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; copy_to_user (array, sem_io, nsems*sizeof(ushort)); break; case SETVAL: + err = -EACCES; if (ipcperms (ipcp, S_IWUGO)) - return -EACCES; + goto out; for (un = sma->undo; un; un = un->id_next) un->semadj[semnum] = 0; curr->semval = val; @@ -523,12 +550,15 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (tbuf.sem_perm.mode & S_IRWXUGO); sma->sem_ctime = CURRENT_TIME; - return 0; + err = 0; + goto out; } - return -EPERM; + err = -EPERM; + goto out; case IPC_STAT: + err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) - return -EACCES; + goto out; tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; @@ -536,8 +566,9 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) copy_to_user (buf, &tbuf, sizeof(*buf)); break; case SETALL: + err = -EACCES; if (ipcperms (ipcp, S_IWUGO)) - return -EACCES; + goto out; for (i = 0; i < nsems; i++) sma->sem_base[i].semval = sem_io[i]; for (un = sma->undo; un; un = un->id_next) @@ -548,47 +579,58 @@ asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) update_queue(sma); break; default: - return -EINVAL; + err = -EINVAL; + goto out; } - return 0; + err = 0; +out: + unlock_kernel(); + return err; } asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) { - int i, id, size, error; + int i, id, size, error = -EINVAL; struct semid_ds *sma; struct sembuf sops[SEMOPM], *sop; struct sem_undo *un; int undos = 0, alter = 0; + lock_kernel(); if (nsops < 1 || semid < 0) - return -EINVAL; + goto out; + error = -E2BIG; if (nsops > SEMOPM) - return -E2BIG; + goto out; + error = -EFAULT; if (!tsops) - return -EFAULT; + goto out; if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops)))) - return i; + goto out; copy_from_user (sops, tsops, nsops * sizeof(*tsops)); id = (unsigned int) semid % SEMMNI; + error = -EINVAL; if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) - return -EINVAL; + goto out; + error = -EIDRM; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) - return -EIDRM; + goto out; for (i = 0; i < nsops; i++) { sop = &sops[i]; + error = -EFBIG; if (sop->sem_num >= sma->sem_nsems) - return -EFBIG; + goto out; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op) alter++; } + error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) - return -EACCES; + goto out; error = try_semop(sma, sops, nsops); if (error < 0) - return error; + goto out; if (undos) { /* Make sure we have an undo structure * for this process and this semaphore set. @@ -599,8 +641,10 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) if (!un) { size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems; un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC); - if (!un) - return -ENOMEM; + if (!un) { + error = -ENOMEM; + goto out; + } memset(un, 0, size); un->semadj = (short *) &un[1]; un->semid = semid; @@ -616,7 +660,7 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) error = do_semop(sma, sops, nsops, un, current->pid); /* maybe some queued-up processes were waiting for this */ update_queue(sma); - return error; + goto out; } else { /* We need to sleep on this operation, so we put the current * task into the pending queue and go to sleep. @@ -639,12 +683,15 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) */ if (!queue.prev) { /* operation is finished, update_queue() removed us */ - return queue.status; + error = queue.status; } else { remove_from_queue(sma,&queue); - return -EINTR; + error = -EINTR; } } +out: + unlock_kernel(); + return error; } /* diff --git a/ipc/shm.c b/ipc/shm.c index b23cdc501ab5..78c6b89d3aa6 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -8,11 +8,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -130,27 +133,33 @@ found: asmlinkage int sys_shmget (key_t key, int size, int shmflg) { struct shmid_ds *shp; - int id = 0; - - if (size < 0 || size > SHMMAX) - return -EINVAL; - if (key == IPC_PRIVATE) - return newseg(key, shmflg, size); - if ((id = findkey (key)) == -1) { + int err, id = 0; + + lock_kernel(); + if (size < 0 || size > SHMMAX) { + err = -EINVAL; + } else if (key == IPC_PRIVATE) { + err = newseg(key, shmflg, size); + } else if ((id = findkey (key)) == -1) { if (!(shmflg & IPC_CREAT)) - return -ENOENT; - return newseg(key, shmflg, size); + err = -ENOENT; + else + err = newseg(key, shmflg, size); + } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) { + err = -EEXIST; + } else { + shp = shm_segs[id]; + if (shp->shm_perm.mode & SHM_DEST) + err = -EIDRM; + else if (size > shp->shm_segsz) + err = -EINVAL; + else if (ipcperms (&shp->shm_perm, shmflg)) + err = -EACCES; + else + err = (int) shp->shm_perm.seq * SHMMNI + id; } - if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) - return -EEXIST; - shp = shm_segs[id]; - if (shp->shm_perm.mode & SHM_DEST) - return -EIDRM; - if (size > shp->shm_segsz) - return -EINVAL; - if (ipcperms (&shp->shm_perm, shmflg)) - return -EACCES; - return (unsigned int) shp->shm_perm.seq * SHMMNI + id; + unlock_kernel(); + return err; } /* @@ -202,16 +211,18 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) struct shmid_ds tbuf; struct shmid_ds *shp; struct ipc_perm *ipcp; - int id, err; + int id, err = -EINVAL; + lock_kernel(); if (cmd < 0 || shmid < 0) - return -EINVAL; + goto out; if (cmd == IPC_SET) { + err = -EFAULT; if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_READ, buf, sizeof (*buf)); if (err) - return err; + goto out; copy_from_user (&tbuf, buf, sizeof (*buf)); } @@ -219,8 +230,9 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) case IPC_INFO: { struct shminfo shminfo; + err = -EFAULT; if (!buf) - return -EFAULT; + goto out; shminfo.shmmni = SHMMNI; shminfo.shmmax = SHMMAX; shminfo.shmmin = SHMMIN; @@ -228,18 +240,20 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) shminfo.shmseg = SHMSEG; err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo)); if (err) - return err; + goto out; copy_to_user (buf, &shminfo, sizeof(struct shminfo)); - return max_shmid; + err = max_shmid; + goto out; } case SHM_INFO: { struct shm_info shm_info; + err = -EFAULT; if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info)); if (err) - return err; + goto out; shm_info.used_ids = used_segs; shm_info.shm_rss = shm_rss; shm_info.shm_tot = shm_tot; @@ -247,21 +261,24 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) shm_info.swap_attempts = swap_attempts; shm_info.swap_successes = swap_successes; copy_to_user (buf, &shm_info, sizeof(shm_info)); - return max_shmid; + err = max_shmid; + goto out; } case SHM_STAT: + err = -EFAULT; if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (err) - return err; + goto out; + err = -EINVAL; if (shmid > max_shmid) - return -EINVAL; + goto out; shp = shm_segs[shmid]; if (shp == IPC_UNUSED || shp == IPC_NOID) - return -EINVAL; + goto out; if (ipcperms (&shp->shm_perm, S_IRUGO)) - return -EACCES; + goto out; id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid; tbuf.shm_perm = shp->shm_perm; tbuf.shm_segsz = shp->shm_segsz; @@ -272,42 +289,51 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) tbuf.shm_lpid = shp->shm_lpid; tbuf.shm_nattch = shp->shm_nattch; copy_to_user (buf, &tbuf, sizeof(*buf)); - return id; + err = id; + goto out; } shp = shm_segs[id = (unsigned int) shmid % SHMMNI]; + err = -EINVAL; if (shp == IPC_UNUSED || shp == IPC_NOID) - return -EINVAL; + goto out; + err = -EIDRM; if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI) - return -EIDRM; + goto out; ipcp = &shp->shm_perm; switch (cmd) { case SHM_UNLOCK: + err = -EPERM; if (!suser()) - return -EPERM; + goto out; + err = -EINVAL; if (!(ipcp->mode & SHM_LOCKED)) - return -EINVAL; + goto out; ipcp->mode &= ~SHM_LOCKED; break; case SHM_LOCK: /* Allow superuser to lock segment in memory */ /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ + err = -EPERM; if (!suser()) - return -EPERM; + goto out; + err = -EINVAL; if (ipcp->mode & SHM_LOCKED) - return -EINVAL; + goto out; ipcp->mode |= SHM_LOCKED; break; case IPC_STAT: + err = -EACCES; if (ipcperms (ipcp, S_IRUGO)) - return -EACCES; + goto out; + err = -EFAULT; if (!buf) - return -EFAULT; + goto out; err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (err) - return err; + goto out; tbuf.shm_perm = shp->shm_perm; tbuf.shm_segsz = shp->shm_segsz; tbuf.shm_atime = shp->shm_atime; @@ -328,7 +354,8 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) shp->shm_ctime = CURRENT_TIME; break; } - return -EPERM; + err = -EPERM; + goto out; case IPC_RMID: if (suser() || current->euid == shp->shm_perm.uid || current->euid == shp->shm_perm.cuid) { @@ -337,11 +364,16 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) killseg (id); break; } - return -EPERM; + err = -EPERM; + goto out; default: - return -EINVAL; + err = -EINVAL; + goto out; } - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -465,39 +497,42 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) { struct shmid_ds *shp; struct vm_area_struct *shmd; - int err; + int err = -EINVAL; unsigned int id; unsigned long addr; unsigned long len; + lock_kernel(); if (shmid < 0) { /* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */ - return -EINVAL; + goto out; } shp = shm_segs[id = (unsigned int) shmid % SHMMNI]; if (shp == IPC_UNUSED || shp == IPC_NOID) { /* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */ - return -EINVAL; + goto out; } if (!(addr = (ulong) shmaddr)) { if (shmflg & SHM_REMAP) - return -EINVAL; + goto out; + err = -ENOMEM; if (!(addr = get_unmapped_area(0, shp->shm_segsz))) - return -ENOMEM; + goto out; } else if (addr & (SHMLBA-1)) { if (shmflg & SHM_RND) addr &= ~(SHMLBA-1); /* round down */ else - return -EINVAL; + goto out; } /* * Check if addr exceeds TASK_SIZE (from do_mmap) */ len = PAGE_SIZE*shp->shm_npages; - if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len) - return -EINVAL; + err = -EINVAL; + if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len) + goto out; /* * If shm segment goes below stack, make sure there is some * space left for the stack to grow (presently 4 pages). @@ -506,26 +541,30 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4)) { /* printk("shmat() -> EINVAL because segment intersects stack\n"); */ - return -EINVAL; + goto out; } if (!(shmflg & SHM_REMAP)) if ((shmd = find_vma_intersection(current->mm, addr, addr + shp->shm_segsz))) { /* printk("shmat() -> EINVAL because the interval [0x%lx,0x%lx) intersects an already mapped interval [0x%lx,0x%lx).\n", addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */ - return -EINVAL; + goto out; } + err = -EACCES; if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO)) - return -EACCES; + goto out; + err = -EIDRM; if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI) - return -EIDRM; + goto out; - shmd = (struct vm_area_struct *) kmalloc (sizeof(*shmd), GFP_KERNEL); + err = -ENOMEM; + shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!shmd) - return -ENOMEM; + goto out; if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) { - kfree(shmd); - return -EIDRM; + kmem_cache_free(vm_area_cachep, shmd); + err = -EIDRM; + goto out; } shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id); @@ -545,8 +584,8 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) if ((err = shm_map (shmd))) { if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST) killseg(id); - kfree(shmd); - return err; + kmem_cache_free(vm_area_cachep, shmd); + goto out; } insert_attach(shp,shmd); /* insert shmd into shp->attaches */ @@ -555,7 +594,10 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) shp->shm_atime = CURRENT_TIME; *raddr = addr; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* This is called by fork, once for every shm attach. */ diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c index 9a202359a69e..5d7e2f056c9c 100644 --- a/kernel/exec_domain.c +++ b/kernel/exec_domain.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include static asmlinkage void no_lcall7(struct pt_regs * regs); @@ -34,14 +37,14 @@ static asmlinkage void no_lcall7(struct pt_regs * regs) * personality set incorrectly. Check to see whether SVr4 is available, * and use it, otherwise give the user a SEGV. */ - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); current->personality = PER_SVR4; current->exec_domain = lookup_exec_domain(current->personality); - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)++; + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); if (current->exec_domain && current->exec_domain->handler && current->exec_domain->handler != no_lcall7) { @@ -103,21 +106,27 @@ asmlinkage int sys_personality(unsigned long personality) { struct exec_domain *it; unsigned long old_personality; + int ret; + lock_kernel(); + ret = current->personality; if (personality == 0xffffffff) - return current->personality; + goto out; + ret = -EINVAL; it = lookup_exec_domain(personality); if (!it) - return -EINVAL; + goto out; old_personality = current->personality; - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); current->personality = personality; current->exec_domain = it; - if (current->exec_domain->use_count) - (*current->exec_domain->use_count)++; - - return old_personality; + if (current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + ret = old_personality; +out: + unlock_kernel(); + return ret; } diff --git a/kernel/exit.c b/kernel/exit.c index 13a09a8765c7..0a78e836d393 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -6,6 +6,7 @@ #undef DEBUG_PROC_TREE +#include #include #include #include @@ -16,6 +17,9 @@ #include #include #include +#include +#include +#include #include #include @@ -69,7 +73,7 @@ void force_sig(unsigned long sig, struct task_struct * p) wake_up_process(p); } } - + int send_sig(unsigned long sig,struct task_struct * p,int priv) { @@ -131,7 +135,7 @@ void release(struct task_struct * p) current->cmin_flt += p->min_flt + p->cmin_flt; current->cmaj_flt += p->maj_flt + p->cmaj_flt; current->cnswap += p->nswap + p->cnswap; - kfree(p); + free_task_struct(p); return; } panic("trying to release non-existent task"); @@ -153,14 +157,14 @@ int bad_task_ptr(struct task_struct *p) return 0; return 1; } - + /* * This routine scans the pid tree and makes sure the rep invariant still * holds. Used for debugging only, since it's very slow.... * * It looks a lot scarier than it really is.... we're doing nothing more - * than verifying the doubly-linked list found in p_ysptr and p_osptr, - * and checking it corresponds with the process tree defined by p_cptr and + * than verifying the doubly-linked list found in p_ysptr and p_osptr, + * and checking it corresponds with the process tree defined by p_cptr and * p_pptr; */ void audit_ptree(void) @@ -320,8 +324,11 @@ asmlinkage int sys_kill(int pid,int sig) { int err, retval = 0, count = 0; - if (!pid) - return(kill_pg(current->pgrp,sig,0)); + lock_kernel(); + if (!pid) { + err = kill_pg(current->pgrp,sig,0); + goto out; + } if (pid == -1) { struct task_struct * p; for_each_task(p) { @@ -331,20 +338,26 @@ asmlinkage int sys_kill(int pid,int sig) retval = err; } } - return(count ? retval : -ESRCH); + err = count ? retval : -ESRCH; + goto out; + } + if (pid < 0) { + err = kill_pg(-pid,sig,0); + goto out; } - if (pid < 0) - return(kill_pg(-pid,sig,0)); /* Normal kill */ - return(kill_proc(pid,sig,0)); + err = kill_proc(pid,sig,0); +out: + unlock_kernel(); + return err; } /* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected - * by terminal-generated stop signals. Newly orphaned process groups are + * by terminal-generated stop signals. Newly orphaned process groups are * to receive a SIGHUP and a SIGCONT. - * + * * "I ask you, have you ever known what it is to be an orphan?" */ static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) @@ -352,7 +365,7 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task struct task_struct *p; for_each_task(p) { - if ((p == ignored_task) || (p->pgrp != pgrp) || + if ((p == ignored_task) || (p->pgrp != pgrp) || (p->state == TASK_ZOMBIE) || (p->p_pptr->pid == 1)) continue; @@ -495,7 +508,7 @@ void exit_mm(struct task_struct *tsk) __exit_mm(tsk); } -/* +/* * Send signals to all our closest relatives so that they know * to properly mourn us.. */ @@ -504,7 +517,7 @@ static void exit_notify(void) struct task_struct * p; forget_original_parent(current); - /* + /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) @@ -522,10 +535,10 @@ static void exit_notify(void) } /* Let father know we died */ notify_parent(current); - + /* * This loop does two things: - * + * * A. Make init inherit all the child processes * B. Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped @@ -546,7 +559,7 @@ static void exit_notify(void) notify_parent(p); /* * process group orphan check - * Case ii: Our child is in a different pgrp + * Case ii: Our child is in a different pgrp * than we are, and it was the only connection * outside, so the child pgrp is now orphaned. */ @@ -575,6 +588,9 @@ fake_volatile: sem_exit(); kerneld_exit(); __exit_mm(current); +#if CONFIG_AP1000 + exit_msc(current); +#endif __exit_files(current); __exit_fs(current); __exit_sighand(current); @@ -585,10 +601,10 @@ fake_volatile: #ifdef DEBUG_PROC_TREE audit_ptree(); #endif - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); schedule(); /* * In order to get rid of the "volatile function does return" message @@ -608,7 +624,9 @@ fake_volatile: asmlinkage int sys_exit(int error_code) { + lock_kernel(); do_exit((error_code&0xff)<<8); + unlock_kernel(); } asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) @@ -617,18 +635,20 @@ asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct struct wait_queue wait = { current, NULL }; struct task_struct *p; + lock_kernel(); if (stat_addr) { - flag = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr)); - if (flag) - return flag; + retval = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr)); + if (retval) + goto out; } if (ru) { - flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru)); - if (flag) - return flag; + retval = verify_area(VERIFY_WRITE, ru, sizeof(*ru)); + if (retval) + goto out; } + retval = -EINVAL; if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) - return -EINVAL; + goto out; add_wait_queue(¤t->wait_chldexit,&wait); repeat: @@ -699,6 +719,8 @@ repeat: retval = -ECHILD; end_wait4: remove_wait_queue(¤t->wait_chldexit,&wait); +out: + unlock_kernel(); return retval; } @@ -710,7 +732,12 @@ end_wait4: */ asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options) { - return sys_wait4(pid, stat_addr, options, NULL); + int ret; + + lock_kernel(); + ret = sys_wait4(pid, stat_addr, options, NULL); + unlock_kernel(); + return ret; } #endif diff --git a/kernel/fork.c b/kernel/fork.c index 7ce05ee75304..0beead0f7dd1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -15,10 +15,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -84,7 +87,7 @@ static inline int dup_mmap(struct mm_struct * mm) p = &mm->mmap; flush_cache_mm(current->mm); for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { - tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) { exit_mmap(mm); flush_tlb_mm(current->mm); @@ -177,7 +180,7 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk tsk->files = newf; if (!newf) return -1; - + newf->count = 1; newf->close_on_exec = oldf->close_on_exec; newf->open_fds = oldf->open_fds; @@ -221,10 +224,11 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) unsigned long new_stack; struct task_struct *p; - p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL); + lock_kernel(); + p = alloc_task_struct(); if (!p) goto bad_fork; - new_stack = alloc_kernel_stack(); + new_stack = alloc_kernel_stack(p); if (!new_stack) goto bad_fork_free_p; error = -EAGAIN; @@ -234,10 +238,10 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) *p = *current; - if (p->exec_domain && p->exec_domain->use_count) - (*p->exec_domain->use_count)++; - if (p->binfmt && p->binfmt->use_count) - (*p->binfmt->use_count)++; + if (p->exec_domain && p->exec_domain->module) + __MOD_INC_USE_COUNT(p->exec_domain->module); + if (p->binfmt && p->binfmt->module) + __MOD_INC_USE_COUNT(p->binfmt->module); p->did_exec = 0; p->swappable = 0; @@ -263,8 +267,8 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) p->cutime = p->cstime = 0; #ifdef __SMP__ p->processor = NO_PROC_ID; - p->lock_depth = 1; #endif + p->lock_depth = 0; p->start_time = jiffies; task[nr] = p; SET_LINKS(p); @@ -289,9 +293,15 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) p->swappable = 1; p->exit_signal = clone_flags & CSIGNAL; p->counter = current->counter >> 1; - wake_up_process(p); /* do this last, just in case */ + if(p->pid) { + wake_up_process(p); /* do this last, just in case */ + } else { + p->state = TASK_RUNNING; + p->next_run = p->prev_run = p; + } ++total_forks; - return p->pid; + error = p->pid; + goto fork_out; bad_fork_cleanup_sighand: exit_sighand(p); @@ -300,17 +310,19 @@ bad_fork_cleanup_fs: bad_fork_cleanup_files: exit_files(p); bad_fork_cleanup: - if (p->exec_domain && p->exec_domain->use_count) - (*p->exec_domain->use_count)--; - if (p->binfmt && p->binfmt->use_count) - (*p->binfmt->use_count)--; + if (p->exec_domain && p->exec_domain->module) + __MOD_DEC_USE_COUNT(p->exec_domain->module); + if (p->binfmt && p->binfmt->module) + __MOD_DEC_USE_COUNT(p->binfmt->module); task[nr] = NULL; REMOVE_LINKS(p); nr_tasks--; bad_fork_free_stack: free_kernel_stack(new_stack); bad_fork_free_p: - kfree(p); + free_task_struct(p); bad_fork: +fork_out: + unlock_kernel(); return error; } diff --git a/kernel/info.c b/kernel/info.c index 20b6ad6aee22..065bff7d3b04 100644 --- a/kernel/info.c +++ b/kernel/info.c @@ -12,13 +12,17 @@ #include #include #include +#include +#include #include asmlinkage int sys_sysinfo(struct sysinfo *info) { struct sysinfo val; + int err; + lock_kernel(); memset((char *)&val, 0, sizeof(struct sysinfo)); val.uptime = jiffies / HZ; @@ -33,6 +37,9 @@ asmlinkage int sys_sysinfo(struct sysinfo *info) si_swapinfo(&val); if (copy_to_user(info, &val, sizeof(struct sysinfo))) - return -EFAULT; - return 0; + err = -EFAULT; + else + err = 0; + unlock_kernel(); + return err; } diff --git a/kernel/itimer.c b/kernel/itimer.c index efcc8351b75f..a4332afbecf7 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include @@ -80,15 +82,19 @@ static int _getitimer(int which, struct itimerval *value) asmlinkage int sys_getitimer(int which, struct itimerval *value) { - int error; + int error = -EFAULT; struct itimerval get_buffer; + lock_kernel(); if (!value) - return -EFAULT; + goto out; error = _getitimer(which, &get_buffer); if (error) - return error; - return copy_to_user(value, &get_buffer, sizeof(get_buffer)) ? -EFAULT : 0; + goto out; + error = copy_to_user(value, &get_buffer, sizeof(get_buffer)) ? -EFAULT : 0; +out: + unlock_kernel(); + return error; } void it_real_fn(unsigned long __data) @@ -154,21 +160,26 @@ asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerva int error; struct itimerval set_buffer, get_buffer; + lock_kernel(); if (value) { error = verify_area(VERIFY_READ, value, sizeof(*value)); if (error) - return error; + goto out; error = copy_from_user(&set_buffer, value, sizeof(set_buffer)); - if (error) - return -EFAULT; + if (error) { + error = -EFAULT; + goto out; + } } else memset((char *) &set_buffer, 0, sizeof(set_buffer)); error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); if (error || !ovalue) - return error; + goto out; if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer))) error = -EFAULT; +out: + unlock_kernel(); return error; } diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 1a7514d9cd6a..c13d728fb2ff 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -50,11 +49,12 @@ #include #include -extern unsigned char aux_device_present, kbd_read_mask; -#ifdef __i386__ +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) extern struct drive_info_struct drive_info; #endif +extern unsigned char aux_device_present, kbd_read_mask; + #ifdef CONFIG_PCI #include #include @@ -181,7 +181,7 @@ EXPORT_SYMBOL(register_cdrom); EXPORT_SYMBOL(unregister_cdrom); EXPORT_SYMBOL(cdrom_fops); #endif - + /* block device driver support */ EXPORT_SYMBOL(block_read); EXPORT_SYMBOL(block_write); @@ -201,7 +201,8 @@ EXPORT_SYMBOL(blkdev_release); EXPORT_SYMBOL(gendisk_head); EXPORT_SYMBOL(resetup_one_dev); EXPORT_SYMBOL(unplug_device); -#ifdef __i386__ + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) EXPORT_SYMBOL(drive_info); #endif diff --git a/kernel/module.c b/kernel/module.c index 53a94d1907c8..fd2b74ac7294 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include /* * Originally by Anonymous (as far as I know...) @@ -118,6 +120,7 @@ sys_create_module(const char *name_user, size_t size) long namelen, error; struct module *mod; + lock_kernel(); if (!suser()) { error = -EPERM; goto err0; @@ -150,11 +153,12 @@ sys_create_module(const char *name_user, size_t size) module_list = mod; /* link it in */ - return (unsigned long) mod; - + error = (long) mod; + goto err0; err1: put_mod_name(name); err0: + unlock_kernel(); return error; } @@ -167,14 +171,13 @@ sys_init_module(const char *name_user, struct module *mod_user) { struct module mod_tmp, *mod; char *name, *n_name; - long namelen, n_namelen, i, error; + long namelen, n_namelen, i, error = -EPERM; unsigned long mod_user_size; struct module_ref *dep; - if (!suser()) { - error = -EPERM; + lock_kernel(); + if (!suser()) goto err0; - } if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; goto err0; @@ -184,14 +187,13 @@ sys_init_module(const char *name_user, struct module *mod_user) goto err1; } - /* Check for legal module header sizes. */ + /* Check module header size. We allow a bit of slop over the + size we are familiar with to cope with a version of insmod + for a newer kernel. But don't over do it. */ if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0) goto err1; - switch (mod_user_size) { - case sizeof(struct module): - case &((struct module *)0L)->persist_start: - break; - default: + if (mod_user_size < (unsigned long)&((struct module *)0L)->persist_start + || mod_user_size > sizeof(struct module) + 16*sizeof(void*)) { printk(KERN_ERR "init_module: Invalid module header size.\n" KERN_ERR "A new version of the modutils is likely " "needed.\n"); @@ -264,6 +266,11 @@ sys_init_module(const char *name_user, struct module *mod_user) goto err2; } #endif + if (mod_member_present(mod, can_unload) + && mod->can_unload && !bound(mod->can_unload, 0, mod)) { + printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n"); + goto err2; + } #undef bound @@ -279,14 +286,12 @@ sys_init_module(const char *name_user, struct module *mod_user) printk(KERN_ERR "init_module: changed module name to " "`%s' from `%s'\n", n_name, mod_tmp.name); - error = -EINVAL; goto err3; } /* Ok, that's about all the sanity we can stomach; copy the rest. */ - error = copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod)); - if (error) { + if (copy_from_user(mod+1, mod_user+1, mod->size-sizeof(*mod))) { error = -EFAULT; goto err3; } @@ -301,7 +306,6 @@ sys_init_module(const char *name_user, struct module *mod_user) if (d == mod) { printk(KERN_ERR "init_module: self-referential " "dependancy in mod->deps.\n"); - error = -EINVAL; goto err3; } @@ -310,13 +314,15 @@ sys_init_module(const char *name_user, struct module *mod_user) printk(KERN_ERR "init_module: found dependancy that is " "(no longer?) a module.\n"); - error = -EINVAL; goto err3; found_dep: dep->ref = mod; dep->next_ref = d->refs; d->refs = dep; + /* Being referenced by a dependant module counts as a + use as far as kerneld is concerned. */ + d->flags |= MOD_USED_ONCE; } /* Free our temporary memory. */ @@ -327,13 +333,15 @@ sys_init_module(const char *name_user, struct module *mod_user) mod->usecount = 1; if (mod->init && mod->init() != 0) { mod->usecount = 0; - return -EBUSY; + error = -EBUSY; + goto err0; } mod->usecount--; /* And set it running. */ mod->flags |= MOD_RUNNING; - return 0; + error = 0; + goto err0; err3: put_mod_name(n_name); @@ -342,6 +350,7 @@ err2: err1: put_mod_name(name); err0: + unlock_kernel(); return error; } @@ -350,45 +359,53 @@ sys_delete_module(const char *name_user) { struct module *mod, *next; char *name; - long error; + long error = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; if (name_user) { if ((error = get_mod_name(name_user, &name)) < 0) - return error; + goto out; if (error == 0) { + error = -EINVAL; put_mod_name(name); - return -EINVAL; + goto out; } + error = -ENOENT; if ((mod = find_module(name)) == NULL) { put_mod_name(name); - return -ENOENT; + goto out; } put_mod_name(name); - if (mod->refs != NULL || mod->usecount != 0) - return -EBUSY; + error = -EBUSY; + if (mod->refs != NULL || __MOD_IN_USE(mod)) + goto out; free_module(mod); - return 0; + error = 0; + goto out; } /* Do automatic reaping */ for (mod = module_list; mod != &kernel_module; mod = next) { next = mod->next; if (mod->refs == NULL && - mod->usecount == 0 && ((mod->flags & (MOD_AUTOCLEAN|MOD_RUNNING|MOD_DELETED|MOD_USED_ONCE)) - == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE))) { + == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE)) && + !__MOD_IN_USE(mod)) { if (mod->flags & MOD_VISITED) mod->flags &= ~MOD_VISITED; else free_module(mod); } } - return 0; + error = 0; +out: + unlock_kernel(); + return error; } /* Query various bits about modules. */ @@ -418,7 +435,8 @@ qm_modules(char *buf, size_t bufsize, size_t *ret) return 0; calc_space_needed: - for (space += len; mod; mod = mod->next) + space += len; + while ((mod = mod->next) != &kernel_module) space += strlen(mod->name)+1; if (put_user(space, ret)) @@ -460,7 +478,8 @@ qm_deps(struct module *mod, char *buf, size_t bufsize, size_t *ret) return 0; calc_space_needed: - for (space += len; i < mod->ndeps; ++i) + space += len; + while (++i < mod->ndeps) space += strlen(mod->deps[i].dep->name)+1; if (put_user(space, ret)) @@ -503,7 +522,8 @@ qm_refs(struct module *mod, char *buf, size_t bufsize, size_t *ret) return 0; calc_space_needed: - for (space += len; ref; ref = ref->next_ref) + space += len; + while ((ref = ref->next_ref) != NULL) space += strlen(ref->ref->name)+1; if (put_user(space, ret)) @@ -528,15 +548,15 @@ qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret) space = mod->nsyms * 2*sizeof(void *); - if (!access_ok(VERIFY_WRITE, buf, space)) - return -EFAULT; - i = len = 0; s = mod->syms; if (space > bufsize) goto calc_space_needed; + if (!access_ok(VERIFY_WRITE, buf, space)) + return -EFAULT; + bufsize -= space; vals = (unsigned long *)buf; strings = buf+space; @@ -562,8 +582,8 @@ qm_symbols(struct module *mod, char *buf, size_t bufsize, size_t *ret) return 0; calc_space_needed: - for (space += len; i < mod->nsyms; ++i, ++s) - space += strlen(s->name)+1; + for (; i < mod->nsyms; ++i, ++s) + space += strlen((++s)->name)+1; if (put_user(space, ret)) return -EFAULT; @@ -584,6 +604,8 @@ qm_info(struct module *mod, char *buf, size_t bufsize, size_t *ret) info.addr = (unsigned long)mod; info.size = mod->size; info.flags = mod->flags; + info.usecount = (mod_member_present(mod, can_unload) + && mod->can_unload ? -1 : mod->usecount); if (copy_to_user(buf, &info, sizeof(struct module_info))) return -EFAULT; @@ -601,20 +623,25 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret) { struct module *mod; + int err; + lock_kernel(); if (name_user == NULL) mod = &kernel_module; else { long namelen; char *name; - if ((namelen = get_mod_name(name_user, &name)) < 0) - return namelen; + if ((namelen = get_mod_name(name_user, &name)) < 0) { + err = namelen; + goto out; + } + err = -ENOENT; if (namelen == 0) mod = &kernel_module; else if ((mod = find_module(name)) == NULL) { put_mod_name(name); - return -ENOENT; + goto out; } put_mod_name(name); } @@ -622,28 +649,38 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, switch (which) { case 0: - return 0; + err = 0; + break; case QM_MODULES: - return qm_modules(buf, bufsize, ret); + err = qm_modules(buf, bufsize, ret); + break; case QM_DEPS: - return qm_deps(mod, buf, bufsize, ret); + err = qm_deps(mod, buf, bufsize, ret); + break; case QM_REFS: - return qm_refs(mod, buf, bufsize, ret); + err = qm_refs(mod, buf, bufsize, ret); + break; case QM_SYMBOLS: - return qm_symbols(mod, buf, bufsize, ret); + err = qm_symbols(mod, buf, bufsize, ret); + break; case QM_INFO: - return qm_info(mod, buf, bufsize, ret); + err = qm_info(mod, buf, bufsize, ret); + break; + default: + err = -EINVAL; + break; } - - return -EINVAL; +out: + unlock_kernel(); + return err; } /* * Copy the kernel symbol table to user space. If the argument is * NULL, just return the size of the table. * - * This call is depreciated in favour of query_module+QM_SYMBOLS which - * does not arbitrarily limit the length of the symbol. + * This call is obsolete. New programs should use query_module+QM_SYMBOLS + * which does not arbitrarily limit the length of symbols. */ asmlinkage int @@ -652,13 +689,14 @@ sys_get_kernel_syms(struct kernel_sym *table) struct module *mod; int i; + lock_kernel(); for (mod = module_list, i = 0; mod; mod = mod->next) { /* include the count for the module name! */ i += mod->nsyms + 1; } if (table == NULL) - return i; + goto out; for (mod = module_list, i = 0; mod; mod = mod->next) { struct kernel_sym ksym; @@ -675,7 +713,7 @@ sys_get_kernel_syms(struct kernel_sym *table) ksym.name[sizeof(ksym.name)-1] = '\0'; if (copy_to_user(table, &ksym, sizeof(ksym)) != 0) - return i; + goto out; ++i, ++table; if (mod->nsyms == 0) @@ -687,10 +725,12 @@ sys_get_kernel_syms(struct kernel_sym *table) ksym.name[sizeof(ksym.name)-1] = '\0'; if (copy_to_user(table, &ksym, sizeof(ksym)) != 0) - return i; + goto out; ++i, ++table; } } +out: + unlock_kernel(); return i; } @@ -771,15 +811,16 @@ int get_module_list(char *p) long len; const char *q; -#define safe_copystr(str, len) \ +#define safe_copy_str(str, len) \ do { \ if (left < len) \ goto fini; \ memcpy(p, str, len); p += len, left -= len; \ } while (0) +#define safe_copy_cstr(str) safe_copy_str(str, sizeof(str)-1) len = strlen(mod->name); - safe_copystr(mod->name, len); + safe_copy_str(mod->name, len); if ((len = 20 - len) > 0) { if (left < len) @@ -790,47 +831,45 @@ int get_module_list(char *p) } len = sprintf(tmpstr, "%8lu", mod->size); - safe_copystr(tmpstr, len); + safe_copy_str(tmpstr, len); if (mod->flags & MOD_RUNNING) { - len = sprintf(tmpstr, "%4lu", mod->usecount); - safe_copystr(tmpstr, len); + len = sprintf(tmpstr, "%4ld", + (mod_member_present(mod, can_unload) + && mod->can_unload + ? -1 : mod->usecount)); + safe_copy_str(tmpstr, len); } if (mod->flags & MOD_DELETED) - q = " (deleted)"; - else if (mod->flags & MOD_RUNNING) - q = ""; - else - q = " (uninitialized)"; - len = strlen(q); - safe_copystr(q, len); - - safe_copystr("\t", 1); + safe_copy_cstr(" (deleted)"); + else if (mod->flags & MOD_RUNNING) { + if (mod->flags & MOD_AUTOCLEAN) + safe_copy_cstr(" (autoclean)"); + if (!(mod->flags & MOD_USED_ONCE)) + safe_copy_cstr(" (unused)"); + } else + safe_copy_cstr(" (uninitialized)"); if ((ref = mod->refs) != NULL) { - safe_copystr("[", 1); + safe_copy_cstr(" ["); while (1) { q = ref->ref->name; len = strlen(q); - safe_copystr(q, len); + safe_copy_str(q, len); if ((ref = ref->next_ref) != NULL) - safe_copystr(" ", 1); + safe_copy_cstr(" "); else break; } - safe_copystr("]", 1); - } - - if ((mod->flags & (MOD_RUNNING | MOD_AUTOCLEAN)) - == (MOD_RUNNING | MOD_AUTOCLEAN)) { - safe_copystr(" (autoclean)", 12); + safe_copy_cstr("]"); } - safe_copystr("\n", 1); + safe_copy_cstr("\n"); -#undef safe_copystr +#undef safe_copy_str +#undef safe_copy_cstr } fini: diff --git a/kernel/printk.c b/kernel/printk.c index ff8cd212cc51..b0ea9c521683 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -64,87 +66,103 @@ asmlinkage int sys_syslog(int type, char * buf, int len) unsigned long i, j, count; int do_clear = 0; char c; - int error; + int error = -EPERM; + lock_kernel(); if ((type != 3) && !suser()) - return -EPERM; + goto out; + error = 0; switch (type) { - case 0: /* Close log */ - return 0; - case 1: /* Open log */ - return 0; - case 2: /* Read from log */ - if (!buf || len < 0) - return -EINVAL; - if (!len) - return 0; - error = verify_area(VERIFY_WRITE,buf,len); - if (error) - return error; - cli(); - while (!log_size) { - if (current->signal & ~current->blocked) { - sti(); - return -ERESTARTSYS; - } - interruptible_sleep_on(&log_wait); - } - i = 0; - while (log_size && i < len) { - c = *((char *) log_buf+log_start); - log_start++; - log_size--; - log_start &= LOG_BUF_LEN-1; + case 0: /* Close log */ + break; + case 1: /* Open log */ + break; + case 2: /* Read from log */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + goto out; + cli(); + error = -ERESTARTSYS; + while (!log_size) { + if (current->signal & ~current->blocked) { sti(); - put_user(c,buf); - buf++; - i++; - cli(); + goto out; } + interruptible_sleep_on(&log_wait); + } + i = 0; + while (log_size && i < len) { + c = *((char *) log_buf+log_start); + log_start++; + log_size--; + log_start &= LOG_BUF_LEN-1; sti(); - return i; - case 4: /* Read/clear last kernel messages */ - do_clear = 1; - /* FALL THRU */ - case 3: /* Read last kernel messages */ - if (!buf || len < 0) - return -EINVAL; - if (!len) - return 0; - error = verify_area(VERIFY_WRITE,buf,len); - if (error) - return error; - count = len; - if (count > LOG_BUF_LEN) - count = LOG_BUF_LEN; - if (count > logged_chars) - count = logged_chars; - j = log_start + log_size - count; - for (i = 0; i < count; i++) { - c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); - put_user(c, buf++); - } - if (do_clear) - logged_chars = 0; - return i; - case 5: /* Clear ring buffer */ + put_user(c,buf); + buf++; + i++; + cli(); + } + sti(); + error = i; + break; + case 4: /* Read/clear last kernel messages */ + do_clear = 1; + /* FALL THRU */ + case 3: /* Read last kernel messages */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + goto out; + count = len; + if (count > LOG_BUF_LEN) + count = LOG_BUF_LEN; + if (count > logged_chars) + count = logged_chars; + j = log_start + log_size - count; + for (i = 0; i < count; i++) { + c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); + put_user(c, buf++); + } + if (do_clear) logged_chars = 0; - return 0; - case 6: /* Disable logging to console */ - console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; - return 0; - case 7: /* Enable logging to console */ - console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; - return 0; - case 8: - if (len < 1 || len > 8) - return -EINVAL; - if (len < MINIMUM_CONSOLE_LOGLEVEL) - len = MINIMUM_CONSOLE_LOGLEVEL; - console_loglevel = len; - return 0; + error = i; + break; + case 5: /* Clear ring buffer */ + logged_chars = 0; + break; + case 6: /* Disable logging to console */ + console_loglevel = MINIMUM_CONSOLE_LOGLEVEL; + break; + case 7: /* Enable logging to console */ + console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; + break; + case 8: + error = -EINVAL; + if (len < 1 || len > 8) + goto out; + if (len < MINIMUM_CONSOLE_LOGLEVEL) + len = MINIMUM_CONSOLE_LOGLEVEL; + console_loglevel = len; + error = 0; + break; + default: + error = -EINVAL; + break; } - return -EINVAL; +out: + unlock_kernel(); + return error; } diff --git a/kernel/resource.c b/kernel/resource.c index 48184bfcf677..09ba07bb18a7 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -119,6 +119,67 @@ int check_region(unsigned int from, unsigned int num) return (find_gap(&iolist, from, num) == NULL) ? -EBUSY : 0; } +#ifdef __sparc__ /* Why to carry unused code on other architectures? */ +/* + * This is for architectures with MMU-managed ports (sparc). + */ +unsigned int occupy_region(unsigned int base, unsigned int end, + unsigned int num, unsigned int align, const char *name) +{ + unsigned int from = 0, till; + unsigned long flags; + int i; + resource_entry_t *p; /* Scanning ptr */ + resource_entry_t *p1; /* === p->next */ + resource_entry_t *s; /* Found slot */ + + if (base > end-1) + return 0; + if (num > end - base) + return 0; + + for (i = 0; i < IOTABLE_SIZE; i++) + if (iotable[i].num == 0) + break; + if (i == IOTABLE_SIZE) { + /* Driver prints a warning typicaly. */ + return 0; + } + + save_flags(flags); + cli(); + /* printk("occupy: search in %08x[%x] ", base, end - base); */ + s = NULL; + for (p = &iolist; p != NULL; p = p1) { + p1 = p->next; + /* Find window in list */ + from = (p->from+p->num + align-1) & ~(align-1); + till = (p1 == NULL)? (unsigned) (0 - align): p1->from; + /* printk(" %08x:%08x", from, till); */ + /* Clip window with base and end */ + if (from < base) from = base; + if (till > end) till = end; + /* See if result is large enougth */ + if (from < till && from + num < till) { + s = p; + break; + } + } + /* printk("\r\n"); */ + restore_flags(flags); + + if (s == NULL) + return 0; + + iotable[i].name = name; + iotable[i].from = from; + iotable[i].num = num; + iotable[i].next = s->next; + s->next = &iotable[i]; + return from; +} +#endif + /* Called from init/main.c to reserve IO ports. */ void reserve_setup(char *str, int *ints) { diff --git a/kernel/sched.c b/kernel/sched.c index 09697cf3fc5a..a02a9d2f9297 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -106,9 +107,6 @@ struct kernel_stat kstat = { 0 }; static inline void add_to_runqueue(struct task_struct * p) { -#ifdef __SMP__ - int cpu=smp_processor_id(); -#endif #if 1 /* sanity tests */ if (p->next_run || p->prev_run) { printk("task already on run-queue\n"); @@ -123,19 +121,7 @@ static inline void add_to_runqueue(struct task_struct * p) init_task.prev_run = p; #ifdef __SMP__ /* this is safe only if called with cli()*/ - while(set_bit(31,&smp_process_available)) - { - while(test_bit(31,&smp_process_available)) - { - if(clear_bit(cpu,&smp_invalidate_needed)) - { - local_flush_tlb(); - set_bit(cpu,&cpu_callin_map[0]); - } - } - } - smp_process_available++; - clear_bit(31,&smp_process_available); + inc_smp_counter(&smp_process_available); if ((0!=p->pid) && smp_threads_ready) { int i; @@ -302,14 +288,12 @@ asmlinkage void schedule(void) /* check alarm, wake up any interruptible tasks that have got a signal */ + lock_kernel(); if (intr_count) goto scheduling_in_interrupt; - if (bh_active & bh_mask) { - intr_count = 1; + if (bh_active & bh_mask) do_bottom_half(); - intr_count = 0; - } run_task_queue(&tq_scheduler); @@ -401,11 +385,13 @@ asmlinkage void schedule(void) if (timeout) del_timer(&timer); } - return; + goto out; scheduling_in_interrupt: printk("Aiee: scheduling in interrupt %p\n", __builtin_return_address(0)); +out: + unlock_kernel(); } #ifndef __alpha__ @@ -416,8 +402,10 @@ scheduling_in_interrupt: */ asmlinkage int sys_pause(void) { + lock_kernel(); current->state = TASK_INTERRUPTIBLE; schedule(); + unlock_kernel(); return -ERESTARTNOHAND; } @@ -1065,6 +1053,7 @@ static void update_process_times(unsigned long ticks, unsigned long system) utime = 0; stime = ticks; } + update_one_process(p, ticks, utime, stime); if (p->priority < DEF_PRIORITY) @@ -1082,14 +1071,17 @@ static void update_process_times(unsigned long ticks, unsigned long system) * Idle processor found, do we have anything * we could run? */ - if (!(0x7fffffff & smp_process_available)) + if (!(read_smp_counter(&smp_process_available))) continue; } /* Ok, we should reschedule, do the magic */ - if (i==cpu) + cli(); + if (i==cpu) { need_resched = 1; - else + } else { smp_message_pass(i, MSG_RESCHEDULE, 0L, 0); + } + sti(); } #endif } @@ -1151,6 +1143,7 @@ asmlinkage unsigned int sys_alarm(unsigned int seconds) struct itimerval it_new, it_old; unsigned int oldalarm; + lock_kernel(); it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; it_new.it_value.tv_sec = seconds; it_new.it_value.tv_usec = 0; @@ -1160,6 +1153,7 @@ asmlinkage unsigned int sys_alarm(unsigned int seconds) /* And we'd better return too much than too little anyway */ if (it_old.it_value.tv_usec) oldalarm++; + unlock_kernel(); return oldalarm; } @@ -1169,32 +1163,62 @@ asmlinkage unsigned int sys_alarm(unsigned int seconds) */ asmlinkage int sys_getpid(void) { - return current->pid; + int ret; + + lock_kernel(); + ret = current->pid; + unlock_kernel(); + return ret; } asmlinkage int sys_getppid(void) { - return current->p_opptr->pid; + int ret; + + lock_kernel(); + ret = current->p_opptr->pid; + unlock_kernel(); + return ret; } asmlinkage int sys_getuid(void) { - return current->uid; + int ret; + + lock_kernel(); + ret = current->uid; + unlock_kernel(); + return ret; } asmlinkage int sys_geteuid(void) { - return current->euid; + int ret; + + lock_kernel(); + ret = current->euid; + unlock_kernel(); + return ret; } asmlinkage int sys_getgid(void) { - return current->gid; + int ret; + + lock_kernel(); + ret = current->gid; + unlock_kernel(); + return ret; } asmlinkage int sys_getegid(void) { - return current->egid; + int ret; + + lock_kernel(); + ret = current->egid; + unlock_kernel(); + return ret; } /* @@ -1206,14 +1230,17 @@ asmlinkage int sys_nice(int increment) { unsigned long newprio; int increase = 0; + int ret = -EPERM; + lock_kernel(); newprio = increment; if (increment < 0) { if (!suser()) - return -EPERM; + goto out; newprio = -increment; increase = 1; } + ret = 0; if (newprio > 40) newprio = 40; /* @@ -1233,7 +1260,9 @@ asmlinkage int sys_nice(int increment) if (newprio > DEF_PRIORITY*2) newprio = DEF_PRIORITY*2; current->priority = newprio; - return 0; +out: + unlock_kernel(); + return ret; } #endif @@ -1305,86 +1334,124 @@ static int setscheduler(pid_t pid, int policy, asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { - return setscheduler(pid, policy, param); + int ret; + + lock_kernel(); + ret = setscheduler(pid, policy, param); + unlock_kernel(); + return ret; } asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param) { - return setscheduler(pid, -1, param); + int ret; + + lock_kernel(); + ret = setscheduler(pid, -1, param); + unlock_kernel(); + return ret; } asmlinkage int sys_sched_getscheduler(pid_t pid) { struct task_struct *p; + int ret = -EINVAL; + lock_kernel(); if (pid < 0) - return -EINVAL; + goto out; p = find_process_by_pid(pid); + ret = -ESRCH; if (!p) - return -ESRCH; + goto out; - return p->policy; + ret = p->policy; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param) { struct task_struct *p; struct sched_param lp; + int ret = -EINVAL; + lock_kernel(); if (!param || pid < 0) - return -EINVAL; + goto out; p = find_process_by_pid(pid); + ret = -ESRCH; if (!p) - return -ESRCH; + goto out; lp.sched_priority = p->rt_priority; - return copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0; + ret = copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_sched_yield(void) { + lock_kernel(); cli(); move_last_runqueue(current); sti(); + unlock_kernel(); return 0; } asmlinkage int sys_sched_get_priority_max(int policy) { + int ret = -EINVAL; + + lock_kernel(); switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - return 99; - case SCHED_OTHER: - return 0; + case SCHED_FIFO: + case SCHED_RR: + ret = 99; + break; + case SCHED_OTHER: + ret = 0; + break; } - - return -EINVAL; + unlock_kernel(); + return ret; } asmlinkage int sys_sched_get_priority_min(int policy) { + int ret = -EINVAL; + + lock_kernel(); switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - return 1; - case SCHED_OTHER: - return 0; + case SCHED_FIFO: + case SCHED_RR: + ret = 1; + break; + case SCHED_OTHER: + ret = 0; } - - return -EINVAL; + unlock_kernel(); + return ret; } asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { struct timespec t; + int ret; + lock_kernel(); t.tv_sec = 0; - t.tv_nsec = 0; /* <-- Linus, please fill correct value in here */ - return -ENOSYS; /* and then delete this line. Thanks! */ - return copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0; + t.tv_nsec = 0; /* <-- Linus, please fill correct value in here */ + ret = -ENOSYS; goto out; /* and then delete this line. Thanks! */ + ret = copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0; +out: + unlock_kernel(); + return ret; } /* @@ -1412,16 +1479,17 @@ static void jiffiestotimespec(unsigned long jiffies, struct timespec *value) asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) { - int error; + int error = -EFAULT; struct timespec t; unsigned long expire; - error = copy_from_user(&t, rqtp, sizeof(struct timespec)); - if (error) - return -EFAULT; + lock_kernel(); + if(copy_from_user(&t, rqtp, sizeof(struct timespec))) + goto out; + error = -EINVAL; if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0) - return -EINVAL; + goto out; if (t.tv_sec == 0 && t.tv_nsec <= 2000000L && current->policy != SCHED_OTHER) { @@ -1430,7 +1498,8 @@ asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) * high precision by a busy wait for all real-time processes. */ udelay((t.tv_nsec + 999) / 1000); - return 0; + error = 0; + goto out; } expire = timespectojiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies; @@ -1438,17 +1507,20 @@ asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) current->state = TASK_INTERRUPTIBLE; schedule(); + error = 0; if (expire > jiffies) { if (rmtp) { jiffiestotimespec(expire - jiffies - (expire > jiffies + 1), &t); + error = -EFAULT; if (copy_to_user(rmtp, &t, sizeof(struct timespec))) - return -EFAULT; + goto out; } - return -EINTR; + error = -EINTR; } - - return 0; +out: + unlock_kernel(); + return error; } static void show_task(int nr,struct task_struct * p) @@ -1516,7 +1588,7 @@ void sched_init(void) * process right in SMP mode. */ int cpu=smp_processor_id(); -#ifndef __SMP__ +#ifndef __SMP__ current_set[cpu]=&init_task; #else init_task.processor=cpu; diff --git a/kernel/signal.c b/kernel/signal.c index c41728dac837..9e8afe95fd11 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include @@ -31,10 +33,11 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) sigset_t new_set, old_set = current->blocked; int error; + lock_kernel(); if (set) { error = get_user(new_set, set); if (error) - return error; + goto out; new_set &= _BLOCKABLE; switch (how) { case SIG_BLOCK: @@ -47,15 +50,19 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) current->blocked = new_set; break; default: - return -EINVAL; + error = -EINVAL; + goto out; } } if (oset) { error = put_user(old_set, oset); if (error) - return error; + goto out; } - return 0; + error = 0; +out: + unlock_kernel(); + return error; } /* @@ -63,14 +70,22 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) */ asmlinkage int sys_sgetmask(void) { - return current->blocked; + int ret; + + lock_kernel(); + ret = current->blocked; + unlock_kernel(); + return ret; } asmlinkage int sys_ssetmask(int newmask) { - int old=current->blocked; + int old; + lock_kernel(); + old = current->blocked; current->blocked = newmask & _BLOCKABLE; + unlock_kernel(); return old; } @@ -78,8 +93,13 @@ asmlinkage int sys_ssetmask(int newmask) asmlinkage int sys_sigpending(sigset_t *set) { + int ret; + /* fill in "set" with signals pending but blocked. */ - return put_user(current->blocked & current->signal, set); + lock_kernel(); + ret = put_user(current->blocked & current->signal, set); + unlock_kernel(); + return ret; } /* @@ -97,7 +117,7 @@ asmlinkage int sys_sigpending(sigset_t *set) * isn't actually ignored, but does automatic child reaping, while * SIG_DFL is explicitly said by POSIX to force the signal to be ignored.. */ -static inline void check_pending(int signum) +inline void check_pending(int signum) { struct sigaction *p; @@ -120,17 +140,19 @@ static inline void check_pending(int signum) */ asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler) { - int err; + unsigned long err; struct sigaction tmp; + lock_kernel(); + err = -EINVAL; if (signum<1 || signum>32) - return -EINVAL; + goto out; if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; + goto out; if (handler != SIG_DFL && handler != SIG_IGN) { err = verify_area(VERIFY_READ, handler, 1); if (err) - return err; + goto out; } memset(&tmp, 0, sizeof(tmp)); tmp.sa_handler = handler; @@ -138,39 +160,52 @@ asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler) handler = current->sig->action[signum-1].sa_handler; current->sig->action[signum-1] = tmp; check_pending(signum); - return (unsigned long) handler; + err = (unsigned long) handler; +out: + unlock_kernel(); + return err; } #endif +#ifndef __sparc__ asmlinkage int sys_sigaction(int signum, const struct sigaction * action, struct sigaction * oldaction) { struct sigaction new_sa, *p; + int ret = -EINVAL; + lock_kernel(); if (signum<1 || signum>32) - return -EINVAL; + goto out; p = signum - 1 + current->sig->action; if (action) { - int err = verify_area(VERIFY_READ, action, sizeof(*action)); - if (err) - return err; + ret = verify_area(VERIFY_READ, action, sizeof(*action)); + if (ret) + goto out; + ret = -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; + goto out; + ret = -EFAULT; if (copy_from_user(&new_sa, action, sizeof(struct sigaction))) - return -EFAULT; + goto out; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); - if (err) - return err; + ret = verify_area(VERIFY_READ, new_sa.sa_handler, 1); + if (ret) + goto out; } } + ret = -EFAULT; if (oldaction) { if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - return -EFAULT; + goto out; } if (action) { *p = new_sa; check_pending(signum); } - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } +#endif diff --git a/kernel/softirq.c b/kernel/softirq.c index 022b55355a63..4ad1850edf29 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -35,6 +37,8 @@ asmlinkage void do_bottom_half(void) unsigned long mask, left; void (**bh)(void); + lock_kernel(); + intr_count=1; sti(); bh = bh_base; active = bh_active & bh_mask; @@ -48,7 +52,11 @@ asmlinkage void do_bottom_half(void) fn(); } } - return; + goto out; bad_bh: printk ("irq.c:bad bottom half entry %08lx\n", mask); +out: + intr_count=0; + unlock_kernel(); + return; } diff --git a/kernel/sys.c b/kernel/sys.c index bdd06e83b819..ab5e06bf335a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) #include #endif @@ -74,13 +76,15 @@ static int proc_sel(struct task_struct *p, int which, int who) asmlinkage int sys_setpriority(int which, int who, int niceval) { struct task_struct *p; - int error = ESRCH; + int error = EINVAL; unsigned int priority; + lock_kernel(); if (which > 2 || which < 0) - return -EINVAL; + goto out; /* normalize: avoid signed division (rounding problems) */ + error = ESRCH; priority = niceval; if (niceval < 0) priority = -niceval; @@ -109,6 +113,8 @@ asmlinkage int sys_setpriority(int which, int who, int niceval) else p->priority = priority; } +out: + unlock_kernel(); return -error; } @@ -121,9 +127,11 @@ asmlinkage int sys_getpriority(int which, int who) { struct task_struct *p; long max_prio = -ESRCH; + int ret = -EINVAL; + lock_kernel(); if (which > 2 || which < 0) - return -EINVAL; + goto out; for_each_task (p) { if (!proc_sel(p, which, who)) @@ -135,7 +143,10 @@ asmlinkage int sys_getpriority(int which, int who) /* scale the priority from timeslice to 0..40 */ if (max_prio > 0) max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY; - return max_prio; + ret = max_prio; +out: + unlock_kernel(); + return ret; } #ifndef __alpha__ @@ -194,11 +205,16 @@ extern asmlinkage int sys_kill(int, int); */ asmlinkage int sys_reboot(int magic, int magic_too, int flag) { + int error = -EPERM; + + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + error = -EINVAL; if (magic != 0xfee1dead || (magic_too != 672274793 && magic_too != 85072278)) - return -EINVAL; + goto out; + error = 0; if (flag == 0x01234567) { notifier_call_chain(&boot_notifier_list, SYS_DOWN, NULL); @@ -220,8 +236,10 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag) notifier_call_chain(&boot_notifier_list, SYS_HALT, NULL); do_exit(0); } else - return -EINVAL; - return (0); + error = -EINVAL; +out: + unlock_kernel(); + return error; } /* @@ -260,14 +278,16 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) { int old_rgid = current->gid; int old_egid = current->egid; + int err = -EPERM; + lock_kernel(); if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || suser()) current->gid = rgid; else - return(-EPERM); + goto out; } if (egid != (gid_t) -1) { if ((old_rgid == egid) || @@ -277,7 +297,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) current->fsgid = current->egid = egid; else { current->gid = old_rgid; - return(-EPERM); + goto out; } } if (rgid != (gid_t) -1 || @@ -286,7 +306,10 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) current->fsgid = current->egid; if (current->egid != old_egid) current->dumpable = 0; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -295,16 +318,21 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) asmlinkage int sys_setgid(gid_t gid) { int old_egid = current->egid; + int err = -EPERM; + lock_kernel(); if (suser()) current->gid = current->egid = current->sgid = current->fsgid = gid; else if ((gid == current->gid) || (gid == current->sgid)) current->egid = current->fsgid = gid; else - return -EPERM; + goto out; + err = 0; if (current->egid != old_egid) current->dumpable = 0; - return 0; +out: + unlock_kernel(); + return err; } static char acct_active = 0; @@ -353,66 +381,70 @@ int acct_process(long exitcode) asmlinkage int sys_acct(const char *name) { - struct inode *inode = (struct inode *)0; - char *tmp; - int error; - - if (!suser()) - return -EPERM; - - if (name == (char *)0) { - if (acct_active) { - if (acct_file.f_op->release) - acct_file.f_op->release(acct_file.f_inode, &acct_file); - - if (acct_file.f_inode != (struct inode *) 0) - iput(acct_file.f_inode); - - acct_active = 0; - } - return 0; - } else { - if (!acct_active) { - - if ((error = getname(name, &tmp)) != 0) - return (error); - - error = open_namei(tmp, O_RDWR, 0600, &inode, 0); - putname(tmp); - - if (error) - return (error); - - if (!S_ISREG(inode->i_mode)) { - iput(inode); - return -EACCES; - } - - if (!inode->i_op || !inode->i_op->default_file_ops || - !inode->i_op->default_file_ops->write) { - iput(inode); - return -EIO; - } - - acct_file.f_mode = 3; - acct_file.f_flags = 0; - acct_file.f_count = 1; - acct_file.f_inode = inode; - acct_file.f_pos = inode->i_size; - acct_file.f_reada = 0; - acct_file.f_op = inode->i_op->default_file_ops; - - if (acct_file.f_op->open) - if (acct_file.f_op->open(acct_file.f_inode, &acct_file)) { - iput(inode); - return -EIO; - } - - acct_active = 1; - return 0; - } else - return -EBUSY; - } + struct inode *inode = (struct inode *)0; + char *tmp; + int error = -EPERM; + + lock_kernel(); + if (!suser()) + goto out; + + if (name == (char *)0) { + if (acct_active) { + if (acct_file.f_op->release) + acct_file.f_op->release(acct_file.f_inode, &acct_file); + + if (acct_file.f_inode != (struct inode *) 0) + iput(acct_file.f_inode); + + acct_active = 0; + } + error = 0; + } else { + error = -EBUSY; + if (!acct_active) { + if ((error = getname(name, &tmp)) != 0) + goto out; + + error = open_namei(tmp, O_RDWR, 0600, &inode, 0); + putname(tmp); + if (error) + goto out; + + error = -EACCES; + if (!S_ISREG(inode->i_mode)) { + iput(inode); + goto out; + } + + error = -EIO; + if (!inode->i_op || !inode->i_op->default_file_ops || + !inode->i_op->default_file_ops->write) { + iput(inode); + goto out; + } + + acct_file.f_mode = 3; + acct_file.f_flags = 0; + acct_file.f_count = 1; + acct_file.f_inode = inode; + acct_file.f_pos = inode->i_size; + acct_file.f_reada = 0; + acct_file.f_op = inode->i_op->default_file_ops; + + if(acct_file.f_op->open) + if(acct_file.f_op->open(acct_file.f_inode, &acct_file)) { + iput(inode); + goto out; + } + + acct_active = 1; + error = 0; + } + } +out: + unlock_kernel(); + return error; } #ifndef __alpha__ @@ -467,16 +499,20 @@ asmlinkage int sys_old_syscall(void) */ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) { - int old_ruid = current->uid; - int old_euid = current->euid; + int old_ruid; + int old_euid; + int err = -EPERM; + lock_kernel(); + old_ruid = current->uid; + old_euid = current->euid; if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || (current->euid==ruid) || suser()) current->uid = ruid; else - return(-EPERM); + goto out; } if (euid != (uid_t) -1) { if ((old_ruid == euid) || @@ -486,7 +522,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) current->fsuid = current->euid = euid; else { current->uid = old_ruid; - return(-EPERM); + goto out; } } if (ruid != (uid_t) -1 || @@ -495,7 +531,10 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) current->fsuid = current->euid; if (current->euid != old_euid) current->dumpable = 0; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -512,16 +551,22 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) asmlinkage int sys_setuid(uid_t uid) { int old_euid = current->euid; + int retval = 0; + lock_kernel(); if (suser()) current->uid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; - else - return -EPERM; + else { + retval = -EPERM; + goto out; + } if (current->euid != old_euid) current->dumpable = 0; - return(0); +out: + unlock_kernel(); + return retval; } @@ -532,36 +577,43 @@ asmlinkage int sys_setuid(uid_t uid) asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { uid_t old_ruid, old_euid, old_suid; + int err = -EPERM; + lock_kernel(); old_ruid = current->uid; old_euid = current->euid; old_suid = current->suid; if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) - return -EPERM; + goto out; if ((euid != (uid_t) -1) && (euid != current->uid) && (euid != current->euid) && (euid != current->suid)) - return -EPERM; + goto out; if ((suid != (uid_t) -1) && (suid != current->uid) && (suid != current->euid) && (suid != current->suid)) - return -EPERM; + goto out; if (ruid != (uid_t) -1) current->uid = ruid; if (euid != (uid_t) -1) current->euid = euid; if (suid != (uid_t) -1) current->suid = suid; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { int retval; + lock_kernel(); if (!(retval = put_user(current->uid, ruid)) && !(retval = put_user(current->euid, euid))) retval = put_user(current->suid, suid); + unlock_kernel(); return retval; } @@ -574,13 +626,16 @@ asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) */ asmlinkage int sys_setfsuid(uid_t uid) { - int old_fsuid = current->fsuid; + int old_fsuid; + lock_kernel(); + old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || suser()) current->fsuid = uid; if (current->fsuid != old_fsuid) current->dumpable = 0; + unlock_kernel(); return old_fsuid; } @@ -589,19 +644,24 @@ asmlinkage int sys_setfsuid(uid_t uid) */ asmlinkage int sys_setfsgid(gid_t gid) { - int old_fsgid = current->fsgid; + int old_fsgid; + lock_kernel(); + old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || suser()) current->fsgid = gid; if (current->fsgid != old_fsgid) current->dumpable = 0; + unlock_kernel(); return old_fsgid; } asmlinkage long sys_times(struct tms * tbuf) { int error; + + lock_kernel(); if (tbuf) { error = put_user(current->utime,&tbuf->tms_utime); if (!error) @@ -611,9 +671,12 @@ asmlinkage long sys_times(struct tms * tbuf) if (!error) error = put_user(current->cstime,&tbuf->tms_cstime); if (error) - return error; + goto out; } - return jiffies; + error = jiffies; +out: + unlock_kernel(); + return error; } /* @@ -631,89 +694,127 @@ asmlinkage long sys_times(struct tms * tbuf) asmlinkage int sys_setpgid(pid_t pid, pid_t pgid) { struct task_struct * p; + int err = -EINVAL; + lock_kernel(); if (!pid) pid = current->pid; if (!pgid) pgid = pid; if (pgid < 0) - return -EINVAL; + goto out; for_each_task(p) { if (p->pid == pid) goto found_task; } - return -ESRCH; + err = -ESRCH; + goto out; found_task: + err = -ESRCH; if (p->p_pptr == current || p->p_opptr == current) { + err = -EPERM; if (p->session != current->session) - return -EPERM; + goto out; + err = -EACCES; if (p->did_exec) - return -EACCES; + goto out; } else if (p != current) - return -ESRCH; + goto out; + err = -EPERM; if (p->leader) - return -EPERM; + goto out; if (pgid != pid) { struct task_struct * tmp; for_each_task (tmp) { if (tmp->pgrp == pgid && - tmp->session == current->session) + tmp->session == current->session) goto ok_pgid; } - return -EPERM; + goto out; } ok_pgid: p->pgrp = pgid; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } asmlinkage int sys_getpgid(pid_t pid) { struct task_struct * p; - - if (!pid) - return current->pgrp; - for_each_task(p) { - if (p->pid == pid) - return p->pgrp; + int ret; + + lock_kernel(); + if (!pid) { + ret = current->pgrp; + } else { + for_each_task(p) { + if (p->pid == pid) { + ret = p->pgrp; + goto out; + } + } + ret = -ESRCH; } - return -ESRCH; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_getpgrp(void) { - return current->pgrp; + int ret; + + lock_kernel(); + ret = current->pgrp; + unlock_kernel(); + return ret; } asmlinkage int sys_getsid(pid_t pid) { struct task_struct * p; - - if (!pid) - return current->session; - for_each_task(p) { - if (p->pid == pid) - return p->session; + int ret; + + lock_kernel(); + if (!pid) { + ret = current->session; + } else { + for_each_task(p) { + if (p->pid == pid) { + ret = p->session; + goto out; + } + } + ret = -ESRCH; } - return -ESRCH; +out: + unlock_kernel(); + return ret; } asmlinkage int sys_setsid(void) { struct task_struct * p; + int err = -EPERM; + lock_kernel(); for_each_task(p) { if (p->pgrp == current->pid) - return -EPERM; + goto out; } current->leader = 1; current->session = current->pgrp = current->pid; current->tty = NULL; current->tty_old_pgrp = 0; - return current->pgrp; + err = current->pgrp; +out: + unlock_kernel(); + return err; } /* @@ -721,34 +822,44 @@ asmlinkage int sys_setsid(void) */ asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist) { - int i; + int i, err = -EINVAL; + lock_kernel(); if (gidsetsize < 0) - return -EINVAL; + goto out; i = current->ngroups; if (gidsetsize) { + err = -EINVAL; if (i > gidsetsize) - return -EINVAL; + goto out; + err = -EFAULT; if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i)) - return -EFAULT; + goto out; } - return i; + err = i; +out: + unlock_kernel(); + return err; } asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) { - int err; + int err = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + err = -EINVAL; if ((unsigned) gidsetsize > NGROUPS) - return -EINVAL; + goto out; err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)); if (err) { gidsetsize = 0; err = -EFAULT; } current->ngroups = gidsetsize; +out: + unlock_kernel(); return err; } @@ -773,11 +884,17 @@ out: asmlinkage int sys_newuname(struct new_utsname * name) { + int err = -EFAULT; + + lock_kernel(); if (!name) - return -EFAULT; + goto out; if (copy_to_user(name,&system_utsname,sizeof *name)) - return -EFAULT; - return 0; + goto out; + err = 0; +out: + unlock_kernel(); + return err; } #ifndef __alpha__ @@ -788,17 +905,22 @@ asmlinkage int sys_newuname(struct new_utsname * name) */ asmlinkage int sys_uname(struct old_utsname * name) { - int error = -EFAULT;; + int error = -EFAULT; + + lock_kernel(); if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) error = 0; + unlock_kernel(); return error; } asmlinkage int sys_olduname(struct oldold_utsname * name) { - int error; + int error = -EFAULT; + + lock_kernel(); if (!name) - return -EFAULT; + goto out; error = copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); if (!error) error = put_user(0,name->sysname+__OLD_UTS_LEN); @@ -818,36 +940,49 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) error = copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); if (!error) error = put_user(0,name->machine+__OLD_UTS_LEN); - return error ? -EFAULT : 0; + error = error ? -EFAULT : 0; +out: + unlock_kernel(); + return error; } #endif asmlinkage int sys_sethostname(char *name, int len) { - int error; + int error = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + error = -EINVAL; if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; + goto out; error = copy_from_user(system_utsname.nodename, name, len); - if (error) - return -EFAULT; + if (error) { + error = -EFAULT; + goto out; + } system_utsname.nodename[len] = 0; - return 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_gethostname(char *name, int len) { - int i; + int i, err = -EINVAL; + lock_kernel(); if (len < 0) - return -EINVAL; + goto out; i = 1+strlen(system_utsname.nodename); if (i > len) i = len; - return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0; + err = copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0; +out: + unlock_kernel(); + return err; } /* @@ -856,48 +991,66 @@ asmlinkage int sys_gethostname(char *name, int len) */ asmlinkage int sys_setdomainname(char *name, int len) { - int error; + int error = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + error = -EINVAL; if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; + goto out; error = copy_from_user(system_utsname.domainname, name, len); if (error) - return -EFAULT; - system_utsname.domainname[len] = 0; - return 0; + error = -EFAULT; + else + system_utsname.domainname[len] = 0; +out: + unlock_kernel(); + return error; } asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim) { + int error; + + lock_kernel(); if (resource >= RLIM_NLIMITS) - return -EINVAL; - return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim)) - ? -EFAULT : 0 ; + error = -EINVAL; + else + error = copy_to_user(rlim, current->rlim + resource, sizeof(*rlim)) + ? -EFAULT : 0; + unlock_kernel(); + return error; } asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) { struct rlimit new_rlim, *old_rlim; - int err; + int err = -EINVAL; + lock_kernel(); if (resource >= RLIM_NLIMITS) - return -EINVAL; + goto out; err = copy_from_user(&new_rlim, rlim, sizeof(*rlim)); - if (err) - return -EFAULT; + if (err) { + err = -EFAULT; + goto out; + } old_rlim = current->rlim + resource; + err = -EPERM; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && !suser()) - return -EPERM; + goto out; if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) - return -EPERM; + goto out; } *old_rlim = new_rlim; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -911,7 +1064,9 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) int getrusage(struct task_struct *p, int who, struct rusage *ru) { struct rusage r; + int err; + lock_kernel(); memset((char *) &r, 0, sizeof(r)); switch (who) { case RUSAGE_SELF: @@ -942,20 +1097,31 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru) r.ru_nswap = p->nswap + p->cnswap; break; } - return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; + err = copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; + unlock_kernel(); + return err; } asmlinkage int sys_getrusage(int who, struct rusage *ru) { + int err = -EINVAL; + + lock_kernel(); if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) - return -EINVAL; - return getrusage(current, who, ru); + goto out; + err = getrusage(current, who, ru); +out: + unlock_kernel(); + return err; } asmlinkage int sys_umask(int mask) { - int old = current->fs->umask; + int old; + lock_kernel(); + old = current->fs->umask; current->fs->umask = mask & S_IRWXUGO; + unlock_kernel(); return (old); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ce4f82da89f7..f96870ed90b4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -226,12 +228,17 @@ extern asmlinkage int sys_sysctl(struct __sysctl_args *args) { struct __sysctl_args tmp; int error; + + lock_kernel(); error = verify_area(VERIFY_READ, args, sizeof(*args)); if (error) - return error; + goto out; copy_from_user(&tmp, args, sizeof(tmp)); - return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, - tmp.newval, tmp.newlen); + error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, + tmp.newval, tmp.newlen); +out: + unlock_kernel(); + return error; } /* Like in_group_p, but testing against egid, not fsgid */ diff --git a/kernel/time.c b/kernel/time.c index c2090a5830be..6f3cd8d40297 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include @@ -64,11 +66,13 @@ asmlinkage int sys_time(int * tloc) { int i; + lock_kernel(); i = CURRENT_TIME; if (tloc) { if (put_user(i,tloc)) i = -EFAULT; } + unlock_kernel(); return i; } @@ -80,12 +84,14 @@ asmlinkage int sys_time(int * tloc) */ asmlinkage int sys_stime(int * tptr) { - int value; + int value = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + value = -EFAULT; if (get_user(value, tptr)) - return -EFAULT; + goto out; cli(); xtime.tv_sec = value; xtime.tv_usec = 0; @@ -93,24 +99,33 @@ asmlinkage int sys_stime(int * tptr) time_maxerror = MAXPHASE; time_esterror = MAXPHASE; sti(); - return 0; + value = 0; +out: + unlock_kernel(); + return value; } #endif asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz) { + int err = -EFAULT; + + lock_kernel(); if (tv) { struct timeval ktv; do_gettimeofday(&ktv); if (copy_to_user(tv, &ktv, sizeof(ktv))) - return -EFAULT; + goto out; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) - return -EFAULT; + goto out; } - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -151,16 +166,19 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) static int firsttime = 1; struct timeval new_tv; struct timezone new_tz; + int err = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + err = -EFAULT; if (tv) { if (copy_from_user(&new_tv, tv, sizeof(*tv))) - return -EFAULT; + goto out; } if (tz) { if (copy_from_user(&new_tz, tz, sizeof(*tz))) - return -EFAULT; + goto out; sys_tz = new_tz; if (firsttime) { firsttime = 0; @@ -170,7 +188,10 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) } if (tv) do_settimeofday(&new_tv); - return 0; + err = 0; +out: + unlock_kernel(); + return err; } long pps_offset = 0; /* pps time offset (us) */ @@ -197,35 +218,33 @@ void (*hardpps_ptr)(struct timeval *) = (void (*)(struct timeval *))0; asmlinkage int sys_adjtimex(struct timex *txc_p) { long ltemp, mtemp, save_adjust; - int error; - - /* Local copy of parameter */ - struct timex txc; + int error = -EFAULT; + struct timex txc; /* Local copy of parameter */ + lock_kernel(); /* Copy the user data space into the kernel copy * structure. But bear in mind that the structures * may change */ - error = copy_from_user(&txc, txc_p, sizeof(struct timex)); - if (error) - return -EFAULT; + if(copy_from_user(&txc, txc_p, sizeof(struct timex))) + goto out; /* In order to modify anything, you gotta be super-user! */ + error = -EPERM; if (txc.modes && !suser()) - return -EPERM; - - /* Now we validate the data before disabling interrupts - */ + goto out; + /* Now we validate the data before disabling interrupts */ + error = -EINVAL; if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET)) /* adjustment Offset limited to +- .512 seconds */ if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE ) - return -EINVAL; + goto out; /* if the quartz is off by more than 10% something is VERY wrong ! */ if (txc.modes & ADJ_TICK) if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ) - return -EINVAL; + goto out; cli(); @@ -343,5 +362,8 @@ asmlinkage int sys_adjtimex(struct timex *txc_p) sti(); - return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state; + error = copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state; +out: + unlock_kernel(); + return error; } diff --git a/mm/Makefile b/mm/Makefile index 19552c98fd5c..5f5156049d6b 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -9,7 +9,7 @@ O_TARGET := mm.o O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ - kmalloc.o vmalloc.o \ + kmalloc.o vmalloc.o slab.o \ swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o include $(TOPDIR)/Rules.make diff --git a/mm/filemap.c b/mm/filemap.c index c40adb6ac4d1..fb439fbd8adb 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -1222,18 +1224,20 @@ asmlinkage int sys_msync(unsigned long start, size_t len, int flags) { unsigned long end; struct vm_area_struct * vma; - int unmapped_error, error; + int unmapped_error, error = -EINVAL; + lock_kernel(); if (start & ~PAGE_MASK) - return -EINVAL; + goto out; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; if (end < start) - return -EINVAL; + goto out; if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) - return -EINVAL; + goto out; + error = 0; if (end == start) - return 0; + goto out; /* * If the interval [start,end) covers some unmapped address ranges, * just ignore them, but return -EFAULT at the end. @@ -1242,8 +1246,9 @@ asmlinkage int sys_msync(unsigned long start, size_t len, int flags) unmapped_error = 0; for (;;) { /* Still start < end. */ + error = -EFAULT; if (!vma) - return -EFAULT; + goto out; /* Here start < vma->vm_end. */ if (start < vma->vm_start) { unmapped_error = -EFAULT; @@ -1254,15 +1259,19 @@ asmlinkage int sys_msync(unsigned long start, size_t len, int flags) if (start < end) { error = msync_interval(vma, start, end, flags); if (error) - return error; + goto out; } - return unmapped_error; + error = unmapped_error; + goto out; } /* Here vma->vm_start <= start < vma->vm_end < end. */ error = msync_interval(vma, start, vma->vm_end, flags); if (error) - return error; + goto out; start = vma->vm_end; vma = vma->vm_next; } +out: + unlock_kernel(); + return error; } diff --git a/mm/mlock.c b/mm/mlock.c index 14281d9c37b7..27bff13ffca1 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -7,11 +7,13 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include #include #include @@ -28,7 +30,7 @@ static inline int mlock_fixup_start(struct vm_area_struct * vma, { struct vm_area_struct * n; - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!n) return -EAGAIN; *n = *vma; @@ -49,7 +51,7 @@ static inline int mlock_fixup_end(struct vm_area_struct * vma, { struct vm_area_struct * n; - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!n) return -EAGAIN; *n = *vma; @@ -70,12 +72,12 @@ static inline int mlock_fixup_middle(struct vm_area_struct * vma, { struct vm_area_struct * left, * right; - left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!left) return -EAGAIN; - right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!right) { - kfree(left); + kmem_cache_free(vm_area_cachep, left); return -EAGAIN; } *left = *vma; @@ -187,7 +189,9 @@ asmlinkage int sys_mlock(unsigned long start, size_t len) { unsigned long locked; unsigned long lock_limit; + int error = -ENOMEM; + lock_kernel(); len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK; start &= PAGE_MASK; @@ -199,21 +203,29 @@ asmlinkage int sys_mlock(unsigned long start, size_t len) /* check against resource limits */ if (locked > lock_limit) - return -ENOMEM; + goto out; /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ if (locked > num_physpages/2) - return -ENOMEM; + goto out; - return do_mlock(start, len, 1); + error = do_mlock(start, len, 1); +out: + unlock_kernel(); + return error; } asmlinkage int sys_munlock(unsigned long start, size_t len) { + int ret; + + lock_kernel(); len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK; start &= PAGE_MASK; - return do_mlock(start, len, 0); + ret = do_mlock(start, len, 0); + unlock_kernel(); + return ret; } static int do_mlockall(int flags) @@ -248,25 +260,36 @@ static int do_mlockall(int flags) asmlinkage int sys_mlockall(int flags) { unsigned long lock_limit; + int ret = -EINVAL; + lock_kernel(); if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) - return -EINVAL; + goto out; lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; + ret = -ENOMEM; if (current->mm->total_vm > lock_limit) - return -ENOMEM; + goto out; /* we may lock at most half of physical memory... */ /* (this check is pretty bogus, but doesn't hurt) */ if (current->mm->total_vm > num_physpages/2) - return -ENOMEM; + goto out; - return do_mlockall(flags); + ret = do_mlockall(flags); +out: + unlock_kernel(); + return ret; } asmlinkage int sys_munlockall(void) { - return do_mlockall(0); + int ret; + + lock_kernel(); + ret = do_mlockall(0); + unlock_kernel(); + return ret; } diff --git a/mm/mmap.c b/mm/mmap.c index 56d71ec1ef79..f2ea12f65d4d 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -7,13 +7,15 @@ #include #include #include +#include #include #include #include #include -#include #include #include +#include +#include #include #include @@ -41,6 +43,9 @@ pgprot_t protection_map[16] = { __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +/* SLAB cache for vm_area_struct's. */ +kmem_cache_t *vm_area_cachep; + /* * Check that a process has enough memory to allocate a * new virtual mapping. @@ -64,54 +69,62 @@ static inline int vm_enough_memory(long pages) asmlinkage unsigned long sys_brk(unsigned long brk) { - unsigned long rlim; + unsigned long rlim, retval; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; + lock_kernel(); + retval = mm->brk; if (brk < mm->end_code) - return mm->brk; + goto out; newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); - if (oldbrk == newbrk) - return mm->brk = brk; + if (oldbrk == newbrk) { + retval = mm->brk = brk; + goto out; + } /* * Always allow shrinking brk */ if (brk <= mm->brk) { - mm->brk = brk; + retval = mm->brk = brk; do_munmap(newbrk, oldbrk-newbrk); - return brk; + goto out; } /* * Check against rlimit and stack.. */ + retval = mm->brk; rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (brk - mm->end_code > rlim) - return mm->brk; + goto out; /* * Check against existing mmap mappings. */ if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) - return mm->brk; + goto out; /* * Check if we have enough memory.. */ if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) - return mm->brk; + goto out; /* * Ok, looks good - let it rip. */ if(do_mmap(NULL, oldbrk, newbrk-oldbrk, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0) != oldbrk) - return mm->brk; - return mm->brk = brk; + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0) == oldbrk) + mm->brk = brk; + retval = mm->brk; +out: + unlock_kernel(); + return retval; } /* @@ -215,8 +228,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, if (file && (!file->f_op || !file->f_op->mmap)) return -ENODEV; - vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct), - GFP_KERNEL); + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!vma) return -ENOMEM; @@ -256,7 +268,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, /* Check against address space limit. */ if ((mm->total_vm << PAGE_SHIFT) + len > current->rlim[RLIMIT_AS].rlim_cur) { - kfree(vma); + kmem_cache_free(vm_area_cachep, vma); return -ENOMEM; } @@ -264,7 +276,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) { if (!(flags & MAP_NORESERVE) && !vm_enough_memory(len >> PAGE_SHIFT)) { - kfree(vma); + kmem_cache_free(vm_area_cachep, vma); return -ENOMEM; } } @@ -273,7 +285,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, int error = file->f_op->mmap(file->f_inode, file, vma); if (error) { - kfree(vma); + kmem_cache_free(vm_area_cachep, vma); return error; } } @@ -284,7 +296,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, /* merge_segments might have merged our vma, so we can't use it any more */ mm->total_vm += len >> PAGE_SHIFT; - if (flags & VM_LOCKED) { + if ((flags & VM_LOCKED) && !(flags & VM_IO)) { unsigned long start = addr; mm->locked_vm += len >> PAGE_SHIFT; do { @@ -751,7 +763,7 @@ static void unmap_fixup(struct vm_area_struct *area, else { /* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */ /* Add end mapping -- leave beginning for below */ - mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!mpnt) return; @@ -767,7 +779,7 @@ static void unmap_fixup(struct vm_area_struct *area, } /* construct whatever mapping is needed */ - mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!mpnt) return; *mpnt = *area; @@ -782,7 +794,12 @@ static void unmap_fixup(struct vm_area_struct *area, asmlinkage int sys_munmap(unsigned long addr, size_t len) { - return do_munmap(addr, len); + int ret; + + lock_kernel(); + ret = do_munmap(addr, len); + unlock_kernel(); + return ret; } /* @@ -851,7 +868,7 @@ int do_munmap(unsigned long addr, size_t len) zap_page_range(current->mm, st, size); flush_tlb_range(current->mm, st, end); unmap_fixup(mpnt, st, size); - kfree(mpnt); + kmem_cache_free(vm_area_cachep, mpnt); } while (free); /* we could zap the page tables here too.. */ @@ -896,7 +913,7 @@ void exit_mmap(struct mm_struct * mm) zap_page_range(mm, start, size); if (mpnt->vm_inode) iput(mpnt->vm_inode); - kfree(mpnt); + kmem_cache_free(vm_area_cachep, mpnt); mpnt = next; } } @@ -1045,9 +1062,19 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l remove_shared_vm_struct(mpnt); if (mpnt->vm_inode) mpnt->vm_inode->i_count--; - kfree_s(mpnt, sizeof(*mpnt)); + kmem_cache_free(vm_area_cachep, mpnt); mpnt = prev; } no_vma: up(&mm->mmap_sem); } + +void vma_init(void) +{ + vm_area_cachep = kmem_cache_create("vm_area_struct", + sizeof(struct vm_area_struct), + sizeof(long)*8, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if(!vm_area_cachep) + panic("vma_init: Cannot alloc vm_area_struct cache."); +} diff --git a/mm/mprotect.c b/mm/mprotect.c index 5aa7794a4296..7f5e26243389 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -7,11 +7,13 @@ #include #include #include +#include +#include #include #include #include #include -#include +#include #include #include @@ -99,7 +101,7 @@ static inline int mprotect_fixup_start(struct vm_area_struct * vma, { struct vm_area_struct * n; - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!n) return -ENOMEM; *n = *vma; @@ -122,7 +124,7 @@ static inline int mprotect_fixup_end(struct vm_area_struct * vma, { struct vm_area_struct * n; - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!n) return -ENOMEM; *n = *vma; @@ -145,12 +147,12 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma, { struct vm_area_struct * left, * right; - left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!left) return -ENOMEM; - right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!right) { - kfree(left); + kmem_cache_free(vm_area_cachep, left); return -ENOMEM; } *left = *vma; @@ -204,21 +206,24 @@ asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) { unsigned long nstart, end, tmp; struct vm_area_struct * vma, * next; - int error; + int error = -EINVAL; + lock_kernel(); if (start & ~PAGE_MASK) - return -EINVAL; + goto out; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; if (end < start) - return -EINVAL; + goto out; if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) - return -EINVAL; + goto out; + error = 0; if (end == start) - return 0; + goto out; vma = find_vma(current->mm, start); + error = -EFAULT; if (!vma || vma->vm_start > start) - return -EFAULT; + goto out; for (nstart = start ; ; ) { unsigned int newflags; @@ -249,5 +254,7 @@ asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) } } merge_segments(current->mm, start, end); +out: + unlock_kernel(); return error; } diff --git a/mm/mremap.c b/mm/mremap.c index 65c0ff5351ed..dfe826847630 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -8,11 +8,13 @@ #include #include #include +#include +#include #include #include #include #include -#include +#include #include #include @@ -129,8 +131,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma, { struct vm_area_struct * new_vma; - new_vma = (struct vm_area_struct *) - kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (new_vma) { unsigned long new_addr = get_unmapped_area(addr, new_len); @@ -149,7 +150,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma, current->mm->total_vm += new_len >> PAGE_SHIFT; return new_addr; } - kfree(new_vma); + kmem_cache_free(vm_area_cachep, new_vma); } return -ENOMEM; } @@ -163,9 +164,11 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long flags) { struct vm_area_struct *vma; + unsigned long ret = -EINVAL; + lock_kernel(); if (addr & ~PAGE_MASK) - return -EINVAL; + goto out; old_len = PAGE_ALIGN(old_len); new_len = PAGE_ALIGN(new_len); @@ -173,29 +176,33 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, * Always allow a shrinking remap: that just unmaps * the unnecessary pages.. */ + ret = addr; if (old_len > new_len) { do_munmap(addr+new_len, old_len - new_len); - return addr; + goto out; } /* * Ok, we need to grow.. */ + ret = -EFAULT; vma = find_vma(current->mm, addr); if (!vma || vma->vm_start > addr) - return -EFAULT; + goto out; /* We can't remap across vm area boundaries */ if (old_len > vma->vm_end - addr) - return -EFAULT; + goto out; if (vma->vm_flags & VM_LOCKED) { unsigned long locked = current->mm->locked_vm << PAGE_SHIFT; locked += new_len - old_len; + ret = -EAGAIN; if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) - return -EAGAIN; + goto out; } + ret = -ENOMEM; if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) > current->rlim[RLIMIT_AS].rlim_cur) - return -ENOMEM; + goto out; /* old_len exactly to the end of the area.. */ if (old_len == vma->vm_end - addr && @@ -210,7 +217,8 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, current->mm->total_vm += pages; if (vma->vm_flags & VM_LOCKED) current->mm->locked_vm += pages; - return addr; + ret = addr; + goto out; } } @@ -219,6 +227,10 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, * we need to create a new one and move it.. */ if (flags & MREMAP_MAYMOVE) - return move_vma(vma, addr, old_len, new_len); - return -ENOMEM; + ret = move_vma(vma, addr, old_len, new_len); + else + ret = -ENOMEM; +out: + unlock_kernel(); + return ret; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f6f1bbd706e7..0b76eea08c90 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5,6 +5,7 @@ * Swap reorganised 29.12.95, Stephen Tweedie */ +#include #include #include #include @@ -34,7 +35,13 @@ int nr_free_pages = 0; * of different sizes */ +#if CONFIG_AP1000 +/* the AP+ needs to allocate 8MB contiguous, aligned chunks of ram + for the ring buffers */ +#define NR_MEM_LISTS 12 +#else #define NR_MEM_LISTS 6 +#endif /* The start of this MUST match the start of "struct page" */ struct free_area_struct { @@ -239,7 +246,7 @@ void show_free_areas(void) nr ++; } total += nr * ((PAGE_SIZE>>10) << order); - printk("%lu*%lukB ", nr, (PAGE_SIZE>>10) << order); + printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order)); } restore_flags(flags); printk("= %lukB)\n", total); diff --git a/mm/slab.c b/mm/slab.c new file mode 100644 index 000000000000..8b8ee2d932b0 --- /dev/null +++ b/mm/slab.c @@ -0,0 +1,1526 @@ +/* + * linux/mm/slab.c + * Written by Mark Hemment, 1996. + * (markhe@nextd.demon.co.uk) + */ +/* + * An implementation of the Slab Allocator as described in outline in; + * UNIX Internals: The New Frontiers by Uresh Vahalia + * Pub: Prentice Hall ISBN 0-13-101908-2 + * or with a little more detail in; + * The Slab Allocator: An Object-Caching Kernel Memory Allocator + * Jeff Bonwick (Sun Microsystems). + * Presented at: USENIX Summer 1994 Technical Conference + */ + +#include +#include +#include +#include +#include + +/* SLAB_MGMT_CHECKS - define to enable extra checks in + * kmem_cache_[create|destroy|shrink]. + * If you're not messing around with these funcs, then undef this. + * SLAB_HIGH_PACK - define to allow 'bufctl's to be stored within objs that do not + * have a state. This allows more objs per slab, but removes the + * ability to sanity check an addr on release (if the addr is + * within any slab, anywhere, kmem_cache_free() will accept it!). + * SLAB_DEBUG_SUPPORT - when defined, kmem_cache_create() will honour; SLAB_DEBUG_FREE, + * SLAB_DEBUG_INITIAL and SLAB_RED_ZONE. + */ +#define SLAB_MGMT_CHECKS +#undef SLAB_HIGH_PACK +#define SLAB_DEBUG_SUPPORT /* undef this when your cache is stable */ + +#define BYTES_PER_WORD sizeof(void *) + +/* legal flag mask for kmem_cache_create() */ +#if defined(SLAB_DEBUG_SUPPORT) +#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_HWCACHE_ALIGN|SLAB_RED_ZONE) +#else +#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN) +#endif /* SLAB_DEBUG_SUPPORT */ + +/* Magic num for red zoning. + * Placed in the first word after the end of an obj + */ +#define SLAB_RED_MAGIC1 0x5A2CF071UL /* when obj is active */ +#define SLAB_RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */ + +/* Used for linking objs within a slab. How much of the struct is + * used, and where its placed, depends on the packing used in a cache. + * Don't mess with the order! + */ +typedef struct kmem_bufctl_s { + struct kmem_bufctl_s *buf_nextp; + struct kmem_slab_s *buf_slabp; + void *buf_objp; /* start of obj */ + struct kmem_bufctl_s *buf_hnextp; + struct kmem_bufctl_s **buf_hashp; +} kmem_bufctl_t; + +/* different portions of the bufctl are used - so need some macros */ +#define kmem_bufctl_offset(x) ((unsigned long)&((kmem_bufctl_t *)0)->x) +#define kmem_bufctl_short_size (kmem_bufctl_offset(buf_objp)) +#define kmem_bufctl_very_short_size (kmem_bufctl_offset(buf_slabp)) + +/* Slab management struct. + * Manages the objs in a slab. Placed either at the end of mem allocated + * for the slab, or from an internal obj cache (SLAB_CFLGS_OFF_SLAB). + * Slabs are chain into a partially ordered list. The linking ptrs must + * be first in the struct! + * The size of the struct is important(ish); it should align well on + * cache line(s) + */ +typedef struct kmem_slab_s { + struct kmem_slab_s *s_nextp; + struct kmem_slab_s *s_prevp; + void *s_mem; /* addr of mem allocated for slab */ + unsigned long s_jiffies; + kmem_bufctl_t *s_freep; /* ptr to first inactive obj in slab */ + unsigned long s_flags; + unsigned long s_magic; + unsigned long s_inuse; /* num of objs active in slab */ +} kmem_slab_t; + +/* to test for end of slab chain */ +#define kmem_slab_end(x) ((kmem_slab_t*)&((x)->c_firstp)) + +/* s_magic */ +#define SLAB_MAGIC_ALLOC 0xA5C32F2BUL +#define SLAB_MAGIC_UNALLOC 0xB2F23C5AUL + +/* s_flags */ +#define SLAB_SFLGS_DMA 0x000001UL /* slab's mem can do DMA */ + +/* cache struct - manages a cache. + * c_lastp must appear immediately after c_firstp! + */ +struct kmem_cache_s { + kmem_slab_t *c_freep; /* first slab w. free objs */ + unsigned long c_flags; + unsigned long c_offset; + struct kmem_bufctl_s **c_hashp; /* ptr for off-slab bufctls */ + kmem_slab_t *c_firstp; /* first slab in chain */ + kmem_slab_t *c_lastp; /* last slab in chain */ + unsigned long c_hashbits; + unsigned long c_num; /* # of objs per slab */ + unsigned long c_gfporder; /* order of pgs per slab (2^n) */ + unsigned long c_org_size; + unsigned long c_magic; + unsigned long c_inuse; /* kept at zero */ + void (*c_ctor)(void *, int, unsigned long); /* constructor func */ + void (*c_dtor)(void *, int, unsigned long); /* de-constructor func */ + unsigned long c_align; /* alignment of objs */ + unsigned long c_colour; /* cache colouring range */ + unsigned long c_colour_next;/* cache colouring */ + const char *c_name; + struct kmem_cache_s *c_nextp; +}; + +/* magic # for c_magic - used to detect out-of-slabs in __kmem_cache_alloc() */ +#define SLAB_C_MAGIC 0x4F17A36DUL + +/* internal c_flags */ +#define SLAB_CFLGS_OFF_SLAB 0x010000UL /* slab mgmt in own cache */ +#define SLAB_CFLGS_BUFCTL 0x020000UL /* bufctls in own cache */ +#define SLAB_CFLGS_RELEASED 0x040000UL /* cache is/being destroyed */ + +#if defined(SLAB_HIGH_PACK) +#define SLAB_CFLGS_PTR_IN_OBJ 0x080000UL /* free ptr in obj */ +#endif + +#define SLAB_OFF_SLAB(x) ((x) & SLAB_CFLGS_OFF_SLAB) +#define SLAB_BUFCTL(x) ((x) & SLAB_CFLGS_BUFCTL) +#define SLAB_RELEASED(x) ((x) & SLAB_CFLGS_RELEASED) +#if defined(SLAB_HIGH_PACK) +#define SLAB_PTR_IN_OBJ(x) ((x) & SLAB_CFLGS_PTR_IN_OBJ) +#else +#define SLAB_PTR_IN_OBJ(x) (0) +#endif + +/* maximum size of an obj (in 2^order pages) */ +#define SLAB_OBJ_MAX_ORDER 5 /* 32 pages */ + +/* maximum num of pages for a slab (avoids trying to ask for too may contigious pages) */ +#define SLAB_MAX_GFP_ORDER 5 /* 32 pages */ + +/* the 'prefered' minimum num of objs per slab - maybe less for large objs */ +#define SLAB_MIN_OBJS_PER_SLAB 4 + +/* if the num of objs per slab is <= SLAB_MIN_OBJS_PER_SLAB, + * then the page order must be less than this before trying the next order + */ +#define SLAB_BREAK_GFP_ORDER 2 + +/* size of hash tables for caches which use off-slab bufctls (SLAB_CFLGS_BUFCTL) */ +#define KMEM_HASH_SIZE 128 + +/* size description struct for general-caches */ +typedef struct cache_sizes { + unsigned long cs_size; + kmem_cache_t *cs_cachep; +} cache_sizes_t; + +static cache_sizes_t cache_sizes[] = { +#if PAGE_SIZE == 4096 + { 32, NULL}, +#endif + { 64, NULL}, + { 128, NULL}, + { 256, NULL}, + { 512, NULL}, + {1024, NULL}, + {2048, NULL}, + {4096, NULL}, + {8192, NULL}, +#if PAGE_SIZE == 8192 + {16384, NULL}, +#endif + {0, NULL} +}; + +/* Names for the general-caches. + * Not placed into the sizes struct for a good reason; the + * string ptr is not needed while searching in kmem_alloc()/ + * kmem_free(), and would 'get-in-the-way' - think about it. + */ +static char *cache_sizes_name[] = { +#if PAGE_SIZE == 4096 + "cache-32", +#endif + "cache-64", + "cache-128", + "cache-256", + "cache-512", + "cache-1024", + "cache-2048", + "cache-4096", +#if PAGE_SIZE == 4096 + "cache-8192" +#elif PAGE_SIZE == 8192 + "cache-8192", + "cache-16384" +#else +#error Your page size is not supported for the general-caches - please fix +#endif +}; + +static void kmem_hash_ctor(void *ptr, int , unsigned long); /* fwd ref */ +extern kmem_cache_t cache_cache; /* fwd ref */ + +/* internal cache of hash objs, only used when bufctls are off-slab */ +static kmem_cache_t cache_hash = { +/* freep, flags */ kmem_slab_end(&cache_hash), 0, +/* offset, hashp */ sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, NULL, +/* firstp, lastp */ kmem_slab_end(&cache_hash), kmem_slab_end(&cache_hash), +/* hashbits, num, gfporder */ 0, 0, 0, +/* org_size, magic */ sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE, SLAB_C_MAGIC, +/* inuse, ctor, dtor, align */ 0, kmem_hash_ctor, NULL, L1_CACHE_BYTES, +/* colour, colour_next */ 0, 0, +/* name, nextp */ "hash_cache", &cache_cache +}; + +/* internal cache of freelist mgmnt objs, only use when bufctls are off-slab */ +static kmem_cache_t cache_bufctl = { +/* freep, flags */ kmem_slab_end(&cache_bufctl), 0, +/* offset, hashp */ sizeof(kmem_bufctl_t), NULL, +/* firstp, lastp */ kmem_slab_end(&cache_bufctl), kmem_slab_end(&cache_bufctl), +/* hashbits, num, gfporder */ 0, 0, 0, +/* org_size, magic */ sizeof(kmem_bufctl_t), SLAB_C_MAGIC, +/* inuse, ctor, dtor, align */ 0, NULL, NULL, BYTES_PER_WORD*2, +/* colour, colour_next */ 0, 0, +/* name, nextp */ "bufctl_cache", &cache_hash +}; + +/* internal cache of slab mngmnt objs, only used when slab mgmt is off-slab */ +static kmem_cache_t cache_slab = { +/* freep, flags */ kmem_slab_end(&cache_slab), 0, +/* offset, hashp */ sizeof(kmem_slab_t), NULL, +/* firstp, lastp */ kmem_slab_end(&cache_slab), kmem_slab_end(&cache_slab), +/* hashbits, num, gfporder */ 0, 0, 0, +/* org_size, magic */ sizeof(kmem_slab_t), SLAB_C_MAGIC, +/* inuse, ctor, dtor, align */ 0, NULL, NULL, L1_CACHE_BYTES, +/* colour, colour_next */ 0, 0, +/* name, nextp */ "slab_cache", &cache_bufctl +}; + +/* internal cache of cache description objs */ +static kmem_cache_t cache_cache = { +/* freep, flags */ kmem_slab_end(&cache_cache), 0, +/* offset, hashp */ sizeof(kmem_cache_t), NULL, +/* firstp, lastp */ kmem_slab_end(&cache_cache), kmem_slab_end(&cache_cache), +/* hashbits, num, gfporder */ 0, 0, 0, +/* org_size, magic */ sizeof(kmem_cache_t), SLAB_C_MAGIC, +/* inuse, ctor, dtor, align */ 0, NULL, NULL, L1_CACHE_BYTES, +/* colour, colour_next */ 0, 0, +/* name */ "kmem_cache", +/* nextp */ &cache_slab +}; + +/* constructor for hash tables */ +static void kmem_hash_ctor(void *ptr, int size, unsigned long flags) +{ + memset(ptr, 0, sizeof(kmem_bufctl_t*)*KMEM_HASH_SIZE); +} + +/* place maintainer for reaping */ +static kmem_cache_t *clock_searchp = &cache_cache; + +/* Init an internal cache */ +static void +kmem_own_cache_init(kmem_cache_t *cachep) +{ + unsigned long size, i; + + if (cachep->c_inuse || cachep->c_magic != SLAB_C_MAGIC) { + panic("Bad init of internal cache %s", cachep->c_name); + /* NOTREACHED */ + } + size = cachep->c_offset + kmem_bufctl_short_size; + i = size % cachep->c_align; + if (i) + size += (cachep->c_align-i); + cachep->c_offset = size-kmem_bufctl_short_size; + + i = ((PAGE_SIZE<c_gfporder)-sizeof(kmem_slab_t)); + cachep->c_num = i / size; /* num of objs per slab */ + + /* cache colouring */ + cachep->c_colour = 1 + (i-(cachep->c_num*size))/cachep->c_align; + cachep->c_colour_next = cachep->c_colour; +} + +/* Initialisation - setup all internal caches */ +long +kmem_cache_init(long start, long end) +{ + /* sanity */ +#define kmem_cache_offset(x) ((unsigned long)&((kmem_cache_t *)0)->x) +#define kmem_slab_offset(x) ((unsigned long)&((kmem_slab_t *)0)->x) + if (((kmem_cache_offset(c_magic)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_magic)) || + ((kmem_cache_offset(c_inuse)-kmem_cache_offset(c_firstp)) != kmem_slab_offset(s_inuse))) { + /* Offsets to the magic are incorrect, either the structures have + * been incorrectly changed, or adjustments are needed for your + * architecture. + */ + panic("kmem_cache_init(): Offsets are different - been messed with!\n"); + /* NOTREACHED */ + } +#undef kmem_cache_offset +#undef kmem_slab_offset + + kmem_own_cache_init(&cache_cache); + kmem_own_cache_init(&cache_slab); + kmem_own_cache_init(&cache_bufctl); + kmem_own_cache_init(&cache_hash); + return start; +} + +/* Initialisation - setup general caches */ +void +kmem_cache_sizes_init(void) +{ + unsigned long i; + + i = sizeof(cache_sizes)/sizeof(cache_sizes[0])-1; + while (i--) + cache_sizes[i].cs_cachep = kmem_cache_create(cache_sizes_name[i], + cache_sizes[i].cs_size, + 0, 0, NULL, NULL); +} + +/* Interface to system's page allocator. + * dma pts to non-zero if all of the mem is suitable for DMA + */ +static inline void * +kmem_getpages(const kmem_cache_t *cachep, unsigned long flags, unsigned int *dma) +{ + struct page *page; + void *addr; + + addr = (void*) __get_free_pages(flags & SLAB_LEVEL_MASK, \ + cachep->c_gfporder, flags & SLAB_DMA); + *dma = 1<c_gfporder; + if (!(flags & SLAB_DMA) && addr) { + /* need to check if can dma */ + page = mem_map + MAP_NR(addr); + while ((*dma)--) { + if (!PageDMA(page)) { + *dma = 0; + break; + } + page++; + } + } + return addr; +} + +/* Interface to system's page release */ +static inline void +kmem_freepages(kmem_cache_t *cachep, void *addr) +{ + free_pages((unsigned long)addr, cachep->c_gfporder); +} + +/* Hashing function - used for caches with off-slab bufctls */ +static inline int +kmem_hash(const kmem_cache_t *cachep, const void *objp) +{ + return (((unsigned long)objp >> cachep->c_hashbits) & (KMEM_HASH_SIZE-1)); +} + +/* Link bufctl into a hash table - used for caches with off-slab bufctls + * - called with ints disabled + */ +static inline void * +kmem_add_to_hash(kmem_cache_t *cachep, kmem_bufctl_t *bufp) +{ + kmem_bufctl_t **bufpp = bufp->buf_hashp; + + bufp->buf_hnextp = *bufpp; + return (*bufpp = bufp)->buf_objp; +} + +/* Find bufcntl for given obj addr, and unlink. + * - called with ints disabled + */ +static inline kmem_bufctl_t * +kmem_remove_from_hash(kmem_cache_t *cachep, const void *objp) +{ + kmem_bufctl_t *bufp; + kmem_bufctl_t **bufpp = &cachep->c_hashp[kmem_hash(cachep, objp)]; + + for (;*bufpp; bufpp = &(*bufpp)->buf_hnextp) { + if ((*bufpp)->buf_objp != objp) + continue; + bufp = *bufpp; + *bufpp = bufp->buf_hnextp; + return bufp; + } + return NULL; +} + +/* Three slab chain funcs - all called with ints disabled */ +static inline void +kmem_slab_unlink(kmem_slab_t *slabp) +{ + kmem_slab_t *prevp = slabp->s_prevp; + kmem_slab_t *nextp = slabp->s_nextp; + + prevp->s_nextp = nextp; + nextp->s_prevp = prevp; +} + +static inline void +kmem_slab_link_end(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + slabp->s_nextp = kmem_slab_end(cachep); + slabp->s_prevp = cachep->c_lastp; + kmem_slab_end(cachep)->s_prevp = slabp; + slabp->s_prevp->s_nextp = slabp; +} + +static inline void +kmem_slab_link_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + kmem_slab_t *nextp = cachep->c_freep; + + slabp->s_nextp = nextp; + cachep->c_freep = slabp; + slabp->s_prevp = nextp->s_prevp; + nextp->s_prevp = slabp; + slabp->s_prevp->s_nextp = slabp; +} + +/* Cal the num objs, wastage, and bytes left over for a given slab size */ +static int +kmem_cache_cal_waste(unsigned long gfporder, unsigned long size, + unsigned long extra, unsigned long flags, + unsigned long *left_over, unsigned long *num) +{ + unsigned long wastage; + + wastage = PAGE_SIZE << gfporder; + gfporder = 0; + if (!SLAB_OFF_SLAB(flags)) + gfporder = sizeof(kmem_slab_t); + wastage -= gfporder; + *num = wastage / size; + wastage -= (*num * size); + *left_over = wastage; + + wastage += (extra * *num); + wastage += gfporder; + + return wastage; +} + +/* Create a cache + * Returns a ptr to the cache on success, NULL on failure. + * Cannot be called within a int, but can be interrupted. + * NOTE: The 'name' is assumed to be memory that is _not_ going to disappear. + */ +kmem_cache_t * +kmem_cache_create(const char *name, unsigned long size, unsigned long align, + unsigned long flags, void (*ctor)(void*, int, unsigned long), + void (*dtor)(void*, int, unsigned long)) +{ + const char *func_nm="kmem_create: "; + kmem_cache_t *searchp, *cachep; + unsigned long words, i; + unsigned long num, left_over; + + /* sanity checks */ +#if defined(SLAB_MGMT_CHECKS) + if (!name) { + printk(KERN_ERR "%sNULL ptr\n", func_nm); + return NULL; + } + if (intr_count) { + printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name); + return NULL; + } + + if (size < kmem_bufctl_very_short_size) { + printk(KERN_WARNING "%sSize too small %lu - %s\n", func_nm, size, name); + size = kmem_bufctl_very_short_size; + } + + if (size > ((1<= size) { + printk(KERN_WARNING "%sAlign weired %lu - %s\n", func_nm, align, name); + align = 0; + } + + if (dtor && !ctor) { + /* Descon, but no con - doesn't make sense */ + printk(KERN_ERR "%sDecon but no con - %s\n", func_nm, name); + return NULL; + } + + if ((flags & SLAB_DEBUG_INITIAL) && !ctor) { + /* No constructor, but inital state check requested */ + printk(KERN_WARNING "%sNo con, but init state check requested - %s\n", + func_nm, name); + flags &= ~SLAB_DEBUG_INITIAL; + } +#endif /* SLAB_MGMT_CHECKS */ + + /* get cache's description obj */ + cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL); + if (!cachep) + goto opps; + + /* remember original size, so can be passed to a constructor or decon. + * Allows the same con/decon to be used for caches of similar objs + * that have a different size data buffer assoicated with them + */ + cachep->c_org_size = size; + +#if defined(SLAB_DEBUG_SUPPORT) + if (flags & SLAB_RED_ZONE) + size += BYTES_PER_WORD; /* word for redzone */ +#endif /* SLAB_DEBUG_SUPPORT */ + + /* Make a guess if slab mngmnt obj and/or bufctls are 'on' or 'off' slab */ + i = kmem_bufctl_short_size; + if (size < (PAGE_SIZE>>3)) { + /* Size is small(ish). Use format where bufctl size per + * obj is low, and slab mngmnt is on-slab + */ + if (!ctor && !dtor && !(flags & SLAB_RED_ZONE)) { + /* the objs in this cache have no state - can store + * store freelist ptr within obj. (redzoning is a state) + */ +#if defined(SLAB_HIGH_PACK) + i=0; + flags |= SLAB_CFLGS_PTR_IN_OBJ; +#else + i = kmem_bufctl_very_short_size; +#endif + } + } else { + /* Size is large, assume best to place the slab mngmnt obj + * off-slab (should allow better packing of objs) + */ + flags |= SLAB_CFLGS_OFF_SLAB; + if (!(size & ~PAGE_MASK) || + size == (PAGE_SIZE+PAGE_SIZE/2) || + size == (PAGE_SIZE/2) || + size == (PAGE_SIZE/4) || + size == (PAGE_SIZE/8)) { + /* to avoid waste the bufctls are off-slab */ + flags |= SLAB_CFLGS_BUFCTL; + /* get hash table for cache */ + cachep->c_hashp = kmem_cache_alloc(&cache_hash, SLAB_KERNEL); + if (cachep->c_hashp == NULL) { + kmem_cache_free(&cache_cache, cachep); + goto opps; + } + i = 0; + cachep->c_hashbits = PAGE_SHIFT; + if (size <= (PAGE_SIZE/2)) { + cachep->c_hashbits--; + if (size <= (PAGE_SIZE/4)) cachep->c_hashbits--; + if (size <= (PAGE_SIZE/8)) cachep->c_hashbits -= 2; + } + } /* else slab mngmnt is off-slab, but freelist ptrs are on */ + } + size += i; + + /* Adjust the mem used for objs so they will align correctly. + * Force objs to start on word boundaries, but caller may specify + * h/w cache line boundaries. This 'alignment' is slightly different + * to the 'align' argument. Objs may be requested to start on h/w + * lines (as that is how the members of the obj have been organised), + * but the 'align' may be quite high (say 64) as the first 64 bytes + * are commonly accessed/modified within a loop (stops h/w line + * thrashing). The 'align' is the slab colouring. + */ + words = BYTES_PER_WORD; + if (flags & SLAB_HWCACHE_ALIGN) + words = L1_CACHE_BYTES; + words--; + size += words; + size = size & ~words; + /* alignment might not be a factor of the boundary alignment - fix-up */ + align += words; + align = align & ~words; + + + /* Cal size (in pages) of slabs, and the num of objs per slab. + * This could be made much more intelligent. */ + cachep->c_gfporder=0; + do { + unsigned long wastage; + wastage = kmem_cache_cal_waste(cachep->c_gfporder, size, i, + flags, &left_over, &num); + if (!num) + goto next; + if (SLAB_PTR_IN_OBJ(flags)) + break; + if (cachep->c_gfporder == SLAB_MAX_GFP_ORDER) + break; + /* large num of objs is good, but v. large slabs are bad for the + * VM sub-system + */ + if (num <= SLAB_MIN_OBJS_PER_SLAB) { + if (cachep->c_gfporder < SLAB_BREAK_GFP_ORDER) + goto next; + } + /* stop caches with small objs having a large num of pages */ + if (left_over <= sizeof(kmem_slab_t)) + break; + if ((wastage*8) <= (PAGE_SIZE<c_gfporder)) + break; /* acceptable wastage */ +next: + cachep->c_gfporder++; + } while (1); + cachep->c_num = num; + + /* try with requested alignment, but reduce it if that will + * allow at least some alignment words + */ + words++; + if (left_over < align) + align = (left_over / words) * words; + else if (!align && words <= left_over) { + /* no alignment given, but space enough - give one */ + align = words; + if (words == BYTES_PER_WORD) { + if (BYTES_PER_WORD*4 <= left_over) + align += align; + if (BYTES_PER_WORD*8 <= left_over) + align += align; + } + } + cachep->c_align = align; + +#if 0 + printk("Size:%lu Orig:%lu Left:%lu Align %lu Pages:%d - %s\n", + size, cachep->c_org_size, left_over, align, 1<c_gfporder, name); + if (SLAB_OFF_SLAB(flags)) printk("OFF SLAB\n"); + if (SLAB_BUFCTL(flags)) printk("BUFCTL PTRS\n"); +#endif + + /* if the bufctl's are on-slab, c_offset does not inc the size of the bufctl */ + if (!SLAB_BUFCTL(flags)) + size -= kmem_bufctl_short_size; + cachep->c_freep = kmem_slab_end(cachep); + cachep->c_flags = flags; + cachep->c_offset = size; + cachep->c_firstp = kmem_slab_end(cachep); + cachep->c_lastp = kmem_slab_end(cachep); + cachep->c_ctor = ctor; + cachep->c_dtor = dtor; + cachep->c_magic = SLAB_C_MAGIC; + cachep->c_inuse = 0; /* always zero */ + cachep->c_name = name; /* simply point to the name */ + + cachep->c_colour = 1; + if (align) + cachep->c_colour += (left_over/align); + cachep->c_colour_next = cachep->c_colour; + + /* warn on dup cache names */ + searchp = &cache_cache; + do { + if (!strcmp(searchp->c_name, name)) { + printk(KERN_WARNING "%sDup name - %s\n", func_nm, name); + break; + } + searchp = searchp->c_nextp; + } while (searchp != &cache_cache); + cachep->c_nextp = cache_cache.c_nextp; + cache_cache.c_nextp = cachep; + return cachep; +opps: + printk(KERN_WARNING "%sOut of mem creating cache %s\n", func_nm, name); + return NULL; +} + +/* Destroy all the objs in a slab, and release the mem back to the system. + * Before calling the slab must have been unlinked + */ +static void +kmem_slab_destroy(kmem_cache_t *cachep, kmem_slab_t *slabp, unsigned long flags) +{ + if (cachep->c_dtor || SLAB_BUFCTL(cachep->c_flags)) { + kmem_bufctl_t *bufp = slabp->s_freep; + + /* for each obj in slab... */ + while (bufp) { + kmem_bufctl_t *freep; + if (cachep->c_dtor) { + void *objp = ((void*)bufp)-cachep->c_offset; + if (SLAB_BUFCTL(cachep->c_flags)) + objp = bufp->buf_objp; + (cachep->c_dtor)(objp, cachep->c_org_size, flags); + } + freep = bufp; + bufp = bufp->buf_nextp; + if (SLAB_BUFCTL(cachep->c_flags)) + kmem_cache_free(&cache_bufctl, freep); + } + } + + slabp->s_magic = SLAB_MAGIC_UNALLOC; + kmem_freepages(cachep, slabp->s_mem); + if (SLAB_OFF_SLAB(cachep->c_flags)) + kmem_cache_free(&cache_slab, slabp); +} + +/* Destroy (remove) a cache. + * All objs in the cache should be inactive + */ +int +kmem_cache_destroy(kmem_cache_t *cachep) +{ + kmem_cache_t **searchp; + kmem_slab_t *slabp; + unsigned long save_flags; + +#if defined(SLAB_MGMT_CHECKS) + if (!cachep) { + printk(KERN_ERR "kmem_dest: NULL ptr\n"); + goto err_end; + } + + if (intr_count) { + printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name); +err_end: + return 1; + } +#endif /* SLAB_MGMT_CHECKS */ + + /* unlink the cache from the chain of active caches. + * Note: the chain is never modified during an int + */ + searchp = &(cache_cache.c_nextp); + for (;*searchp != &cache_cache; searchp = &((*searchp)->c_nextp)) { + if (*searchp != cachep) + continue; + goto good_cache; + } + printk(KERN_ERR "kmem_dest: Invalid cache addr %p\n", cachep); + return 1; +good_cache: + /* disable cache so attempts to allocated from an int can + * be caught. + */ + save_flags(save_flags); + cli(); + if (cachep->c_freep != kmem_slab_end(cachep)) { + restore_flags(save_flags); + printk(KERN_ERR "kmem_dest: active cache - %s\n", cachep->c_name); + return 2; + } + *searchp = cachep->c_nextp; /* remove from cache chain */ + cachep->c_flags |= SLAB_CFLGS_RELEASED; + cachep->c_freep = kmem_slab_end(cachep); + if (cachep == clock_searchp) + clock_searchp = cachep->c_nextp; + restore_flags(save_flags); + + while ((slabp = cachep->c_firstp) != kmem_slab_end(cachep)) { + kmem_slab_unlink(slabp); + kmem_slab_destroy(cachep, slabp, 0); + } + + if (SLAB_BUFCTL(cachep->c_flags)) + kmem_cache_free(&cache_hash, cachep->c_hashp); + kmem_cache_free(&cache_cache, cachep); + return 0; +} + +/* Shrink a cache, ie. remove _all_ inactive slabs. + * Can be called when a user of a cache knows they are not going to be + * needing any new objs for a while. + * NOTE: This func is probably going to disappear - let me know if you + * are using it! + */ +int +kmem_cache_shrink(kmem_cache_t *cachep, int wait) +{ + kmem_slab_t *slabp; + unsigned long dtor_flags; + unsigned long save_flags, num_freed=0; + +#if defined(SLAB_MGMT_CHECKS) + if (!cachep) { + printk(KERN_ERR "kmem_shrink: NULL ptr\n"); + goto end; + } + + if (intr_count) { + printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name); + goto end; + } +#endif /* SLAB_MGMT_CHECKS */ + + dtor_flags = 0; + if (!wait) /* not allowed to wait */ + dtor_flags = SLAB_DTOR_ATOMIC; + + save_flags(save_flags); + while (0) { + cli(); + slabp = cachep->c_lastp; + if (slabp == kmem_slab_end(cachep) || slabp->s_inuse) { + restore_flags(save_flags); + goto end; + } + kmem_slab_unlink(slabp); + if (cachep->c_freep == slabp) + cachep->c_freep = kmem_slab_end(cachep); + restore_flags(save_flags); + num_freed++; + kmem_slab_destroy(cachep, slabp, dtor_flags); + } +end: + return num_freed; +} + +/* Search for a slab whose objs are suitable for DMA. + * Note: since testing the first free slab (in __kmem_cache_alloc()), + * ints must not have been enabled! + */ +static inline kmem_slab_t * +kmem_cache_search_dma(kmem_cache_t *cachep) +{ + kmem_slab_t *slabp = cachep->c_freep->s_nextp; + + for (; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) { + if (!(slabp->s_flags & SLAB_SFLGS_DMA)) + continue; + kmem_slab_unlink(slabp); + kmem_slab_link_free(cachep, slabp); + return slabp; + } + return NULL; +} + +/* get the mem for a slab mgmt obj */ +static inline kmem_slab_t * +kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, unsigned long local_flags, unsigned long offset) +{ + kmem_slab_t *slabp; + + if (SLAB_OFF_SLAB(cachep->c_flags)) { + /* slab mngmnt obj is off-slab */ + if (!(slabp = kmem_cache_alloc(&cache_slab, local_flags))) + return NULL; + } else { + /* slab mngmnt at end of slab mem */ + slabp = objp + (PAGE_SIZE << cachep->c_gfporder); + slabp--; + if (!SLAB_PTR_IN_OBJ(cachep->c_flags)) { + /* A bit of extra help for the L1 cache; try to position the slab + * mgmnt struct at different offsets within the gap at the end + * of a slab. This helps avoid thrashing the h/w cache lines, + * that map to the end of a page, too much... + */ + unsigned long gap = cachep->c_offset; + if (!SLAB_BUFCTL(cachep->c_flags)) + gap += kmem_bufctl_short_size; + gap = (PAGE_SIZE << cachep->c_gfporder)-((gap*cachep->c_num)+offset+sizeof(*slabp)); + gap /= (sizeof(*slabp)/2); + gap *= (sizeof(*slabp)/2); + slabp = (((void*)slabp)-gap); + } + } + + slabp->s_flags = slabp->s_inuse = slabp->s_jiffies = 0; + + return slabp; +} + +static inline int +kmem_cache_init_objs(kmem_cache_t *cachep, kmem_slab_t *slabp, void *objp, + unsigned long local_flags, unsigned long ctor_flags) +{ + kmem_bufctl_t **bufpp = &slabp->s_freep; + unsigned long num = cachep->c_num; + + do { + if (SLAB_BUFCTL(cachep->c_flags)) { + if (!(*bufpp = kmem_cache_alloc(&cache_bufctl, local_flags))) { + kmem_slab_destroy(cachep, slabp, 0); + return 1; + } + (*bufpp)->buf_objp = objp; + (*bufpp)->buf_hashp = &cachep->c_hashp[kmem_hash(cachep, objp)]; + } + + if (cachep->c_ctor) + cachep->c_ctor(objp, cachep->c_org_size, ctor_flags); + +#if defined(SLAB_DEBUG_SUPPORT) + if (cachep->c_flags & SLAB_RED_ZONE) + *((unsigned long*)(objp+cachep->c_org_size)) = SLAB_RED_MAGIC1; +#endif /* SLAB_DEBUG_SUPPORT */ + + objp += cachep->c_offset; + if (!SLAB_BUFCTL(cachep->c_flags)) { + *bufpp = objp; + objp += kmem_bufctl_short_size; + } + if (!SLAB_PTR_IN_OBJ(cachep->c_flags)) + (*bufpp)->buf_slabp = slabp; + bufpp = &(*bufpp)->buf_nextp; + } while (--num); + *bufpp = NULL; + return 0; +} + +/* Grow (by 1) the number of slabs within a cache. + * This is called by kmem_cache_alloc() when there are no + * inactive objs left in a cache + */ +static void +kmem_cache_grow(kmem_cache_t *cachep, unsigned long flags) +{ + kmem_slab_t *slabp; + void *objp; + unsigned int offset, dma; + unsigned long ctor_flags, local_flags, save_flags; + + if (flags & SLAB_NO_GROW) + return; /* caller doesn't want us to grow */ + + save_flags(save_flags); + /* The test for missing atomic flag is performed here, rather than + * the more obvious place, simply to reduce the critical path length + * in kmem_cache_alloc(). If a caller is slightly mis-behaving, + * will eventually be caught here (where it matters) + */ + if (intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) { + static int count = 0; + if (count < 8) { + printk(KERN_ERR "kmem_grow: Called nonatomically from " + "int - %s\n", cachep->c_name); + count++; + } + flags &= ~SLAB_LEVEL_MASK; + flags |= SLAB_ATOMIC; + } + local_flags = (flags & SLAB_LEVEL_MASK); + ctor_flags = SLAB_CTOR_CONSTRUCTOR; + if ((flags & SLAB_LEVEL_MASK) == SLAB_ATOMIC) { + /* Not allowed to sleep. + * Need to tell a constructor about this - it + * might need to know.... + */ + ctor_flags |= SLAB_CTOR_ATOMIC; + } + + slabp = NULL; + /* get mem for the objs */ + if (!(objp = kmem_getpages(cachep, flags, &dma))) + goto opps1; + + /* get colour for the slab, and cal the next value */ + cli(); + if (!(offset = --(cachep->c_colour_next))) + cachep->c_colour_next = cachep->c_colour; + restore_flags(save_flags); + offset *= cachep->c_align; + + /* get slab mgmt */ + if (!(slabp = kmem_cache_slabmgmt(cachep, objp, local_flags, offset))) + goto opps2; + if (dma) + slabp->s_flags = SLAB_SFLGS_DMA; + + slabp->s_mem = objp; + objp += offset; /* address of first object */ + + /* For on-slab bufctls, c_offset is the distance between the start of + * an obj and its related bufctl. For off-slab bufctls, c_offset is + * the distance between objs in the slab. + * Reason for bufctl at end of obj (when on slab), as opposed to the front; + * if stored within the obj (has no state), and the obj is 'used' after being + * freed then (normally) most activity occurs at the beginning of the obj. + * By keeping the bufctl ptr away from the front, should reduce the chance of + * corruption. Also, allows easier alignment of objs onto cache lines when + * bufctl is not stored with the objs. + * Downsize; if, while an obj is active, a write is made past its end, then the + * bufctl will be corrupted :( + */ + if (kmem_cache_init_objs(cachep, slabp, objp, local_flags, ctor_flags)) + goto no_objs; + + cli(); + /* make slab active */ + slabp->s_magic = SLAB_MAGIC_ALLOC; + kmem_slab_link_end(cachep, slabp); + if (cachep->c_freep == kmem_slab_end(cachep)) + cachep->c_freep = slabp; + restore_flags(save_flags); + return; +no_objs: + kmem_freepages(cachep, slabp->s_mem); +opps2: + kmem_freepages(cachep, objp); +opps1: + if (slabp && SLAB_OFF_SLAB(cachep->c_flags)) + kmem_cache_free(&cache_slab, slabp); + /* printk("kmem_alloc: Out of mem - %s\n", cachep->c_name); */ + return; +} + +#if defined(SLAB_DEBUG_SUPPORT) +/* Perform extra freeing checks. + * Currently, this check is only for caches that use bufctl structures + * within the slab. Those which use bufctl's from the internal cache + * have a reasonable check when the address is searched for. + */ +static void * +kmem_extra_free_checks(const kmem_cache_t *cachep, kmem_bufctl_t *search_bufp, + const kmem_bufctl_t *bufp, void * objp) +{ + if (SLAB_BUFCTL(cachep->c_flags)) + goto end; + + /* check slab's freelist to see if this obj is there */ + for (; search_bufp; search_bufp = search_bufp->buf_nextp) { + if (search_bufp != bufp) + continue; + printk(KERN_ERR "kmem_free: Double free detected during checking " + "%p - %s\n", objp, cachep->c_name); + return NULL; + } +end: + return objp; +} +#endif /* SLAB_DEBUG_SUPPORT */ + +static inline void +kmem_cache_full_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + if (!slabp->s_nextp->s_inuse) + return; /* at correct position */ + slabp->s_jiffies = jiffies; /* set release time */ + if (cachep->c_freep == slabp) + cachep->c_freep = slabp->s_nextp; + kmem_slab_unlink(slabp); + kmem_slab_link_end(cachep, slabp); + + return; +} + +static inline void +kmem_cache_one_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + if (slabp->s_nextp->s_inuse != cachep->c_num) { + cachep->c_freep = slabp; + return; + } + kmem_slab_unlink(slabp); + kmem_slab_link_free(cachep, slabp); + return; +} + +/* Returns a ptr to an obj in the given cache. + * The obj is in the initial state (if there is one) + */ +static inline void * +__kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags) +{ + kmem_slab_t *slabp; + kmem_bufctl_t *bufp; + void *objp; + unsigned long save_flags; + + /* sanity check */ + if (!cachep) + goto nul_ptr; + save_flags(save_flags); + cli(); + /* get slab alloc is to come from */ + slabp = cachep->c_freep; + + /* magic is a sanity check _and_ says if we need a new slab */ + if (slabp->s_magic != SLAB_MAGIC_ALLOC) + goto alloc_new_slab; +try_again: + /* DMA allocations are 'rare' - keep out of critical path */ + if (flags & SLAB_DMA) + goto search_dma; +try_again_dma: + slabp->s_inuse++; + bufp = slabp->s_freep; + slabp->s_freep = bufp->buf_nextp; + if (!SLAB_BUFCTL(cachep->c_flags)) { + /* Nasty - we want the 'if' to be taken in the common case */ + if (slabp->s_freep) { +short_finished: + objp = ((void*)bufp) - cachep->c_offset; + restore_flags(save_flags); +#if defined(SLAB_DEBUG_SUPPORT) + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; +#endif /* SLAB_DEBUG_SUPPORT */ + return objp; + } else { + cachep->c_freep = slabp->s_nextp; + goto short_finished; + } + } + + if (!slabp->s_freep) + cachep->c_freep = slabp->s_nextp; + + /* link into hash chain */ + objp = kmem_add_to_hash(cachep, bufp); + restore_flags(save_flags); +#if defined(SLAB_DEBUG_SUPPORT) + if (!(cachep->c_flags & SLAB_RED_ZONE)) +#endif /* SLAB_DEBUG_SUPPORT */ + return objp; + +#if defined(SLAB_DEBUG_SUPPORT) +red_zone: + /* set alloc red-zone, and check old one */ + if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1) + printk(KERN_ERR "kmem_alloc: Bad redzone %p - %s\n", + objp, cachep->c_name); + return objp; +#endif /* SLAB_DEBUG_SUPPORT */ + +search_dma: + if (slabp->s_flags & SLAB_SFLGS_DMA) + goto try_again_dma; + /* need to search... */ + if ((slabp = kmem_cache_search_dma(cachep))) + goto try_again_dma; +alloc_new_slab: + /* Either out of slabs, or magic number corruption */ + if (slabp != kmem_slab_end(cachep)) + goto bad_slab; + /* need a new slab */ + restore_flags(save_flags); + if (SLAB_RELEASED(cachep->c_flags)) { + printk(KERN_ERR "kmem_alloc: destroyed cache\n"); + goto end; + } + + /* Be lazy and only check for valid flags + * here (keeping it out of the critical path above) + */ + if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) { + printk(KERN_ERR "kmem_alloc: Illegal flgs %lX (correcting) - %s\n", + flags, cachep->c_name); + flags &= (SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW); + } + + kmem_cache_grow(cachep, flags); + cli(); + if ((slabp=cachep->c_freep) != kmem_slab_end(cachep)) + goto try_again; + restore_flags(save_flags); +end: + return NULL; +bad_slab: + /* v. serious error - maybe panic() here? */ + printk(KERN_ERR "kmem_alloc: Bad slab magic (corruption) - %s\n", + cachep->c_name); + goto end; +nul_ptr: + printk(KERN_ERR "kmem_alloc: NULL ptr\n"); + goto end; +} + +/* Release an obj back to its cache. + * If the obj has a constructed state, it should be + * in this state _before_ it is released. + */ +static inline void +__kmem_cache_free(kmem_cache_t *cachep, void *objp) +{ + kmem_slab_t *slabp; + kmem_bufctl_t *bufp; + unsigned long save_flags; + + /* basic sanity checks */ + if (!cachep) + goto nul_cache; + if (!objp) + goto nul_obj; + + save_flags(save_flags); +#if defined(SLAB_DEBUG_SUPPORT) + if (cachep->c_flags & SLAB_DEBUG_INITIAL) + goto init_state_check; +finished_initial: +#endif /* SLAB_DEBUG_SUPPORT */ + + if (SLAB_BUFCTL(cachep->c_flags)) + goto bufctl; + + bufp = (kmem_bufctl_t *)(objp+cachep->c_offset); + + /* get slab for the obj */ + if (SLAB_PTR_IN_OBJ(cachep->c_flags)) { + /* if SLAB_HIGH_PACK is undef, the below is optimised away */ + slabp = (kmem_slab_t *)((((unsigned long)objp)&PAGE_MASK)+PAGE_SIZE); + slabp--; + } else + slabp = (kmem_slab_t *) bufp->buf_slabp; + + if (slabp->s_magic != SLAB_MAGIC_ALLOC) /* sanity check */ + goto bad_obj; + cli(); + +#if defined(SLAB_DEBUG_SUPPORT) + if (cachep->c_flags & (SLAB_DEBUG_FREE|SLAB_RED_ZONE)) + goto extra_checks; +#endif /* SLAB_DEBUG_SUPPORT */ + +passed_extra: + if (!slabp->s_inuse) /* sanity check */ + goto too_many; + bufp->buf_nextp = slabp->s_freep; + slabp->s_freep = bufp; + if (--(slabp->s_inuse)) { + if (bufp->buf_nextp) { + restore_flags(save_flags); + return; + } + kmem_cache_one_free(cachep, slabp); + restore_flags(save_flags); + return; + } + kmem_cache_full_free(cachep, slabp); + restore_flags(save_flags); + return; +bufctl: + /* Off-slab bufctls. Need to search hash for bufctl, and hence the slab. + * No 'extra' checks are performed for objs stored this way, finding + * the obj a check enough + */ + cli(); + if ((bufp = kmem_remove_from_hash(cachep, objp))) { + slabp = (kmem_slab_t *) bufp->buf_slabp; +#if defined(SLAB_DEBUG_SUPPORT) + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; +#endif /* SLAB_DEBUG_SUPPORT */ + goto passed_extra; + } + restore_flags(save_flags); + printk(KERN_ERR "kmem_free: Either bad obj addr or double free: %p - %s\n", + objp, cachep->c_name); + return; +#if defined(SLAB_DEBUG_SUPPORT) +red_zone: + if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { + /* Either write past end of the object, or a double free */ + printk(KERN_ERR "kmem_free: Bad redzone %p - %s\n", + objp, cachep->c_name); + } + goto passed_extra; +init_state_check: + /* Need to call the slab's constructor so that + * the caller can perform a verify of its state (debugging) + */ + cachep->c_ctor(objp, cachep->c_org_size, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY); + goto finished_initial; +extra_checks: + if ((cachep->c_flags & SLAB_DEBUG_FREE) && + (objp != kmem_extra_free_checks(cachep, slabp->s_freep, bufp, objp))) { + restore_flags(save_flags); + return; + } + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; + goto passed_extra; +#endif /* SLAB_DEBUG_SUPPORT */ +bad_obj: + /* The addr of the slab doesn't contain the correct + * magic num + */ + if (slabp->s_magic == SLAB_MAGIC_UNALLOC) { + /* magic num says this is an unalloc slab */ + printk(KERN_ERR "kmem_free: obj %p from destroyed slab - %s\n", + objp, cachep->c_name); + return; + } + printk(KERN_ERR "kmem_free: Bad obj %p - %s\n", objp, cachep->c_name); + return; +too_many: + /* don't add to freelist */ + restore_flags(save_flags); + printk(KERN_ERR "kmem_free: obj free for slab with no active objs - %s\n", + cachep->c_name); + return; +nul_obj: + printk(KERN_ERR "kmem_free: NULL obj - %s\n", cachep->c_name); + return; +nul_cache: + printk(KERN_ERR "kmem_free: NULL cache ptr\n"); + return; +} + +void * +kmem_cache_alloc(kmem_cache_t *cachep, unsigned long flags) +{ + return __kmem_cache_alloc(cachep, flags); +} + +void +kmem_cache_free(kmem_cache_t *cachep, void *objp) +{ + __kmem_cache_free(cachep, objp); +} + +void * +kmem_alloc(unsigned long size, unsigned long flags) +{ + cache_sizes_t *cachep = cache_sizes; + + for (; cachep->cs_size; cachep++) { + if (size > cachep->cs_size) + continue; + /* should the inline version be used here? */ + return kmem_cache_alloc(cachep->cs_cachep, flags); + } + printk(KERN_ERR "kmem_alloc: Size (%lu) too large\n", size); + return NULL; +} + +void +kmem_free(void *objp, unsigned long size) +{ + cache_sizes_t *cachep = cache_sizes; + + for (; cachep->cs_size; cachep++) { + if (size > cachep->cs_size) + continue; + /* should the inline version be used here? */ + kmem_cache_free(cachep->cs_cachep, objp); + return; + } + printk(KERN_ERR "kmem_free: Size (%lu) too large - strange\n", size); +} + + + +/* Called from try_to_free_page(). + * Ideal solution would have a weight for each cache, based on; + * o num of fully free slabs + * o if the objs have a constructor/deconstructor + * o length of time slabs have been fully free (ie. ageing) + * This function _cannot_ be called within a int, but it + * can be interrupted. + */ +int +kmem_cache_reap(int pri, int dma, int wait) +{ + unsigned long dtor_flags = 0; + unsigned long best_jiffie; + unsigned long now; + int count = 8; + kmem_slab_t *best_slabp = NULL; + kmem_cache_t *best_cachep = NULL; + kmem_slab_t *slabp; + kmem_cache_t *searchp; + unsigned long save_flags; + + /* 'pri' maps to the number of caches to examine, not the number of slabs. + * This avoids only checking the jiffies for slabs in one cache at the + * expensive spending more cycles + */ + pri = (9 - pri); + if (!wait) /* not allowed to wait */ + dtor_flags = SLAB_DTOR_ATOMIC; + searchp = clock_searchp; + save_flags(save_flags); + now = jiffies; + best_jiffie = now - (2*HZ); /* 2secs - avoid heavy thrashing */ + while (pri--) { + kmem_slab_t *local_slabp; + unsigned long local_jiffie; + if (searchp == &cache_cache) + goto next; + + /* sanity check for corruption */ + if (searchp->c_inuse || searchp->c_magic != SLAB_C_MAGIC) { + printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", + searchp->c_name); + goto next; + } + + local_slabp = NULL; + local_jiffie = now - (2*HZ); + cli(); + /* As the fully free slabs, within a cache, have no particular + * order, we need to test them all. Infact, we only check 'count' + * slabs. + */ + slabp = searchp->c_lastp; + for (;count && slabp != kmem_slab_end(searchp) && !slabp->s_inuse; slabp = slabp->s_prevp, count--) { + if (slabp->s_jiffies >= local_jiffie) + continue; + + /* weight caches with a con/decon */ + if ((searchp->c_ctor || searchp->c_dtor) && slabp->s_jiffies >= (local_jiffie - (2*HZ))) + continue; + + /* weight caches with high page orders. Avoids stressing the + * VM sub-system by reducing the frequency requests for a large + * num of contigious pages + */ + if (searchp->c_gfporder > 1 && slabp->s_jiffies >= (local_jiffie - (4*HZ))) + continue; + + local_jiffie = slabp->s_jiffies; + local_slabp = slabp; + if (!searchp->c_gfporder && (now-local_jiffie) >= (300*HZ)) { + /* an old, one page slab. Make a quick get away... */ + pri = 0; + break; + } + } + if (local_slabp) { + if (!count || local_jiffie < best_jiffie) { + best_slabp = local_slabp; + best_jiffie = local_jiffie; + best_cachep = searchp; + if (!count) + break; + } + } + restore_flags(save_flags); +next: + searchp = searchp->c_nextp; + if (searchp == clock_searchp) + break; + count = 8; /* # of slabs at which we force a reap */ + } + + /* only move along with we didn't find an over allocated cache */ + if (count) + clock_searchp = clock_searchp->c_nextp; + + if (!best_slabp) + return 0; + + cli(); + if (best_slabp->s_inuse) { + /* an object in our selected slab has been + * allocated. This souldn't happen v. often, so we + * simply fail - which isn't ideal but will do. + * NOTE: No test for the case where an obj has been + * allocated from the slab, and then freed. While + * this would change our idea of the best slab to + * reap, it's not worth the re-calculation effort. + */ + restore_flags(save_flags); + return 0; + } + + if (best_cachep->c_freep == best_slabp) + best_cachep->c_freep = best_slabp->s_nextp; + kmem_slab_unlink(best_slabp); + + restore_flags(save_flags); + kmem_slab_destroy(best_cachep, best_slabp, dtor_flags); + + return 1; +} + +/* /proc/slabinfo + * cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab + */ +int +get_slabinfo(char *buf) +{ + kmem_cache_t *cachep; + kmem_slab_t *slabp; + unsigned long active_objs; + unsigned long num_slabs, active_slabs; + unsigned long save_flags; + int len=0; + + /* output format version, so at least we can change it without _too_ + * many complaints + */ + len = sprintf(buf, "slabinfo - version: 1.0\n"); + save_flags(save_flags); + cachep = &cache_cache; + do { + active_slabs = num_slabs = active_objs = 0; + cli(); + for (slabp = cachep->c_firstp; + slabp != kmem_slab_end(cachep); + slabp = slabp->s_nextp) { + num_slabs++; + active_objs += slabp->s_inuse; + if (slabp->s_inuse) + active_slabs++; + } + restore_flags(save_flags); + len += sprintf(buf+len, "%-20s%lu %lu %lu %lu %d\n", cachep->c_name, + active_objs, cachep->c_num*num_slabs, + active_slabs, num_slabs, 1<c_gfporder); + } while ((cachep = cachep->c_nextp) != &cache_cache); + return len; +} diff --git a/mm/swapfile.c b/mm/swapfile.c index dae1d52092aa..d8c72a61c604 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include #include @@ -319,17 +321,18 @@ static int try_to_unuse(unsigned int type) asmlinkage int sys_swapoff(const char * specialfile) { - struct swap_info_struct * p; + struct swap_info_struct * p = NULL; struct inode * inode; struct file filp; int i, type, prev; - int err; + int err = -EPERM; + lock_kernel(); if (!suser()) - return -EPERM; + goto out; err = namei(specialfile,&inode); if (err) - return err; + goto out; prev = -1; for (type = swap_list.head; type >= 0; type = swap_info[type].next) { p = swap_info + type; @@ -345,9 +348,10 @@ asmlinkage int sys_swapoff(const char * specialfile) } prev = type; } + err = -EINVAL; if (type < 0){ iput(inode); - return -EINVAL; + goto out; } if (prev < 0) { swap_list.head = p->next; @@ -372,7 +376,7 @@ asmlinkage int sys_swapoff(const char * specialfile) else swap_info[prev].next = p - swap_info; p->flags = SWP_WRITEOK; - return err; + goto out; } if(p->swap_device){ memset(&filp, 0, sizeof(filp)); @@ -396,7 +400,10 @@ asmlinkage int sys_swapoff(const char * specialfile) free_page((long) p->swap_lockmap); p->swap_lockmap = NULL; p->flags = 0; - return 0; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -410,19 +417,20 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) struct inode * swap_inode; unsigned int type; int i, j, prev; - int error; + int error = -EPERM; struct file filp; static int least_priority = 0; - memset(&filp, 0, sizeof(filp)); + lock_kernel(); if (!suser()) - return -EPERM; + goto out; + memset(&filp, 0, sizeof(filp)); p = swap_info; for (type = 0 ; type < nr_swapfiles ; type++,p++) if (!(p->flags & SWP_USED)) break; if (type >= MAX_SWAPFILES) - return -EPERM; + goto out; if (type >= nr_swapfiles) nr_swapfiles = type+1; p->flags = SWP_USED; @@ -538,7 +546,8 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) } else { swap_info[prev].next = p - swap_info; } - return 0; + error = 0; + goto out; bad_swap: if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_inode,&filp); @@ -551,6 +560,8 @@ bad_swap_2: p->swap_map = NULL; p->swap_lockmap = NULL; p->flags = 0; +out: + unlock_kernel(); return error; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 6ff7e0c398b4..19505533ca47 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -5,7 +5,7 @@ * * Swap reorganised 29.12.95, Stephen Tweedie. * kswapd added: 7.1.96 sct - * Version: $Id: vmscan.c,v 1.4.2.2 1996/01/20 18:22:47 linux Exp $ + * Version: $Id: vmscan.c,v 1.21 1997/01/06 06:54:03 davem Exp $ */ #include @@ -20,6 +20,7 @@ #include #include #include +#include #include #include /* for cli()/sti() */ @@ -347,9 +348,13 @@ int try_to_free_page(int priority, int dma, int wait) return 1; state = 1; case 1: - if (shm_swap(i, dma)) + if (kmem_cache_reap(i, dma, wait)) return 1; state = 2; + case 2: + if (shm_swap(i, dma)) + return 1; + state = 3; default: if (swap_out(i, dma, wait)) return 1; @@ -368,7 +373,7 @@ int try_to_free_page(int priority, int dma, int wait) int kswapd(void *unused) { int i; - char *revision="$Revision: 1.4.2.2 $", *s, *e; + char *revision="$Revision: 1.21 $", *s, *e; current->session = 1; current->pgrp = 1; @@ -380,11 +385,7 @@ int kswapd(void *unused) * and other internals and thus be subject to the SMP locking * rules. (On a uniprocessor box this does nothing). */ - -#ifdef __SMP__ lock_kernel(); - syscall_count++; -#endif /* Give kswapd a realtime priority. */ current->policy = SCHED_FIFO; diff --git a/net/802/Makefile b/net/802/Makefile index c32b0950618c..d4522a2d32fc 100644 --- a/net/802/Makefile +++ b/net/802/Makefile @@ -13,7 +13,7 @@ O_OBJS = p8023.o sysctl_net_802.o ifeq ($(CONFIG_LLC),y) SUB_DIRS += transit O_OBJS += llc_sendpdu.o llc_utility.o cl2llc.o -OX_OBJS += llc_macinit.o +OX_OBJS += llc_macinit.o endif diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index cdbbba3fd1dd..d996796913f2 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1778,7 +1778,7 @@ static struct proto_ops atalk_dgram_ops = { atalk_socketpair, atalk_accept, atalk_getname, - datagram_select, + datagram_poll, atalk_ioctl, atalk_listen, atalk_shutdown, diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 4b69a7dafce3..3bce00326a79 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -2385,7 +2385,7 @@ static struct proto_ops ax25_proto_ops = { ax25_socketpair, ax25_accept, ax25_getname, - datagram_select, + datagram_poll, ax25_ioctl, ax25_listen, ax25_shutdown, diff --git a/net/core/scm.c b/net/core/scm.c index 481f69f4f157..3aa0c7b173f7 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -8,7 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/net/core/sock.c b/net/core/sock.c index bd08736d495c..66b76998b5ed 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -95,6 +95,7 @@ #include #include #include +#include #include #include @@ -367,6 +368,8 @@ int sock_getsockopt(struct socket *sock, int level, int optname, return err; } +static kmem_cache_t *sk_cachep; + /* * All socket objects are allocated here. This is for future * usage. @@ -374,16 +377,22 @@ int sock_getsockopt(struct socket *sock, int level, int optname, struct sock *sk_alloc(int priority) { - struct sock *sk=(struct sock *)kmalloc(sizeof(*sk), priority); - if(!sk) - return NULL; - memset(sk, 0, sizeof(*sk)); + struct sock *sk = kmem_cache_alloc(sk_cachep, priority); + + if(sk) + memset(sk, 0, sizeof(struct sock)); return sk; } void sk_free(struct sock *sk) { - kfree_s(sk,sizeof(*sk)); + kmem_cache_free(sk_cachep, sk); +} + +void sk_init(void) +{ + sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0, + SLAB_HWCACHE_ALIGN, 0, 0); } /* diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index c5765982faff..547df2bacfbd 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -300,15 +300,14 @@ void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned c hh->hh_uptodate = 1; } +#ifndef CONFIG_IP_ROUTER + /* * Copy from an ethernet device memory space to an sk_buff while checksumming if IP */ void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base) { -#ifdef CONFIG_IP_ROUTER - memcpy(dest->data,src,length); -#else struct ethhdr *eth; struct iphdr *iph; int ip_length; @@ -337,5 +336,6 @@ void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int dest->csum=csum_partial_copy(src+sizeof(struct iphdr)+ETH_HLEN,dest->data+sizeof(struct iphdr)+ETH_HLEN,length,base); dest->ip_summed=1; -#endif } + +#endif /* !(CONFIG_IP_ROUTER) */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8a95ece71f41..e10c9fce012d 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1375,7 +1375,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) struct rtable *rt; unsigned char *sha, *tha; u32 sip, tip; - + /* * The hardware length of the packet should match the hardware length * of the device. Similarly, the hardware types should match. The @@ -1415,7 +1415,18 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) } #else if (arp->ar_hln != dev->addr_len || - dev->type != ntohs(arp->ar_hrd) || +#if CONFIG_AP1000 + /* + * ARP from cafe-f was found to use ARPHDR_IEEE802 instead of + * the expected ARPHDR_ETHER. + */ + (strcmp(dev->name,"fddi") == 0 && + arp->ar_hrd != ARPHRD_ETHER && arp->ar_hrd != ARPHRD_IEEE802) || + (strcmp(dev->name,"fddi") != 0 && + dev->type != ntohs(arp->ar_hrd)) || +#else + dev->type != ntohs(arp->ar_hrd) || +#endif dev->flags & IFF_NOARP || skb->pkt_type == PACKET_OTHERHOST || arp->ar_pln != 4) { diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 850d729e8982..cb70a9734775 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -422,7 +422,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) if (!ipv4_config.source_route) { if (ipv4_config.log_martians) printk(KERN_INFO "source route option %08lx -> %08lx\n", - ntohl(iph->saddr), ntohl(iph->daddr)); + ntohl(iph->saddr), ntohl(iph->daddr)); goto drop; } if (RT_LOCALADDR(((struct rtable*)skb->dst)->rt_flags) && diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2be8be456152..b19ec3ce1388 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -170,7 +170,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc, struct device **de int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val,err; - unsigned char ucval; + unsigned char ucval = 0; #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) struct ip_fw tmp_fw; #endif diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index dc545116a449..8d95efe5af7c 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.6 1996/12/12 19:22:09 davem Exp $ + * $Id: af_inet6.c,v 1.8 1997/01/26 07:14:56 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -727,7 +727,7 @@ struct proto_ops inet6_stream_ops = { inet6_socketpair, /* a do nothing */ inet_accept, /* ok */ inet6_getname, - inet_select, /* ok */ + inet_poll, /* ok */ inet6_ioctl, /* must change */ inet_listen, /* ok */ inet_shutdown, /* ok */ @@ -748,7 +748,7 @@ struct proto_ops inet6_dgram_ops = { inet6_socketpair, /* a do nothing */ inet_accept, /* ok */ inet6_getname, - datagram_select, /* ok */ + datagram_poll, /* ok */ inet6_ioctl, /* must change */ inet_listen, /* ok */ inet_shutdown, /* ok */ diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ec090bad1d83..14fad5b4517d 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.5 1996/10/29 22:45:53 roque Exp $ + * $Id: raw.c,v 1.7 1997/01/26 07:14:56 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -449,7 +449,7 @@ struct proto rawv6_prot = { NULL, NULL, NULL, - datagram_select, + datagram_poll, NULL, rawv6_init_sk, NULL, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 171a9b19dbe3..74e054c1f507 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.6 1996/12/12 19:22:18 davem Exp $ + * $Id: tcp_ipv6.c,v 1.7 1997/01/26 07:14:57 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -1236,7 +1236,7 @@ struct proto tcpv6_prot = { NULL, tcp_write_wakeup, tcp_read_wakeup, - tcp_select, + tcp_poll, tcp_ioctl, tcp_v6_init_sock, tcp_v6_destroy_sock, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6429a7cb283d..d2bc4cb1f8b9 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.6 1996/10/16 18:34:16 roque Exp $ + * $Id: udp.c,v 1.7 1997/01/26 07:14:58 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -602,7 +602,7 @@ struct proto udpv6_prot = { NULL, NULL, NULL, - datagram_select, + datagram_poll, udp_ioctl, NULL, NULL, diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 035920e072c6..78d3863de4c7 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -2339,7 +2339,7 @@ static struct proto_ops ipx_dgram_ops = { ipx_socketpair, ipx_accept, ipx_getname, - datagram_select, + datagram_poll, ipx_ioctl, ipx_listen, ipx_shutdown, diff --git a/net/netbeui/netbeui.c b/net/netbeui/netbeui.c index 4392aa327314..c304d4772ea0 100644 --- a/net/netbeui/netbeui.c +++ b/net/netbeui/netbeui.c @@ -23,6 +23,7 @@ #include #include #include /* For TIOCOUTQ/INQ */ +#include #include #include #include @@ -711,11 +712,11 @@ static int netbeui_shutdown(struct socket *sk,int how) return -EOPNOTSUPP; } -static int netbeui_select(struct socket *sock , int sel_type, select_table *wait) +static int netbeui_poll(struct socket *sock, poll_table *wait) { netbeui_socket *sk=(netbeui_socket *)sock->data; - return datagram_select(sk,sel_type,wait); + return datagram_poll(sk,wait); } /* @@ -810,7 +811,7 @@ static struct proto_ops netbeui_proto_ops = { netbeui_socketpair, netbeui_accept, netbeui_getname, - netbeui_select, + netbeui_poll, netbeui_ioctl, netbeui_listen, netbeui_shutdown, diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 75c9f77a7674..841d2282b25a 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1365,7 +1365,7 @@ static struct proto_ops nr_proto_ops = { nr_socketpair, nr_accept, nr_getname, - datagram_select, + datagram_poll, nr_ioctl, nr_listen, nr_shutdown, diff --git a/net/netsyms.c b/net/netsyms.c index 822ff0e25296..9c897df78bb9 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef CONFIG_INET #include @@ -28,6 +29,7 @@ #include #include #include +#include extern struct net_proto_family inet_family_ops; @@ -100,6 +102,21 @@ EXPORT_SYMBOL(skb_copy_datagram); EXPORT_SYMBOL(skb_copy_datagram_iovec); EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(datagram_poll); +EXPORT_SYMBOL(sock_init_data); +EXPORT_SYMBOL(put_cmsg); + +EXPORT_SYMBOL(neigh_table_init); +/* Declared in but not defined? + EXPORT_SYMBOL(neigh_table_destroy); + EXPORT_SYMBOL(neigh_table_run_bh); +*/ +EXPORT_SYMBOL(neigh_alloc); +EXPORT_SYMBOL(neigh_table_ins); +EXPORT_SYMBOL(neigh_queue_ins); +EXPORT_SYMBOL(neigh_unlink); +EXPORT_SYMBOL(neigh_lookup); +EXPORT_SYMBOL(ntbl_walk_table); +EXPORT_SYMBOL(neigh_tbl_run_bh); /* Needed by smbfs.o */ EXPORT_SYMBOL(__scm_destroy); @@ -149,7 +166,6 @@ EXPORT_SYMBOL(inet_listen); EXPORT_SYMBOL(inet_shutdown); EXPORT_SYMBOL(inet_setsockopt); EXPORT_SYMBOL(inet_getsockopt); -EXPORT_SYMBOL(inet_fcntl); EXPORT_SYMBOL(inet_sendmsg); EXPORT_SYMBOL(inet_recvmsg); EXPORT_SYMBOL(tcp_sock_array); @@ -228,11 +244,17 @@ EXPORT_SYMBOL(register_trdev); EXPORT_SYMBOL(unregister_trdev); EXPORT_SYMBOL(init_trdev); #endif - + #ifdef CONFIG_NET_ALIAS #include #endif +/* Used by at least ipip.c. */ +EXPORT_SYMBOL(ipv4_config); +#ifdef CONFIG_IP_MROUTE +EXPORT_SYMBOL(ip_mr_find_tunnel); +#endif + #endif /* CONFIG_INET */ /* Device callback registration */ @@ -249,6 +271,7 @@ EXPORT_SYMBOL(unregister_net_alias_type); EXPORT_SYMBOL(register_netdev); EXPORT_SYMBOL(unregister_netdev); EXPORT_SYMBOL(ether_setup); +EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(eth_type_trans); EXPORT_SYMBOL(eth_copy_and_sum); EXPORT_SYMBOL(alloc_skb); @@ -264,10 +287,14 @@ EXPORT_SYMBOL(dev_remove_pack); EXPORT_SYMBOL(dev_get); EXPORT_SYMBOL(dev_ioctl); EXPORT_SYMBOL(dev_queue_xmit); +#ifdef CONFIG_IP_ACCT +EXPORT_SYMBOL(ip_acct_output); +#endif EXPORT_SYMBOL(dev_base); EXPORT_SYMBOL(dev_close); EXPORT_SYMBOL(dev_mc_add); EXPORT_SYMBOL(arp_find); +EXPORT_SYMBOL(arp_find_1); EXPORT_SYMBOL(n_tty_ioctl); EXPORT_SYMBOL(tty_register_ldisc); EXPORT_SYMBOL(kill_fasync); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8f0b6895e6be..abe7b5ffb890 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1409,7 +1409,7 @@ static struct proto_ops rose_proto_ops = { rose_socketpair, rose_accept, rose_getname, - datagram_select, + datagram_poll, rose_ioctl, rose_listen, rose_shutdown, diff --git a/net/socket.c b/net/socket.c index 42b202b9868c..4e72dbbb370e 100644 --- a/net/socket.c +++ b/net/socket.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include #include @@ -556,16 +558,18 @@ int sock_wake_async(struct socket *sock, int how) asmlinkage int sys_socket(int family, int type, int protocol) { - int i, fd; + int i, fd, err; struct socket *sock; - /* - * Check protocol is in range - */ - - if(family<0||family>=NPROTO) - return -EINVAL; - + lock_kernel(); + + /* + * Check protocol is in range + */ + err = -EINVAL; + if(family<0||family>=NPROTO) + goto out; + #if defined(CONFIG_KERNELD) && defined(CONFIG_NET) /* Attempt to load a protocol module if the find failed. * @@ -582,7 +586,7 @@ asmlinkage int sys_socket(int family, int type, int protocol) #endif if (net_families[family]==NULL) - return -EINVAL; + goto out; /* * Check that this is a type that we know how to manipulate and @@ -593,7 +597,7 @@ asmlinkage int sys_socket(int family, int type, int protocol) if ((type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET && type != SOCK_RAW && type != SOCK_PACKET) || protocol < 0) - return(-EINVAL); + goto out; /* * Allocate the socket and allow the family to set things up. if @@ -601,10 +605,11 @@ asmlinkage int sys_socket(int family, int type, int protocol) * default. */ + err = -ENFILE; if (!(sock = sock_alloc())) { printk(KERN_WARNING "socket: no more sockets\n"); - return(-ENFILE); /* Not exactly a match, but its the + goto out; /* Not exactly a match, but its the closest posix thing */ } @@ -613,18 +618,21 @@ asmlinkage int sys_socket(int family, int type, int protocol) if ((i = net_families[family]->create(sock, protocol)) < 0) { sock_release(sock); - return(i); + err = i; } - - if ((fd = get_fd(sock->inode)) < 0) + else if ((fd = get_fd(sock->inode)) < 0) { sock_release(sock); - return(-EINVAL); + err = -EINVAL; } - - sock->file = current->files->fd[fd]; - - return(fd); + else + { + sock->file = current->files->fd[fd]; + err = fd; + } +out: + unlock_kernel(); + return err; } /* @@ -637,50 +645,59 @@ asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2 struct socket *sock1, *sock2; int err; + lock_kernel(); + /* * Obtain the first socket and check if the underlying protocol * supports the socketpair call. */ - if ((fd1 = sys_socket(family, type, protocol)) < 0) - return(fd1); + if ((fd1 = sys_socket(family, type, protocol)) < 0) { + err = fd1; + goto out; + } sock1 = sockfd_lookup(fd1, &err); if (!sock1) - return err; + goto out; + err = -EOPNOTSUPP; if (!sock1->ops->socketpair) { sys_close(fd1); - return -EOPNOTSUPP; + goto out; } /* * Now grab another socket and try to connect the two together. */ - + err = -EINVAL; if ((fd2 = sys_socket(family, type, protocol)) < 0) { sys_close(fd1); - return(-EINVAL); + goto out; } sock2 = sockfd_lookup(fd2,&err); if (!sock2) - return err; + goto out; if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) { sys_close(fd1); sys_close(fd2); - return(i); + err = i; } - - err = put_user(fd1, &usockvec[0]); - if (!err) - err = put_user(fd2, &usockvec[1]); - if (err) { - sys_close(fd1); - sys_close(fd2); + else + { + err = put_user(fd1, &usockvec[0]); + if (!err) + err = put_user(fd2, &usockvec[1]); + if (err) { + sys_close(fd1); + sys_close(fd2); + } } +out: + unlock_kernel(); return err; } @@ -700,15 +717,20 @@ asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) char address[MAX_SOCK_ADDR]; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd,&err))) - return err; + goto out; if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0) - return err; + goto out; if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) - return(i); - return(0); + err = i; + else + err = 0; +out: + unlock_kernel(); + return err; } @@ -723,11 +745,14 @@ asmlinkage int sys_listen(int fd, int backlog) struct socket *sock; int err=-EOPNOTSUPP; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; if (sock->ops && sock->ops->listen) err=sock->ops->listen(sock, backlog); +out: + unlock_kernel(); return err; } @@ -748,45 +773,48 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad { struct inode *inode; struct socket *sock, *newsock; - int i; int err; char address[MAX_SOCK_ADDR]; int len; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; + err = -EOPNOTSUPP; if (!sock->ops->accept) - return -EOPNOTSUPP; + goto out; + err = -ENOSR; if (!(newsock = sock_alloc())) { printk(KERN_WARNING "accept: no more sockets\n"); - return(-ENOSR); /* Was: EAGAIN, but we are out of system + goto out; /* Was: EAGAIN, but we are out of system resources! */ } inode = newsock->inode; newsock->type = sock->type; - if ((i = sock->ops->dup(newsock, sock)) < 0) + if ((err = sock->ops->dup(newsock, sock)) < 0) { sock_release(newsock); - return(i); + goto out; } - i = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags); + err = newsock->ops->accept(sock, newsock, current->files->fd[fd]->f_flags); - if (i < 0) + if (err < 0) { sock_release(newsock); - return(i); + goto out; } newsock = socki_lookup(inode); if ((fd = get_fd(inode)) < 0) { sock_release(newsock); - return(-EINVAL); + err = -EINVAL; + goto out; } newsock->file = current->files->fd[fd]; @@ -796,7 +824,10 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1); move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen); } - return fd; + err = fd; +out: + unlock_kernel(); + return err; } @@ -815,21 +846,23 @@ asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_ad asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) { struct socket *sock; - int i; char address[MAX_SOCK_ADDR]; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd,&err))) - return err; + goto out; if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0) - return err; + goto out; - i = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, + err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, current->files->fd[fd]->f_flags); - if (i < 0) - return(i); - return(0); + if (err >= 0) + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -844,15 +877,19 @@ asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockadd int len; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); if(err) - return err; + goto out; if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0) - return err; - return 0; + goto out; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -867,15 +904,19 @@ asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockadd int len; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); if(err) - return err; + goto out; if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0) - return err; - return 0; + goto out; + err = 0; +out: + unlock_kernel(); + return err; } /* @@ -890,14 +931,16 @@ asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags) struct msghdr msg; struct iovec iov; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; + err = -EINVAL; if(len<0) - return -EINVAL; + goto out; err=verify_area(VERIFY_READ, buff, len); if(err) - return err; + goto out; iov.iov_base=buff; iov.iov_len=len; @@ -911,7 +954,10 @@ asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags) flags |= MSG_DONTWAIT; msg.msg_flags=flags; - return sock_sendmsg(sock, &msg, len); + err = sock_sendmsg(sock, &msg, len); +out: + unlock_kernel(); + return err; } /* @@ -929,13 +975,14 @@ asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct msghdr msg; struct iovec iov; + lock_kernel(); if (!(sock = sockfd_lookup(fd,&err))) - return err; + goto out; err=verify_area(VERIFY_READ,buff,len); if(err) - return err; - + goto out; + iov.iov_base=buff; iov.iov_len=len; msg.msg_name=NULL; @@ -948,15 +995,18 @@ asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, { err=move_addr_to_kernel(addr,addr_len,address); if (err < 0) - return err; + goto out; msg.msg_name=address; } - + if (current->files->fd[fd]->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; msg.msg_flags=flags; - return sock_sendmsg(sock, &msg, len); + err = sock_sendmsg(sock, &msg, len); +out: + unlock_kernel(); + return err; } @@ -971,15 +1021,17 @@ asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags) struct socket *sock; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; - + goto out; + + err = 0; if(size==0) - return 0; + goto out; err=verify_area(VERIFY_WRITE, ubuf, size); if(err) - return err; - + goto out; + msg.msg_name=NULL; msg.msg_iov=&iov; msg.msg_iovlen=1; @@ -988,8 +1040,12 @@ asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags) iov.iov_base=ubuf; iov.iov_len=size; - return sock_recvmsg(sock, &msg, size, - (current->files->fd[fd]->f_flags & O_NONBLOCK) ? flags | MSG_DONTWAIT : flags); + err = sock_recvmsg(sock, &msg, size, + (current->files->fd[fd]->f_flags & O_NONBLOCK) + ? flags | MSG_DONTWAIT : flags); +out: + unlock_kernel(); + return err; } /* @@ -1007,15 +1063,17 @@ asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, char address[MAX_SOCK_ADDR]; int err; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; + err = 0; if (size==0) - return 0; + goto out; err=verify_area(VERIFY_WRITE,ubuf,size); if(err) - return err; - + goto out; + msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_iovlen=1; @@ -1024,17 +1082,20 @@ asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, iov.iov_base=ubuf; msg.msg_name=address; msg.msg_namelen=MAX_SOCK_ADDR; - err=sock_recvmsg(sock, &msg, size, - (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags); + err = sock_recvmsg(sock, &msg, size, + (current->files->fd[fd]->f_flags & O_NONBLOCK) + ? (flags | MSG_DONTWAIT) : flags); if(err<0) - return err; + goto out; size=err; - - if(addr!=NULL && (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0) - return err; - - return size; + if(addr!=NULL && + (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0) + goto out; + err = size; +out: + unlock_kernel(); + return err; } /* @@ -1047,16 +1108,19 @@ asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int int err; struct socket *sock; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; if (level == SOL_SOCKET) - return sock_setsockopt(sock,level,optname,optval,optlen); - - if (sock->ops->setsockopt) - return sock->ops->setsockopt(sock, level, optname, optval, optlen); - - return -EOPNOTSUPP; + err = sock_setsockopt(sock,level,optname,optval,optlen); + else if (sock->ops->setsockopt) + err = sock->ops->setsockopt(sock, level, optname, optval, optlen); + else + err = -EOPNOTSUPP; +out: + unlock_kernel(); + return err; } /* @@ -1069,16 +1133,19 @@ asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int int err; struct socket *sock; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; if (level == SOL_SOCKET) - return sock_getsockopt(sock,level,optname,optval,optlen); - - if (sock->ops->getsockopt) - return sock->ops->getsockopt(sock, level, optname, optval, optlen); - - return -EOPNOTSUPP; + err = sock_getsockopt(sock,level,optname,optval,optlen); + else if (sock->ops->getsockopt) + err = sock->ops->getsockopt(sock, level, optname, optval, optlen); + else + err = -EOPNOTSUPP; +out: + unlock_kernel(); + return err; } @@ -1091,10 +1158,14 @@ asmlinkage int sys_shutdown(int fd, int how) int err; struct socket *sock; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; - return sock->ops->shutdown(sock, how); + err = sock->ops->shutdown(sock, how); +out: + unlock_kernel(); + return err; } /* @@ -1111,23 +1182,27 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) int err; int total_len; + lock_kernel(); if (!(sock = sockfd_lookup(fd,&err))) - return err; + goto out; + err = -EOPNOTSUPP; if (sock->ops->sendmsg==NULL) - return -EOPNOTSUPP; + goto out; + err = -EFAULT; if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) - return -EFAULT; + goto out; /* do not move before msg_sys is valid */ + err = -EINVAL; if (msg_sys.msg_iovlen>UIO_MAXIOV) - return -EINVAL; + goto out; /* This will also move the address data into kernel space */ err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); if (err < 0) - return err; + goto out; total_len=err; if (msg_sys.msg_controllen) { @@ -1159,6 +1234,8 @@ failed: failed2: if (msg_sys.msg_iov != iov) kfree(msg_sys.msg_iov); +out: + unlock_kernel(); return err; } @@ -1184,14 +1261,17 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) struct sockaddr *uaddr; int *uaddr_len; + lock_kernel(); if (!(sock = sockfd_lookup(fd, &err))) - return err; + goto out; + err = -EFAULT; if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) - return -EFAULT; + goto out; + err = -EINVAL; if (msg_sys.msg_iovlen>UIO_MAXIOV) - return -EINVAL; + goto out; /* * Save the user-mode address (verify_iovec will change the @@ -1202,7 +1282,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) uaddr_len = &msg->msg_namelen; err=verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); if (err<0) - return err; + goto out; total_len=err; @@ -1214,20 +1294,26 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) len=sock_recvmsg(sock, &msg_sys, total_len, flags); if (msg_sys.msg_iov != iov) kfree(msg_sys.msg_iov); - if (len<0) - return len; + if (len<0) { + err = len; + goto out; + } if (uaddr != NULL) { err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); if (err) - return err; + goto out; } + err = -EFAULT; if (put_user(msg_sys.msg_flags, &msg->msg_flags)) - return -EFAULT; + goto out; if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen)) - return -EFAULT; - return len; + goto out; + err = len; +out: + unlock_kernel(); + return err; } @@ -1264,89 +1350,80 @@ asmlinkage int sys_socketcall(int call, unsigned long *args) 4,4,4,6,6,2,5,5,3,3}; unsigned long a[6]; unsigned long a0,a1; + int err = -EINVAL; + lock_kernel(); if(call<1||call>SYS_RECVMSG) - return -EINVAL; - + goto out; + err = -EFAULT; if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long)))) - return -EFAULT; + goto out; a0=a[0]; a1=a[1]; - switch(call) { case SYS_SOCKET: - return(sys_socket(a0,a1,a[2])); + err = sys_socket(a0,a1,a[2]); + break; case SYS_BIND: - return(sys_bind(a0,(struct sockaddr *)a1, - a[2])); + err = sys_bind(a0,(struct sockaddr *)a1, a[2]); + break; case SYS_CONNECT: - return(sys_connect(a0, (struct sockaddr *)a1, - a[2])); + err = sys_connect(a0, (struct sockaddr *)a1, a[2]); + break; case SYS_LISTEN: - return(sys_listen(a0,a1)); + err = sys_listen(a0,a1); + break; case SYS_ACCEPT: - return(sys_accept(a0,(struct sockaddr *)a1, - (int *)a[2])); + err = sys_accept(a0,(struct sockaddr *)a1, (int *)a[2]); + break; case SYS_GETSOCKNAME: - return(sys_getsockname(a0,(struct sockaddr *)a1, - (int *)a[2])); + err = sys_getsockname(a0,(struct sockaddr *)a1, (int *)a[2]); + break; case SYS_GETPEERNAME: - return(sys_getpeername(a0, (struct sockaddr *)a1, - (int *)a[2])); + err = sys_getpeername(a0, (struct sockaddr *)a1, (int *)a[2]); + break; case SYS_SOCKETPAIR: - return(sys_socketpair(a0,a1, - a[2], - (int *)a[3])); + err = sys_socketpair(a0,a1, a[2], (int *)a[3]); + break; case SYS_SEND: - return(sys_send(a0, - (void *)a1, - a[2], - a[3])); + err = sys_send(a0, (void *)a1, a[2], a[3]); + break; case SYS_SENDTO: - return(sys_sendto(a0,(void *)a1, - a[2], - a[3], - (struct sockaddr *)a[4], - a[5])); + err = sys_sendto(a0,(void *)a1, a[2], a[3], + (struct sockaddr *)a[4], a[5]); + break; case SYS_RECV: - return(sys_recv(a0, - (void *)a1, - a[2], - a[3])); + err = sys_recv(a0, (void *)a1, a[2], a[3]); + break; case SYS_RECVFROM: - return(sys_recvfrom(a0, - (void *)a1, - a[2], - a[3], - (struct sockaddr *)a[4], - (int *)a[5])); + err = sys_recvfrom(a0, (void *)a1, a[2], a[3], + (struct sockaddr *)a[4], (int *)a[5]); + break; case SYS_SHUTDOWN: - return(sys_shutdown(a0,a1)); + err = sys_shutdown(a0,a1); + break; case SYS_SETSOCKOPT: - return(sys_setsockopt(a0, - a1, - a[2], - (char *)a[3], - a[4])); + err = sys_setsockopt(a0, a1, a[2], (char *)a[3], a[4]); + break; case SYS_GETSOCKOPT: - return(sys_getsockopt(a0, - a1, - a[2], - (char *)a[3], - (int *)a[4])); + err = sys_getsockopt(a0, a1, a[2], (char *)a[3], (int *)a[4]); + break; case SYS_SENDMSG: - return sys_sendmsg(a0, - (struct msghdr *) a1, - a[2]); + err = sys_sendmsg(a0, (struct msghdr *) a1, a[2]); + break; case SYS_RECVMSG: - return sys_recvmsg(a0, - (struct msghdr *) a1, - a[2]); + err = sys_recvmsg(a0, (struct msghdr *) a1, a[2]); + break; + default: + err = -EINVAL; + break; } - return -EINVAL; /* to keep gcc happy */ +out: + unlock_kernel(); + return err; } @@ -1389,6 +1466,7 @@ void proto_init(void) /* We're all done... */ } +extern void sk_init(void); void sock_init(void) { @@ -1401,6 +1479,12 @@ void sock_init(void) */ for (i = 0; i < NPROTO; i++) net_families[i] = NULL; + + /* + * Initialize sock SLAB cache. + */ + + sk_init(); /* * The netlink device handler may be needed early. diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index e66c01a5ea9a..7aaab4dfb958 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1304,7 +1304,7 @@ static struct proto_ops x25_proto_ops = { x25_socketpair, x25_accept, x25_getname, - datagram_select, + datagram_poll, x25_ioctl, x25_listen, x25_shutdown, diff --git a/scripts/mkdep.c b/scripts/mkdep.c index cd32020d2616..7b005fa72710 100644 --- a/scripts/mkdep.c +++ b/scripts/mkdep.c @@ -126,6 +126,7 @@ preproc: CASE(' ',preproc); CASE('\t',preproc); CASE('i',i_preproc); + CASE('e',e_preproc); GETNEXT skippreproc: @@ -139,6 +140,15 @@ skippreprocslash: GETNEXT; goto skippreproc; +e_preproc: + GETNEXT + NOTCASE('l',skippreproc); + GETNEXT + NOTCASE('i',skippreproc); + GETNEXT + CASE('f',if_line); + goto skippreproc; + i_preproc: GETNEXT CASE('f',if_line); -- 2.39.5