summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS20
-rw-r--r--Documentation/Changes41
-rw-r--r--Documentation/Configure.help54
-rw-r--r--Documentation/cdrom/ide-cd17
-rw-r--r--Documentation/kmod.txt47
-rw-r--r--Documentation/modules.txt6
-rw-r--r--Documentation/sysctl/vm.txt75
-rw-r--r--MAINTAINERS10
-rw-r--r--Makefile5
-rw-r--r--arch/alpha/config.in2
-rw-r--r--arch/alpha/defconfig2
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c5
-rw-r--r--arch/alpha/kernel/process.c6
-rw-r--r--arch/arm/config.in2
-rw-r--r--arch/arm/defconfig2
-rw-r--r--arch/arm/kernel/armksyms.c5
-rw-r--r--arch/arm/kernel/init_task.c1
-rw-r--r--arch/i386/.kernel_offset.lds1
-rw-r--r--arch/i386/Makefile17
-rw-r--r--arch/i386/config.in3
-rw-r--r--arch/i386/defconfig5
-rw-r--r--arch/i386/kernel/head.S21
-rw-r--r--arch/i386/kernel/i386_ksyms.c4
-rw-r--r--arch/i386/kernel/init_task.c1
-rw-r--r--arch/i386/kernel/io_apic.c14
-rw-r--r--arch/i386/kernel/ioport.c16
-rw-r--r--arch/i386/kernel/irq.c48
-rw-r--r--arch/i386/kernel/irq.h13
-rw-r--r--arch/i386/kernel/process.c24
-rw-r--r--arch/i386/kernel/ptrace.c12
-rw-r--r--arch/i386/kernel/smp.c104
-rw-r--r--arch/i386/kernel/trampoline.S3
-rw-r--r--arch/i386/mm/init.c4
-rw-r--r--arch/i386/vmlinux.lds3
-rw-r--r--arch/m68k/amiga/amiga_ksyms.c5
-rw-r--r--arch/m68k/atari/atari_ksyms.c6
-rw-r--r--arch/m68k/config.in2
-rw-r--r--arch/m68k/defconfig2
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c5
-rw-r--r--arch/m68k/kernel/process.c1
-rw-r--r--arch/m68k/mac/ksyms.c5
-rw-r--r--arch/mips/config.in2
-rw-r--r--arch/mips/kernel/init_task.c1
-rw-r--r--arch/mips/kernel/mips_ksyms.c7
-rw-r--r--arch/mips/kernel/syscall.c22
-rw-r--r--arch/mips/mm/r4xx0.c6
-rw-r--r--arch/ppc/config.in2
-rw-r--r--arch/ppc/defconfig2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c5
-rw-r--r--arch/ppc/kernel/process.c1
-rw-r--r--arch/ppc/pmac_defconfig2
-rw-r--r--arch/ppc/prep_defconfig2
-rw-r--r--arch/sparc/config.in2
-rw-r--r--arch/sparc/defconfig2
-rw-r--r--arch/sparc/kernel/init_task.c1
-rw-r--r--arch/sparc/kernel/ptrace.c6
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c5
-rw-r--r--arch/sparc/mm/init.c14
-rw-r--r--arch/sparc64/config.in2
-rw-r--r--arch/sparc64/defconfig2
-rw-r--r--arch/sparc64/kernel/init_task.c1
-rw-r--r--arch/sparc64/kernel/traps.c6
-rw-r--r--arch/sparc64/mm/init.c15
-rw-r--r--drivers/block/floppy.c44
-rw-r--r--drivers/block/ide-cd.c114
-rw-r--r--drivers/block/ide-cd.h4
-rw-r--r--drivers/block/ide-disk.c16
-rw-r--r--drivers/block/ide-pci.c13
-rw-r--r--drivers/block/ide.c14
-rw-r--r--drivers/block/ll_rw_blk.c9
-rw-r--r--drivers/block/md.c9
-rw-r--r--drivers/block/raid5.c5
-rw-r--r--drivers/block/rd.c41
-rw-r--r--drivers/char/ChangeLog8
-rw-r--r--drivers/char/Config.in5
-rw-r--r--drivers/char/apm_bios.c8
-rw-r--r--drivers/char/esp.c4
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.c3
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c6
-rw-r--r--drivers/char/ftape/zftape/zftape-read.c4
-rw-r--r--drivers/char/ftape/zftape/zftape-write.c4
-rw-r--r--drivers/char/lp_m68k.c6
-rw-r--r--drivers/char/misc.c9
-rw-r--r--drivers/char/n_tty.c7
-rw-r--r--drivers/char/rtc.c57
-rw-r--r--drivers/char/serial.c4
-rw-r--r--drivers/char/tty_io.c51
-rw-r--r--drivers/char/tty_ioctl.c7
-rw-r--r--drivers/misc/parport_init.c1
-rw-r--r--drivers/misc/parport_share.c10
-rw-r--r--drivers/net/Config.in5
-rw-r--r--drivers/net/Makefile13
-rw-r--r--drivers/net/Space.c5
-rw-r--r--drivers/net/de4x5.c301
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/hp100.c4642
-rw-r--r--drivers/net/hp100.h2
-rw-r--r--drivers/net/ipddp.c71
-rw-r--r--drivers/net/ipddp.h1
-rw-r--r--drivers/net/ppp.c11
-rw-r--r--drivers/net/seeq8005.c1
-rw-r--r--drivers/net/slip.c6
-rw-r--r--drivers/net/tulip.c4
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/ppa.c6
-rw-r--r--drivers/scsi/scsi.c71
-rw-r--r--drivers/scsi/scsi_error.c5
-rw-r--r--drivers/scsi/scsi_obsolete.c9
-rw-r--r--drivers/scsi/scsi_queue.c5
-rw-r--r--drivers/scsi/sd.c7
-rw-r--r--drivers/scsi/wd7000.c1552
-rw-r--r--drivers/scsi/wd7000.h50
-rw-r--r--drivers/sound/Config.in2
-rw-r--r--drivers/sound/Makefile42
-rw-r--r--drivers/sound/ad1848.c113
-rw-r--r--drivers/sound/audio.c1
-rw-r--r--drivers/sound/bin2hex.c19
-rw-r--r--drivers/sound/cs4232.c17
-rw-r--r--drivers/sound/dev_table.c3
-rw-r--r--drivers/sound/dmabuf.c35
-rw-r--r--drivers/sound/gus_card.c11
-rw-r--r--drivers/sound/hex2hex.c17
-rw-r--r--drivers/sound/maui.c25
-rw-r--r--drivers/sound/midibuf.c1
-rw-r--r--drivers/sound/mpu401.c1778
-rw-r--r--drivers/sound/opl3.c78
-rw-r--r--drivers/sound/pas2_card.c4
-rw-r--r--drivers/sound/pss.c797
-rw-r--r--drivers/sound/sb_audio.c16
-rw-r--r--drivers/sound/sb_card.c22
-rw-r--r--drivers/sound/sb_common.c32
-rw-r--r--drivers/sound/sound_calls.h6
-rw-r--r--drivers/sound/sound_timer.c8
-rw-r--r--drivers/sound/soundcard.c22
-rw-r--r--drivers/sound/uart401.c337
-rw-r--r--drivers/sound/uart6850.c9
-rw-r--r--drivers/sound/v_midi.c11
-rw-r--r--drivers/video/fbcon.c14
-rw-r--r--fs/buffer.c6
-rw-r--r--fs/coda/Makefile2
-rw-r--r--fs/coda/cache.c196
-rw-r--r--fs/coda/cnode.c59
-rw-r--r--fs/coda/coda_linux.c23
-rw-r--r--fs/coda/dir.c104
-rw-r--r--fs/coda/file.c49
-rw-r--r--fs/coda/inode.c (renamed from fs/coda/super.c)35
-rw-r--r--fs/coda/psdev.c4
-rw-r--r--fs/coda/upcall.c55
-rw-r--r--fs/devices.c13
-rw-r--r--fs/exec.c8
-rw-r--r--fs/fcntl.c39
-rw-r--r--fs/filesystems.c8
-rw-r--r--fs/hfs/ChangeLog53
-rw-r--r--fs/hfs/Makefile2
-rw-r--r--fs/hfs/catalog.c403
-rw-r--r--fs/hfs/dir.c19
-rw-r--r--fs/hfs/dir_cap.c16
-rw-r--r--fs/hfs/dir_dbl.c19
-rw-r--r--fs/hfs/dir_nat.c10
-rw-r--r--fs/hfs/file.c16
-rw-r--r--fs/hfs/file_cap.c5
-rw-r--r--fs/hfs/file_hdr.c13
-rw-r--r--fs/hfs/hfs.h13
-rw-r--r--fs/hfs/inode.c45
-rw-r--r--fs/hfs/string.c11
-rw-r--r--fs/hfs/super.c15
-rw-r--r--fs/hfs/sysdep.c39
-rw-r--r--fs/hfs/version.c2
-rw-r--r--fs/ncpfs/Config.in2
-rw-r--r--fs/ncpfs/Makefile3
-rw-r--r--fs/ncpfs/dir.c2
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/ioctl.c33
-rw-r--r--fs/ncpfs/ncpsign_kernel.c114
-rw-r--r--fs/ncpfs/ncpsign_kernel.h16
-rw-r--r--fs/nfs/inode.c21
-rw-r--r--fs/nfs/nfs2xdr.c65
-rw-r--r--fs/nls/nls_base.c8
-rw-r--r--fs/ntfs/fs.c10
-rw-r--r--fs/open.c35
-rw-r--r--fs/proc/array.c30
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c4
-rw-r--r--fs/proc/inode.c8
-rw-r--r--fs/proc/mem.c2
-rw-r--r--fs/proc/root.c12
-rw-r--r--fs/super.c10
-rw-r--r--fs/umsdos/README-WIP.txt75
-rw-r--r--fs/umsdos/dir.c12
-rw-r--r--fs/umsdos/emd.c155
-rw-r--r--fs/umsdos/inode.c33
-rw-r--r--fs/umsdos/namei.c54
-rw-r--r--fs/umsdos/symlink.c3
-rw-r--r--include/asm-alpha/fpu.h22
-rw-r--r--include/asm-i386/page.h7
-rw-r--r--include/asm-i386/pgtable.h14
-rw-r--r--include/asm-i386/processor.h6
-rw-r--r--include/asm-i386/uaccess.h3
-rw-r--r--include/linux/coda.h6
-rw-r--r--include/linux/coda_cache.h15
-rw-r--r--include/linux/coda_fs_i.h7
-rw-r--r--include/linux/coda_linux.h18
-rw-r--r--include/linux/file.h44
-rw-r--r--include/linux/hfs_fs.h6
-rw-r--r--include/linux/hfs_fs_i.h2
-rw-r--r--include/linux/hfs_sysdep.h4
-rw-r--r--include/linux/kerneld.h135
-rw-r--r--include/linux/kmod.h4
-rw-r--r--include/linux/module.h2
-rw-r--r--include/linux/mroute.h2
-rw-r--r--include/linux/ncp_fs.h11
-rw-r--r--include/linux/ncp_fs_sb.h6
-rw-r--r--include/linux/netdevice.h6
-rw-r--r--include/linux/nfs_fs.h3
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/linux/sched.h51
-rw-r--r--include/linux/socket.h2
-rw-r--r--include/linux/sunrpc/clnt.h5
-rw-r--r--include/linux/swap.h6
-rw-r--r--include/linux/swapctl.h46
-rw-r--r--include/linux/sysctl.h9
-rw-r--r--include/linux/tty.h3
-rw-r--r--include/linux/umsdos_fs.p13
-rw-r--r--include/net/dst.h2
-rw-r--r--include/net/ip6_route.h2
-rw-r--r--include/net/ipv6.h2
-rw-r--r--include/net/route.h1
-rw-r--r--include/net/sock.h201
-rw-r--r--include/net/tcp.h441
-rw-r--r--init/main.c15
-rw-r--r--ipc/Makefile4
-rw-r--r--ipc/msg.c341
-rw-r--r--ipc/util.c5
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/exit.c21
-rw-r--r--kernel/fork.c71
-rw-r--r--kernel/kmod.c149
-rw-r--r--kernel/ksyms.c11
-rw-r--r--kernel/module.c2
-rw-r--r--kernel/sched.c124
-rw-r--r--kernel/signal.c12
-rw-r--r--kernel/sys.c36
-rw-r--r--kernel/sysctl.c14
-rw-r--r--mm/page_alloc.c6
-rw-r--r--mm/slab.c6
-rw-r--r--mm/swap.c71
-rw-r--r--mm/swap_state.c10
-rw-r--r--mm/vmscan.c42
-rw-r--r--net/802/sysctl_net_802.c1
-rw-r--r--net/802/tr.c19
-rw-r--r--net/appletalk/ddp.c59
-rw-r--r--net/ax25/af_ax25.c6
-rw-r--r--net/core/dev.c83
-rw-r--r--net/core/dst.c2
-rw-r--r--net/core/iovec.c38
-rw-r--r--net/core/neighbour.c29
-rw-r--r--net/core/sock.c178
-rw-r--r--net/core/sysctl_net_core.c4
-rw-r--r--net/ipv4/af_inet.c15
-rw-r--r--net/ipv4/arp.c8
-rw-r--r--net/ipv4/devinet.c38
-rw-r--r--net/ipv4/fib_frontend.c24
-rw-r--r--net/ipv4/fib_hash.c2
-rw-r--r--net/ipv4/fib_rules.c2
-rw-r--r--net/ipv4/fib_semantics.c2
-rw-r--r--net/ipv4/icmp.c8
-rw-r--r--net/ipv4/igmp.c2
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_fragment.c2
-rw-r--r--net/ipv4/ip_fw.c35
-rw-r--r--net/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ip_masq_mod.c10
-rw-r--r--net/ipv4/ip_masq_raudio.c2
-rw-r--r--net/ipv4/ip_nat_dumb.c34
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/ip_sockglue.c2
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c2
-rw-r--r--net/ipv4/ipmr.c16
-rw-r--r--net/ipv4/proc.c58
-rw-r--r--net/ipv4/rarp.c2
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/route.c348
-rw-r--r--net/ipv4/syncookies.c2
-rw-r--r--net/ipv4/sysctl_net_ipv4.c15
-rw-r--r--net/ipv4/tcp.c440
-rw-r--r--net/ipv4/tcp_input.c852
-rw-r--r--net/ipv4/tcp_ipv4.c784
-rw-r--r--net/ipv4/tcp_output.c449
-rw-r--r--net/ipv4/tcp_timer.c75
-rw-r--r--net/ipv4/timer.c63
-rw-r--r--net/ipv4/udp.c16
-rw-r--r--net/ipv6/addrconf.c4
-rw-r--r--net/ipv6/af_inet6.c7
-rw-r--r--net/ipv6/exthdrs.c2
-rw-r--r--net/ipv6/icmp.c2
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/ip6_fw.c2
-rw-r--r--net/ipv6/ip6_input.c2
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c2
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/proc.c59
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/reassembly.c2
-rw-r--r--net/ipv6/route.c43
-rw-r--r--net/ipv6/sit.c2
-rw-r--r--net/ipv6/tcp_ipv6.c423
-rw-r--r--net/ipv6/udp.c39
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/netbeui/af_netbeui.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netrom/af_netrom.c4
-rw-r--r--net/netsyms.c10
-rw-r--r--net/packet/af_packet.c10
-rw-r--r--net/rose/af_rose.c4
-rw-r--r--net/socket.c10
-rw-r--r--net/unix/af_unix.c6
-rw-r--r--net/x25/af_x25.c2
320 files changed, 10700 insertions, 9117 deletions
diff --git a/CREDITS b/CREDITS
index 4014526e4..5bed63d68 100644
--- a/CREDITS
+++ b/CREDITS
@@ -62,9 +62,10 @@ S: USA
N: Andrea Arcangeli
E: arcangeli@mbox.queen.it
-W: http://www-linux.deis.unibo.it/~mirror/
+W: http://www.cs.unibo.it/~arcangel/
P: 1024/CB4660B9 CC A0 71 81 F4 A0 63 AC C0 4B 81 1D 8C 15 C8 E5
-D: parport sharing fix. Various other kernel hacks.
+D: Parport sharing hacker.
+D: Various other kernel hacks.
S: Via Ciaclini 26
S: Imola 40026
S: Italy
@@ -395,6 +396,11 @@ S: Virginia Tech
S: Blacksburg, Virginia 24061
S: USA
+N: Cyrus Durgin
+E: cider@speakeasy.org
+W: http://www.speakeasy.org/~cider/
+D: implemented kmod
+
N: Torsten Duwe
E: Torsten.Duwe@informatik.uni-erlangen.de
D: Part-time kernel hacker
@@ -1337,6 +1343,7 @@ S: Russia
N: Kirk Petersen
E: kirk@speakeasy.org
W: http://www.speakeasy.org/~kirk/
+D: implemented kmod
D: modularized BSD Unix domain sockets
N: Kai Petzke
@@ -1413,6 +1420,15 @@ S: 6, rue Augustin Thierry
S: 75019 Paris
S: France
+N: Rik van Riel
+E: H.H.vanRiel@fys.ruu.nl
+W: http://www.fys.ruu.nl/~riel/
+D: Maintainer of the mm-patches page (see www.linuxhq.com)
+D: Documentation/sysctl/*, kswapd fixes, random kernel hacker
+S: Vorenkampsweg 1
+S: NL-9488 TG Zeijerveld
+S: The Netherlands
+
N: William E. Roadcap
E: roadcapw@cfw.com
W: http://www.cfw.com/~roadcapw
diff --git a/Documentation/Changes b/Documentation/Changes
index 6f778a20f..9b5846d92 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -32,7 +32,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well.
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: February 16. 1998
+Last updated: March 16. 1998
Current Author: Chris Ricker (kaboom@gatech.edu).
Current Minimal Requirements
@@ -45,11 +45,11 @@ running, the suggested command should tell you.
- Kernel modules modutils-2.1.85 ; insmod -V
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.1 ; ld -v
-- Linux C Library 5.4.38 ; ls -l /lib/libc.so.*
+- Linux C Library 5.4.44 ; ls -l /lib/libc.so.*
- Dynamic Linker (ld.so) 1.9.5 ; ldd -v
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
- Procps 1.2.5 ; ps --version
-- Procinfo 0.11 ; procinfo -v
+- Procinfo 0.13 ; procinfo -v
- Mount 2.7l ; mount --version
- Net-tools 1.41 ; hostname -V
- Loadlin 1.6a
@@ -58,7 +58,7 @@ running, the suggested command should tell you.
- NFS 0.4.21 ; showmount --version
- Bash 1.14.7 ; bash -version
- Ncpfs 2.1.1 ; ncpmount -v
-- Pcmcia-cs 2.9.12
+- Pcmcia-cs 3.0.0
- PPP 2.3.3 ; pppd -v
Upgrade notes
@@ -73,6 +73,10 @@ know it works on your hardware, add a "reboot=warm" command line option
in Lilo. A small number of machines need "reboot=bios" to reboot via
the BIOS.
+ Also, please remember that cua* devices are now obsolete. Switch to
+the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 ->
+ttyS1, etc.).
+
Libc
====
@@ -109,6 +113,12 @@ Modules
You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later.
This version will also work with 2.0.x kernels.
+ As of 2.1.90-pre1, kerneld has been replaced by a kernel thread,
+kmod. See Documentation/kmod.txt for more information. The main
+user-level change this requires is modification to your init scripts to
+check for the absence of /proc/sys/kernel/modprobe before starting
+kerneld.
+
Binutils
========
@@ -148,7 +158,7 @@ in some standard tools. Check in /proc/net/rt_local to verify their
presence.
To turn on IP forwarding, issue the following command: echo 1 >
-/proc/sys/net/ipv4/ip_forwarding
+/proc/sys/net/ipv4/ip_forward
To run bootpd, you'll need to issue the following command: echo 1
>/proc/sys/net/ipv4/ip_boot_agent
@@ -266,12 +276,12 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3
Linux C Library
===============
-The 5.4.38 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.38.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.38.bin.tar.gz
+The 5.4.44 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.44.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.44.bin.tar.gz
Installation notes for 5.4.38:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.38
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.38
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.44
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.44
Linux C++ Library
=================
@@ -308,7 +318,7 @@ Procinfo utilities
==================
The 0.11 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.13.tar.gz
RPM utilities
=============
@@ -391,8 +401,8 @@ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz
Pcmcia-cs
=========
-The 1.9.12 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-2.9.12.tar.gz
+The 3.0.0 release:
+ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-3.0.0.tar.gz
PPP
===
@@ -415,11 +425,12 @@ distribution), most of these are available in RPM format. Check around
your favorite Red Hat mirror site before installing the non-RPM
version. Remember, you might need to use the -force option to get the
upgrade to install. ftp://ftp.redhat.com/pub/contrib/ will have almost
-everything you need.
+everything you need, as does RedHat 5.0.
Those of you running Debian (or a different distribution that
supports .deb packages) can look in the "unstable" and
-"project/experimental" directories of your favorite Debian mirror.
+"project/experimental" directories of your favorite Debian mirror. The
+Debian 2.0 release should have most packages you need as well.
For others, David Bourgin has put together a package of everything
necessary to quickly and easily upgrade to 2.1.x. See
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index daea952c7..eddc729b8 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -103,6 +103,17 @@ CONFIG_MATH_EMULATION
you are not sure, say Y; apart from resulting in a 45kB bigger
kernel, it won't hurt.
+Max physical memory
+CONFIG_MAX_MEMSIZE
+ Linux/x86 can use up to 3.8 gigabytes of physical memory. Default
+ is max 1 gigabyte physical memory (1024 MB), this is enough for
+ most systems.
+ A system with 2G physical memory should use a value of ~2400, a
+ system with 3.8G memory should use something like 3900. A bit of
+ experimentation with the limit wont hurt, the kernel needs a ~128M
+ window for vmalloc() plus PCI space uses up some memory too, thus
+ addresses above FD000000 should rather be kept free.
+
Normal floppy disk support
CONFIG_BLK_DEV_FD
If you want to use your floppy disk drive(s) under Linux, say
@@ -1343,21 +1354,12 @@ CONFIG_MODVERSIONS
non-kernel sources, you would benefit from this option. Otherwise
it's not that important. So, N ought to be a safe bet.
-Kernel daemon support
-CONFIG_KERNELD
- Normally when you have selected some drivers and/or filesystems to
- be created as loadable modules, you also have the responsibility to
- load the corresponding module (via insmod/modprobe) before you can
- use it. If you select Y here, the kernel will take care of this all
- by itself, together with the user level daemon "kerneld". Note that
- "kerneld" will also automatically unload all unused modules, so you
- don't have to use "rmmod" either. kerneld will also provide support
- for different user-level beeper and screen blanker programs later
- on. The "kerneld" daemon is included in the modutils package (check
- Documentation/Changes for latest version and location). You will
- probably want to read the kerneld mini-HOWTO, available via ftp
- (user: anonymous) from
- sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y.
+Kernel module loader support
+CONFIG_KMOD
+ This feature allows the kernel to load modules for itself. When
+ a part of the kernel needs a module, it runs modprobe with the
+ appropriate arguments. Say Y here and read about configuring it
+ in Documentation/kmod.txt. (this is a replacement of kerneld)
ARP daemon support (EXPERIMENTAL)
CONFIG_ARPD
@@ -6135,9 +6137,9 @@ CONFIG_ZFTAPE
loadable module called `zft-compressor.o' which contains code to
support user transparent on-the-fly compression based on Ross
William's lzrw3 algorithm will be produced. If you have enabled
- auto-loading of kernel modules via `kerneld' (i.e. have said `Y' to
- CONFIG_KERNELD) then `zft-compressor.o' will be loaded automatically
- by zftape when needed.
+ the kernel module loader (i.e. have said `Y' to CONFIG_KMOD) then
+ `zft-compressor.o' will be loaded automatically by zftape when
+ needed.
Despite of its name zftape does NOT use compression by default. The
file Documentation/ftape.txt contains a short description of the
most important changes in the file system interface compared to
@@ -6595,12 +6597,6 @@ CONFIG_JOYSTICK
be called joystick.o. If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-ARC console time
-CONFIG_RTC_ARC
- If you boot your Alpha using the ARC firmware, say Y here. This option
- adjusts the RTC clock to take into account the different starting epoch
- used by ARC.
-
Sound card support
CONFIG_SOUND
If you have a Sound Card in your Computer, i.e. if it can say more
@@ -6636,6 +6632,16 @@ CONFIG_SB
an unknown card you may answer Y if the card claims to be
SoundBlaster compatible.
+Are you using the IBM Mwave "emulation" of SB ?
+CONFIG_SB_MWAVE
+ The IBM Mwave can do whats loosely describable as emulation of an 8bit
+ soundblaster if you load the right firmware from DOS warm boot and pray
+ and your machine happens to like you. Say Y if you are doing this as the
+ IRQ test normally fails on the mwave emulation. If you'd like real MWAVE
+ support phone IBM (425-556-8822) and ask them why they still haven't
+ released any documentation.
+ [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html]
+
Generic OPL2/OPL3 FM synthesizer support
CONFIG_ADLIB
Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
diff --git a/Documentation/cdrom/ide-cd b/Documentation/cdrom/ide-cd
index d6ceef8a5..ecd498158 100644
--- a/Documentation/cdrom/ide-cd
+++ b/Documentation/cdrom/ide-cd
@@ -224,10 +224,8 @@ a. Drive is not detected during booting.
- If the autoprobing is not finding your drive, you can tell the
driver to assume that one exists by using a lilo option of the
form `hdX=cdrom', where X is the drive letter corresponding to
- where your drive is installed (see section 2). This is required
- for CDROM drives such as the Pioneer DR-A24X, which do not properly
- identify themselves as ATAPI CDROM drives. Note that if you
- do this and you see a boot message like
+ where your drive is installed. Note that if you do this and you
+ see a boot message like
hdX: ATAPI cdrom (?)
@@ -281,7 +279,16 @@ b. Timeout/IRQ errors.
there are hardware problems with the interrupt setup; they
apparently don't use interrupts.
-
+ - If you own a Pioneer DR-A24X, you _will_ get nasty error messages
+ on boot such as "irq timeout: status=0x50 { DriveReady SeekComplete }"
+ The Pioneer DR-A24X cdrom drives are fairly popular these days.
+ Unfortunatly, these drives seem to become very confused when we perform
+ the standard Linux ATA disk drive probe. If you own one of these drives,
+ you can bypass the ATA probing which confuses these cdrom drives, by
+ adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing
+ lilo (again where X is the drive letter corresponding to where your drive
+ is installed.)
+
c. System hangups.
- If the system locks up when you try to access the cdrom, the most
diff --git a/Documentation/kmod.txt b/Documentation/kmod.txt
new file mode 100644
index 000000000..3deeeaed8
--- /dev/null
+++ b/Documentation/kmod.txt
@@ -0,0 +1,47 @@
+Kmod: The Kernel Module Loader
+Kirk Petersen
+
+Kmod is a simple replacement for kerneld. It consists of a
+request_module() replacement and a kernel thread called kmod. When the
+kernel requests a module, the kmod wakes up and execve()s modprobe,
+passing it the name that was requested. After a configurable period of
+time, kmod will have delete_module() remove any unused modules.
+
+Kmod is configurable through two entries in /proc/sys/kernel. You can
+set the path of modprobe (where the kernel looks for it) by doing:
+
+ echo "/sbin/modprobe" > /proc/sys/kernel/modprobe
+
+To tell kmod when to unload unused modules, do something like:
+
+ echo "120" > /proc/sys/kernel/kmod_unload_delay
+
+Kmod only loads and unloads modules. Kerneld could do more (although
+nothing in the standard kernel used its other features). If you
+require features such as request_route, we suggest that you take
+a similar approach. A simple request_route function could be called,
+and a kroute kernel thread could be sent off to do the work. But
+we should probably keep this to a minimum.
+
+Kerneld also had a mechanism for storing device driver settings. This
+can easily be done with modprobe. When a module is unloaded, modprobe
+could look at a per-driver-configurable location (/proc/sys/drivers/blah)
+for device driver settings and save them to a file. When a module
+is loaded, simply cat that file back to that location in the proc
+filesystem. Or perhaps a script could be a setting in /etc/modules.conf.
+There are many user-land methods that will work (I prefer using /proc,
+myself).
+
+If kerneld worked, why replace it?
+
+- kerneld used sysv ipc, which can now be made into a module. Besides,
+ sysv ipc is ugly and should therefore be avoided (well, certainly for
+ kernel level stuff)
+
+- both kmod and kerneld end up doing the same thing (calling modprobe),
+ so why not skip the middle man?
+
+- removing kerneld related stuff from ipc/msg.c made it 40% smaller
+
+- kmod reports errors through the normal kernel mechanisms, which avoids
+ the chicken and egg problem of kerneld and modular unix domain sockets
diff --git a/Documentation/modules.txt b/Documentation/modules.txt
index b637da0a4..ca9c434f7 100644
--- a/Documentation/modules.txt
+++ b/Documentation/modules.txt
@@ -10,6 +10,12 @@ Some older modules packages aren't aware of some of the newer modular
features that the kernel now supports. The current required version
is listed in the file linux/Documentation/Changes.
+* * * NOTE * * *
+The kernel has been changed to remove kerneld support and use
+the new kmod support. Keep this in mind when reading this file. Kmod
+does the exact same thing as kerneld, but doesn't require an external
+program (see Documentation/kmod.txt)
+
In the beginning...
-------------------
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index a9f5d9058..818d00f40 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -16,6 +16,7 @@ usage.
Currently, these files are in /proc/sys/vm:
- bdflush
+- buffermem
- freepages
- overcommit_memory
- swapctl
@@ -88,11 +89,27 @@ number of jiffies per second is 100, except on Alpha machines
age_super is for filesystem metadata.
==============================================================
+buffermem:
+
+The three values in this file correspond to the values in
+the struct buffer_mem. It controls how much memory should
+be used for buffer and cache memory. Note that memorymapped
+files are also counted as cache memory...
+
+The values are:
+min_percent -- this is the minumum percentage of memory
+ that should be spent on buffer + page cache
+borrow_percent -- when Linux is short on memory, and buffer
+ and cache use more than this percentage of
+ memory, free pages are stolen from them
+max_percent -- this is the maximum amount of memory that
+ can be used for buffer and cache memory
+==============================================================
freepages:
-This file contains three values: min_free_pages, free_pages_low
-and free_pages_high in order.
+This file contains the values in the struct freepages. That
+struct contains three members: min, low and high.
These numbers are used by the VM subsystem to keep a reasonable
number of pages on the free page list, so that programs can
@@ -100,25 +117,23 @@ allocate new pages without having to wait for the system to
free used pages first. The actual freeing of pages is done
by kswapd, a kernel daemon.
-min_free_pages -- when the number of free pages reaches this
- level, only the kernel can allocate memory
- for _critical_ tasks only
-free_pages_low -- when the number of free pages drops below
- this level, kswapd is woken up immediately
-free_pages_high -- this is kswapd's target, when more than
- free_pages_high pages are free, kswapd will
- stop swapping.
+min -- when the number of free pages reaches this
+ level, only the kernel can allocate memory
+ for _critical_ tasks only
+low -- when the number of free pages drops below
+ this level, kswapd is woken up immediately
+high -- this is kswapd's target, when more than <high>
+ pages are free, kswapd will stop swapping.
-When the number of free pages is between free_pages_low and
-free_pages_high, and kswapd hasn't run for swapout_interval
-jiffies, then kswapd is woken up too. See swapout_interval
-for more info.
+When the number of free pages is between low and high,
+and kswapd hasn't run for swapout_interval jiffies, then
+kswapd is woken up too. See swapout_interval for more info.
When free memory is always low on your system, and kswapd has
trouble keeping up with allocations, you might want to
-increase these values, especially free_pages_high and perhaps
-free_pages_low. I've found that a 1:2:4 relation for these
-values tend to work rather well in a heavily loaded system.
+increase these values, especially high and perhaps low.
+I've found that a 1:2:4 relation for these values tend to work
+rather well in a heavily loaded system.
==============================================================
@@ -163,9 +178,7 @@ static inline int vm_enough_memory(long pages)
swapctl:
-This file contains no less than 16 variables, of which about
-half is actually used :-) In the listing below, the unused
-variables are marked as such.
+This file contains no less than 8 variables.
All of these values are used by kswapd, and the usage can be
found in linux/mm/vmscan.c.
@@ -177,18 +190,10 @@ typedef struct swap_control_v5
unsigned int sc_page_advance;
unsigned int sc_page_decline;
unsigned int sc_page_initial_age;
- unsigned int sc_max_buff_age; /* unused */
- unsigned int sc_buff_advance; /* unused */
- unsigned int sc_buff_decline; /* unused */
- unsigned int sc_buff_initial_age; /* unused */
unsigned int sc_age_cluster_fract;
unsigned int sc_age_cluster_min;
unsigned int sc_pageout_weight;
unsigned int sc_bufferout_weight;
- unsigned int sc_buffer_grace; /* unused */
- unsigned int sc_nr_buffs_to_free; /* unused */
- unsigned int sc_nr_pages_to_free; /* unused */
- enum RCL_POLICY sc_policy; /* RCL_PERSIST hardcoded */
} swap_control_v5;
--------------------------------------------------------------
@@ -207,9 +212,8 @@ is adjusted according to the following scheme:
(default 1)
And when a page reaches age 0, it's ready to be swapped out.
-The variables sc_age_cluster_fract till sc_bufferout_weight
-have to do with the amount of scanning kswapd is doing on
-each call to try_to_swap_out().
+The next four variables can be used to control kswapd's
+agressiveness in swapping out pages.
sc_age_cluster_fract is used to calculate how many pages from
a process are to be scanned by kswapd. The formula used is
@@ -221,9 +225,12 @@ also scan small processes.
The values of sc_pageout_weight and sc_bufferout_weight are
used to control the how many tries kswapd will do in order
-to swapout one page / buffer. As with sc_age_cluster_fract,
-the actual value is calculated by several more or less complex
-formulae and the default value is good for every purpose.
+to swapout one page / buffer. These values can be used to
+finetune the ratio between user pages and buffer/cache memory.
+When you find that your Linux system is swapping out too much
+process pages in order to satisfy buffer memory demands, you
+might want to either increase sc_bufferout_weight, or decrease
+the value of sc_pageout_weight.
==============================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 81bf2aeb4..b8198cbf3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -275,8 +275,8 @@ M: oe1kib@oe1xtu.ampr.org
L: linux-hams@vger.rutgers.edu
S: Maintained
-HP100: Driver for HP 10/100 Mbit/s Network Adapter Series
-P: Jarsolav Kysela
+HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
+P: Jaroslav Kysela
M: perex@jcu.cz
S: Maintained
@@ -604,6 +604,12 @@ P: Jean Tourrilhes
M: jt@hplb.hpl.hp.com
S: Maintained
+WD7000 SCSI DRIVER
+P: Miroslav Zagorac
+M: zaga@fly.cc.fer.hr
+L: linux-scsi@vger.rutgers.edu
+S: Maintained
+
Z8530 DRIVER FOR AX.25
P: Joerg Reuter
M: jreuter@poboxes.com
diff --git a/Makefile b/Makefile
index 5f233a827..5a2892a78 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 89
+SUBLEVEL = 90
ARCH = mips
@@ -9,7 +9,7 @@ ARCH = mips
# because it makes re-config very ugly and too many fundamental files depend
# on "CONFIG_SMP"
#
-# NOTE! SMP is experimental. See the file Documentation/SMP.txt
+# For UP operations COMMENT THIS OUT, simply setting SMP = 0 won't work
#
# SMP = 1
#
@@ -270,6 +270,7 @@ include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
include/linux/version.h: ./Makefile
@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver
@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
+ @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
@mv -f .ver $@
init/version.o: init/version.c include/linux/compile.h
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index bda9ca130..1fefe0c62 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -23,7 +23,7 @@ bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
MODULES=y
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index 8c1a4f696..1bdecf444 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -12,7 +12,7 @@
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-# CONFIG_KERNELD is not set
+# CONFIG_KMOD is not set
#
# General setup
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 53741095c..132175541 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -13,6 +13,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
@@ -146,3 +147,7 @@ EXPORT_SYMBOL_NOVERS(__remq);
EXPORT_SYMBOL_NOVERS(__remqu);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 6a90ecb02..f8146c54f 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -39,6 +39,7 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/hwrpb.h>
+#include <asm/fpu.h>
/*
* Initial task structure. Make this a per-architecture thing,
@@ -50,6 +51,7 @@
unsigned long init_user_stack[1024] = { STACK_MAGIC, };
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
@@ -198,6 +200,10 @@ void exit_thread(void)
void flush_thread(void)
{
+ /* Arrange for each exec'ed process to start off with a
+ clean slate wrt the fpu. */
+ current->tss.flags &= ~IEEE_SW_MASK;
+ wrfpcr(FPCR_DYN_NORMAL);
}
void release_thread(struct task_struct *dead_task)
diff --git a/arch/arm/config.in b/arch/arm/config.in
index 2b5303196..b95c2f16e 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -16,7 +16,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/arm/defconfig b/arch/arm/defconfig
index c3a14ebcd..48358557b 100644
--- a/arch/arm/defconfig
+++ b/arch/arm/defconfig
@@ -13,7 +13,7 @@ CONFIG_EXPERIMENTAL=y
#
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
#
# General setup
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 19666ac1e..20c62e2e6 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -4,6 +4,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/mman.h>
+#include <linux/pci.h>
#include <asm/ecard.h>
#include <asm/io.h>
@@ -176,3 +177,7 @@ EXPORT_SYMBOL(change_bit);
EXPORT_SYMBOL(test_and_change_bit);
EXPORT_SYMBOL(find_first_zero_bit);
EXPORT_SYMBOL(find_next_zero_bit);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index acc206942..90ae6952f 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct files * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/i386/.kernel_offset.lds b/arch/i386/.kernel_offset.lds
new file mode 100644
index 000000000..9cfd927bf
--- /dev/null
+++ b/arch/i386/.kernel_offset.lds
@@ -0,0 +1 @@
+__kernel_offset__ = (0x1000-1024)*1024*1024;
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 98bde850f..359c20b9b 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -58,6 +58,9 @@ SUBDIRS := $(SUBDIRS) arch/i386/math-emu
DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
endif
+memsize: dummy
+ @echo "__kernel_offset__ = (0x1000-$(CONFIG_MAX_MEMSIZE))*1024*1024;" > arch/i386/.kernel_offset.lds
+
arch/i386/kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
@@ -66,27 +69,27 @@ arch/i386/mm: dummy
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-zImage: vmlinux
+zImage: memsize vmlinux
@$(MAKEBOOT) zImage
-bzImage: vmlinux
+bzImage: memsize vmlinux
@$(MAKEBOOT) bzImage
compressed: zImage
-zlilo: vmlinux
+zlilo: memsize vmlinux
@$(MAKEBOOT) BOOTIMAGE=zImage zlilo
-bzlilo: vmlinux
+bzlilo: memsize vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
-zdisk: vmlinux
+zdisk: memsize vmlinux
@$(MAKEBOOT) BOOTIMAGE=zImage zdisk
-bzdisk: vmlinux
+bzdisk: memsize vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
-install: vmlinux
+install: memsize vmlinux
@$(MAKEBOOT) BOOTIMAGE=bzImage install
archclean:
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 3e52c2218..058f908e3 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -17,6 +17,7 @@ choice 'Processor family' \
Pentium/K5/5x86/6x86 CONFIG_M586 \
PPro/K6/6x86MX CONFIG_M686" Pentium
bool 'Math emulation' CONFIG_MATH_EMULATION
+int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024
endmenu
mainmenu_option next_comment
@@ -24,7 +25,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 2ca6da6bc..f3792ce05 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -15,13 +15,14 @@
CONFIG_M586=y
# CONFIG_M686 is not set
# CONFIG_MATH_EMULATION is not set
+CONFIG_MAX_MEMSIZE=1024
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-# CONFIG_KERNELD is not set
+# CONFIG_KMOD is not set
#
# General setup
@@ -30,7 +31,6 @@ CONFIG_NET=y
CONFIG_PCI=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
-# CONFIG_PCI_OPTIMIZE is not set
CONFIG_PCI_OLD_PROC=y
# CONFIG_MCA is not set
CONFIG_SYSVIPC=y
@@ -94,7 +94,6 @@ CONFIG_INET=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 6722c4f7f..048921838 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -11,6 +11,9 @@
#include <linux/tasks.h>
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
#define CL_MAGIC_ADDR 0x90020
#define CL_MAGIC 0xA33F
@@ -54,9 +57,9 @@ startup_32:
* be using the global pages.
*
* NOTE! We have to correct for the fact that we're
- * not yet offset 0xC0000000..
+ * not yet offset PAGE_OFFSET..
*/
-#define cr4_bits mmu_cr4_features-0xC0000000
+#define cr4_bits mmu_cr4_features-__PAGE_OFFSET
movl %cr4,%eax # Turn on 4Mb pages
orl cr4_bits,%eax
movl %eax,%cr4
@@ -368,7 +371,7 @@ check_x87:
* sets up a idt with 256 entries pointing to
* ignore_int, interrupt gates. It doesn't actually load
* idt - that can be done only after paging has been enabled
- * and the kernel moved to 0xC0000000. Interrupts
+ * and the kernel moved to PAGE_OFFSET. Interrupts
* are enabled elsewhere, when we can be relatively
* sure everything is ok.
*/
@@ -444,14 +447,16 @@ SYMBOL_NAME(gdt):
/*
* This is initialized to create a identity-mapping at 0-4M (for bootup
* purposes) and another mapping of the 0-4M area at virtual address
- * 0xC0000000.
+ * PAGE_OFFSET.
*/
.org 0x1000
ENTRY(swapper_pg_dir)
.long 0x00102007
- .fill 767,4,0
+ .fill __USER_PGD_PTRS-1,4,0
+ /* default: 767 entries */
.long 0x00102007
- .fill 255,4,0
+ /* default: 255 entries */
+ .fill __KERNEL_PGD_PTRS-1,4,0
/*
* The page tables are initialized to only 4MB here - the final page
@@ -614,8 +619,8 @@ ENTRY(idt_table)
.fill 256,8,0 # idt is uninitialized
/*
- * This gdt setup gives the kernel a 1GB address space at virtual
- * address 0xC0000000 - space enough for expansion, I hope.
+ * This gdt setup gives the kernel a CONFIG_MAX_MEMSIZE sized address space at
+ * virtual address PAGE_OFFSET.
*
* This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
* gdt entries. Ugh.
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index e5812400e..d2837d648 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -8,6 +8,7 @@
#include <linux/in6.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
+#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -97,3 +98,6 @@ EXPORT_SYMBOL(mca_isenabled);
EXPORT_SYMBOL(mca_isadapter);
#endif
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
index acc206942..c0571c769 100644
--- a/arch/i386/kernel/init_task.c
+++ b/arch/i386/kernel/init_task.c
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index be074cac6..219e7f853 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -271,7 +271,7 @@ void setup_IO_APIC_irqs (void)
if (!IO_APIC_IRQ(irq))
continue;
- entry.vector = IO_APIC_GATE_OFFSET + (irq<<3);
+ entry.vector = IO_APIC_VECTOR(irq);
/*
* Determine IRQ line polarity (high active or low active):
@@ -383,7 +383,7 @@ void setup_IO_APIC_irq_ISA_default (unsigned int irq)
entry.mask = 1; /* unmask IRQ now */
entry.dest.logical.logical_dest = 0xff; /* all CPUs */
- entry.vector = IO_APIC_GATE_OFFSET + (irq<<3);
+ entry.vector = IO_APIC_VECTOR(irq);
entry.polarity=0;
entry.trigger=0;
@@ -513,7 +513,7 @@ void print_IO_APIC (void)
return;
}
-void init_sym_mode (void)
+static void init_sym_mode (void)
{
printk("enabling Symmetric IO mode ... ");
outb (0x70, 0x22);
@@ -521,6 +521,14 @@ void init_sym_mode (void)
printk("...done.\n");
}
+void init_pic_mode (void)
+{
+ printk("disabling Symmetric IO mode ... ");
+ outb (0x70, 0x22);
+ outb (0x00, 0x23);
+ printk("...done.\n");
+}
+
char ioapic_OEM_ID [16];
char ioapic_Product_ID [16];
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index 9bb150075..44fd26530 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/stddef.h>
/* 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)
@@ -53,12 +54,25 @@ 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)
{
+ struct thread_struct * t = &current->tss;
+
if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
return -EINVAL;
if (!suser())
return -EPERM;
+ /*
+ * If it's the first ioperm() call in this thread's lifetime, set the
+ * IO bitmap up. ioperm() is much less timing critical than clone(),
+ * this is why we delay this operation until now:
+ */
+#define IO_BITMAP_OFFSET offsetof(struct thread_struct,io_bitmap)
+
+ if (t->bitmap != IO_BITMAP_OFFSET) {
+ t->bitmap = IO_BITMAP_OFFSET;
+ memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
+ }
- set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
+ set_bitmap((unsigned long *)t->io_bitmap, from, num, !turn_on);
return 0;
}
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 24c33be65..4823c1546 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -70,6 +70,7 @@ spinlock_t irq_controller_lock;
static unsigned int irq_events [NR_IRQS] = { -1, };
static int disabled_irq [NR_IRQS] = { 0, };
+static int ipi_pending [NR_IRQS] = { 0, };
/*
* Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
@@ -489,12 +490,8 @@ static inline void wait_on_irq(int cpu)
*/
void synchronize_bh(void)
{
- if (atomic_read(&global_bh_count)) {
- int cpu = smp_processor_id();
- if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
+ if (atomic_read(&global_bh_count) && !in_interrupt())
wait_on_bh();
- }
- }
}
/*
@@ -672,8 +669,8 @@ void enable_8259A_irq (unsigned int irq)
#ifdef __SMP__
void enable_ioapic_irq (unsigned int irq)
{
- unsigned long flags;
- int cpu = smp_processor_id(), should_handle_irq;
+ unsigned long flags, should_handle_irq;
+ int cpu = smp_processor_id();
spin_lock_irqsave(&irq_controller_lock, flags);
if (disabled_irq[irq])
@@ -682,18 +679,32 @@ void enable_ioapic_irq (unsigned int irq)
spin_unlock_irqrestore(&irq_controller_lock, flags);
return;
}
+#if 0
/*
* In the SMP+IOAPIC case it might happen that there are an unspecified
- * number of pending IRQ events unhandled. We protect against multiple
- * enable_irq()'s executing them via disable_irq[irq]++
+ * number of pending IRQ events unhandled. These cases are very rare,
+ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
+ * better to do it this way as thus we dont have to be aware of
+ * 'pending' interrupts in the IRQ path, except at this point.
*/
if (!disabled_irq[irq] && irq_events[irq]) {
+ if (!ipi_pending[irq]) {
+ ipi_pending[irq] = 1;
+ --irq_events[irq];
+ send_IPI(cpu,IO_APIC_VECTOR(irq));
+ }
+ }
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+#else
+ if (!disabled_irq[irq] && irq_events[irq]) {
struct pt_regs regs; /* FIXME: these are fake currently */
disabled_irq[irq]++;
+ hardirq_enter(cpu);
spin_unlock(&irq_controller_lock);
+
release_irqlock(cpu);
- irq_enter(cpu, irq);
+ while (test_bit(0,&global_irq_lock)) mb();
again:
handle_IRQ_event(irq, &regs);
@@ -713,6 +724,7 @@ again:
__restore_flags(flags);
} else
spin_unlock_irqrestore(&irq_controller_lock, flags);
+#endif
}
#endif
@@ -775,15 +787,16 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
ack_APIC_irq();
spin_lock(&irq_controller_lock);
+ if (ipi_pending[irq])
+ ipi_pending[irq] = 0;
if (!irq_events[irq]++ && !disabled_irq[irq])
should_handle_irq = 1;
-
+ hardirq_enter(cpu);
spin_unlock(&irq_controller_lock);
- irq_enter(cpu, irq);
-
if (should_handle_irq) {
+ while (test_bit(0,&global_irq_lock)) mb();
again:
handle_IRQ_event(irq, regs);
@@ -797,7 +810,8 @@ again:
goto again;
}
- irq_exit(cpu, irq);
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
}
#endif
@@ -1034,7 +1048,7 @@ void init_IO_APIC_traps(void)
* 0x80, because int 0x80 is hm, kindof importantish ;)
*/
for (i = 0; i < NR_IRQS ; i++)
- if (IO_APIC_GATE_OFFSET+(i<<3) <= 0xfe) /* HACK */ {
+ if (IO_APIC_VECTOR(i) <= 0xfe) /* HACK */ {
if (IO_APIC_IRQ(i)) {
irq_handles[i] = &ioapic_irq_type;
/*
@@ -1071,8 +1085,8 @@ __initfunc(void init_IRQ(void))
#ifdef __SMP__
for (i = 0; i < NR_IRQS ; i++)
- if (IO_APIC_GATE_OFFSET+(i<<3) <= 0xfe) /* hack -- mingo */
- set_intr_gate(IO_APIC_GATE_OFFSET+(i<<3),interrupt[i]);
+ if (IO_APIC_VECTOR(i) <= 0xfe) /* hack -- mingo */
+ set_intr_gate(IO_APIC_VECTOR(i),interrupt[i]);
/*
* The reschedule interrupt slowly changes it's functionality,
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 6404bc9e3..9824026dc 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -2,13 +2,12 @@
#define __irq_h
/*
- * Various low-level irq details needed by irq.c and smp.c
+ * Various low-level irq details needed by irq.c, process.c,
+ * time.c, io_apic.c and smp.c
*
* Interrupt entry/exit code at both C and assembly level
*/
-#define IO_APIC_GATE_OFFSET 0x51
-
void mask_irq(unsigned int irq);
void unmask_irq(unsigned int irq);
void enable_IO_APIC_irq (unsigned int irq);
@@ -19,9 +18,16 @@ void setup_IO_APIC (void);
void init_IO_APIC_traps(void);
int IO_APIC_get_PCI_irq_vector (int bus, int slot, int fn);
void make_8259A_irq (unsigned int irq);
+void send_IPI (int dest, int vector);
+void init_pic_mode (void);
extern unsigned int io_apic_irqs;
+extern inline int IO_APIC_VECTOR (int irq)
+{
+ return (0x51+(irq<<3));
+}
+
#define MAX_IRQ_SOURCES 128
#define MAX_MP_BUSSES 32
enum mp_bustype {
@@ -38,6 +44,7 @@ extern spinlock_t irq_controller_lock; /*
* IO-APIC
*/
+
#ifdef __SMP__
#include <asm/atomic.h>
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 629e7ef12..6f2245790 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -44,6 +44,7 @@
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif
+#include "irq.h"
#ifdef __SMP__
asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork");
@@ -280,6 +281,12 @@ static inline void kb_wait(void)
void machine_restart(char * __unused)
{
+#if __SMP__
+ /*
+ * turn off the IO-APIC, so we can do a clean reboot
+ */
+ init_pic_mode();
+#endif
if(!reboot_thru_bios) {
/* rebooting needs to touch the page at absolute addr 0 */
@@ -314,10 +321,10 @@ void machine_restart(char * __unused)
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
- virtual address 0xc0000000. */
+ virtual address PAGE_OFFSET. */
- memcpy (swapper_pg_dir, swapper_pg_dir + 768,
- sizeof (swapper_pg_dir [0]) * 256);
+ memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
@@ -473,7 +480,6 @@ void release_thread(struct task_struct *dead_task)
int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
struct task_struct * p, struct pt_regs * regs)
{
- int i;
struct pt_regs * childregs;
p->tss.tr = _TSS(nr);
@@ -510,9 +516,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
else
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
- p->tss.bitmap = offsetof(struct thread_struct,io_bitmap);
- for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
- p->tss.io_bitmap[i] = ~0;
+ /*
+ * a bitmap offset pointing outside of the TSS limit causes a nicely
+ * controllable SIGSEGV. The first sys_ioperm() call sets up the
+ * bitmap properly.
+ */
+ p->tss.bitmap = sizeof(struct thread_struct);
+
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index ca2147ee7..d05b54b63 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -371,7 +371,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (pid == 1) /* you may not mess with init */
goto out;
ret = -ESRCH;
- if (!(child = find_task_by_pid(pid)))
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!!! */
+ if (!child)
goto out;
ret = -EPERM;
if (request == PTRACE_ATTACH) {
@@ -390,9 +393,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
+ unsigned long flags;
+
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
}
send_sig(SIGSTOP, child, 1);
ret = 0;
@@ -545,6 +552,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
case PTRACE_DETACH: { /* detach a process that was attached. */
+ unsigned long flags;
long tmp;
ret = -EIO;
@@ -553,9 +561,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
/* 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);
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 6f4bc60ec..9ca377128 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -1108,23 +1108,59 @@ __initfunc(void smp_boot_cpus(void))
setup_IO_APIC();
}
+
+void send_IPI (int dest, int vector)
+{
+ unsigned long cfg;
+ unsigned long flags;
+
+ __save_flags(flags);
+ __cli();
+
+ /*
+ * prepare target chip field
+ */
+
+ cfg = apic_read(APIC_ICR2) & 0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(dest));
+
+ cfg = apic_read(APIC_ICR);
+ cfg &= ~0xFDFFF;
+ cfg |= APIC_DEST_FIELD|APIC_DEST_DM_FIXED|vector;
+ cfg |= dest;
+
+ /*
+ * Send the IPI. The write to APIC_ICR fires this off.
+ */
+
+ apic_write(APIC_ICR, cfg);
+ __restore_flags(flags);
+}
+
+void funny (void)
+{
+ send_IPI(APIC_DEST_ALLBUT,0x30 /*IO_APIC_VECTOR(11)*/);
+ for(;;)__cli();
+}
+
/*
- * A non wait message cannot pass data or cpu source info. This current setup
- * is only safe because the kernel lock owner is the only person who can send a message.
+ * A non wait message cannot pass data or cpu source info. This current setup
+ * is only safe because the kernel lock owner is the only person who can send
+ * a message.
*
- * Wrapping this whole block in a spinlock is not the safe answer either. A processor may
- * get stuck with irq's off waiting to send a message and thus not replying to the person
- * spinning for a reply....
+ * Wrapping this whole block in a spinlock is not the safe answer either. A
+ * processor may get stuck with irq's off waiting to send a message and thus
+ * not replying to the person spinning for a reply....
*
- * In the end flush tlb ought to be the NMI and a very very short function (to avoid the old
- * IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That
- * will also boost performance.
+ * In the end flush tlb ought to be the NMI and a very very short function
+ * (to avoid the old IDE disk problems), and other messages sent with IRQ's
+ * enabled in a civilised fashion. That will also boost performance.
*/
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- unsigned long flags;
unsigned long cfg;
+ unsigned long dest = 0;
unsigned long target_map;
int p=smp_processor_id();
int irq;
@@ -1166,11 +1202,11 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
}
/*
- * Sanity check we don't re-enter this across CPU's. Only the kernel
- * lock holder may send messages. For a STOP_CPU we are bringing the
- * entire box to the fastest halt we can.. A reschedule carries
- * no data and can occur during a flush.. guess what panic
- * I got to notice this bug...
+ * Sanity check we don't re-enter this across CPU's. Only the kernel
+ * lock holder may send messages. For a STOP_CPU we are bringing the
+ * entire box to the fastest halt we can.. A reschedule carries
+ * no data and can occur during a flush.. guess what panic
+ * I got to notice this bug...
*/
/*
@@ -1183,11 +1219,11 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
p, msg, target);*/
/*
- * Wait for the APIC to become ready - this should never occur. Its
- * a debugging check really.
+ * Wait for the APIC to become ready - this should never occur. Its
+ * a debugging check really.
*/
- while(ct<1000)
+ while (ct<1000)
{
cfg=apic_read(APIC_ICR);
if(!(cfg&(1<<12)))
@@ -1204,49 +1240,32 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
/*
- * Program the APIC to deliver the IPI
- */
-
- __save_flags(flags);
- __cli();
- cfg=apic_read(APIC_ICR2);
- cfg&=0x00FFFFFF;
- apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */
- cfg=apic_read(APIC_ICR);
- cfg&=~0xFDFFF; /* Clear bits */
- cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
-
- /*
* Set the target requirement
*/
if(target==MSG_ALL_BUT_SELF)
{
- cfg|=APIC_DEST_ALLBUT;
+ dest=APIC_DEST_ALLBUT;
target_map=cpu_present_map;
cpu_callin_map[0]=(1<<p);
}
else if(target==MSG_ALL)
{
- cfg|=APIC_DEST_ALLINC;
+ dest=APIC_DEST_ALLINC;
target_map=cpu_present_map;
cpu_callin_map[0]=0;
}
else
- {
- target_map=(1<<target);
- cpu_callin_map[0]=0;
- }
+ panic("huh?");
/*
- * Send the IPI. The write to APIC_ICR fires this off.
+ * Program the APIC to deliver the IPI
*/
-
- apic_write(APIC_ICR, cfg);
- __restore_flags(flags);
+
+ send_IPI(dest,irq);
/*
- * Spin waiting for completion
+ * Spin waiting for completion
*/
switch(wait)
@@ -1443,6 +1462,7 @@ asmlinkage void smp_reschedule_interrupt(void)
int cpu = smp_processor_id();
ack_APIC_irq();
+ for (;;) __cli();
/*
* This looks silly, but we actually do need to wait
* for the global interrupt lock.
@@ -1694,8 +1714,10 @@ __initfunc(void setup_APIC_clock (void))
/*
* We ACK the APIC, just in case there is something pending.
*/
+
ack_APIC_irq ();
+
restore_flags(flags);
}
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index 9cee704f1..1f5303a9e 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -28,6 +28,7 @@
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/page.h>
.data
@@ -62,7 +63,7 @@ idt_48:
gdt_48:
.word 0x0800 # gdt limit = 2048, 256 GDT entries
- .long gdt_table-0xc0000000 # gdt base = gdt (first SMP CPU)
+ .long gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU)
.globl SYMBOL_NAME(trampoline_end)
SYMBOL_NAME_LABEL(trampoline_end)
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index f9172bdae..ef3ac57f4 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -204,8 +204,8 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
/* unmap the original low memory mappings */
pgd_val(pg_dir[0]) = 0;
- /* Map whole memory from 0xC0000000 */
- pg_dir += 768;
+ /* Map whole memory from PAGE_OFFSET */
+ pg_dir += USER_PGD_PTRS;
while (address < end_mem) {
/*
* If we're running on a Pentium CPU, we can use the 4MB
diff --git a/arch/i386/vmlinux.lds b/arch/i386/vmlinux.lds
index 7a1fd3d08..0284015ad 100644
--- a/arch/i386/vmlinux.lds
+++ b/arch/i386/vmlinux.lds
@@ -1,12 +1,13 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*/
+INCLUDE arch/i386/.kernel_offset.lds
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
- . = 0xc0100000;
+ . = __kernel_offset__ + 0x100000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c
index bc962f7d3..0eae9cfdb 100644
--- a/arch/m68k/amiga/amiga_ksyms.c
+++ b/arch/m68k/amiga/amiga_ksyms.c
@@ -2,6 +2,7 @@
#include <linux/types.h>
#include <linux/zorro.h>
#include <asm/amigahw.h>
+#include <linux/pci.h>
extern volatile u_short amiga_audio_min_period;
extern u_short amiga_audio_period;
@@ -24,3 +25,7 @@ EXPORT_SYMBOL(zorro_get_board);
EXPORT_SYMBOL(zorro_config_board);
EXPORT_SYMBOL(zorro_unconfig_board);
EXPORT_SYMBOL(zorro_unused_z2ram);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c
index 0eb19e4a0..86e34fb7f 100644
--- a/arch/m68k/atari/atari_ksyms.c
+++ b/arch/m68k/atari/atari_ksyms.c
@@ -1,4 +1,6 @@
#include <linux/module.h>
+#include <linux/pci.h>
+
#include <asm/ptrace.h>
#include <asm/traps.h>
#include <asm/atarihw.h>
@@ -40,3 +42,7 @@ EXPORT_SYMBOL(ikbd_mouse_rel_pos);
EXPORT_SYMBOL(ikbd_mouse_disable);
EXPORT_SYMBOL(atari_microwire_cmd);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index 0b287bb9d..4b90b6b02 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -14,7 +14,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index e9fe2175b..6ce3991d4 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -12,7 +12,7 @@ CONFIG_EXPERIMENTAL=y
#
# CONFIG_MODULES is not set
# CONFIG_MODVERSIONS is not set
-# CONFIG_KERNELD is not set
+# CONFIG_KMOD is not set
#
# Platform-dependent setup
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index a5c83712b..3e6721d69 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -7,6 +7,7 @@
#include <linux/elfcore.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
+#include <linux/pci.h>
#include <asm/setup.h>
#include <asm/machdep.h>
@@ -58,3 +59,7 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 2318caf81..a6fbd5718 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -40,6 +40,7 @@
*/
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/m68k/mac/ksyms.c b/arch/m68k/mac/ksyms.c
index 05373b04e..573e6f78e 100644
--- a/arch/m68k/mac/ksyms.c
+++ b/arch/m68k/mac/ksyms.c
@@ -1,7 +1,12 @@
#include <linux/module.h>
+#include <linux/pci.h>
#include <asm/ptrace.h>
#include <asm/traps.h>
/* Hook for mouse driver */
extern void (*mac_mouse_interrupt_hook) (char *);
EXPORT_SYMBOL(mac_mouse_interrupt_hook);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/mips/config.in b/arch/mips/config.in
index e33db8348..171170f3b 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -96,7 +96,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
index acc206942..90ae6952f 100644
--- a/arch/mips/kernel/init_task.c
+++ b/arch/mips/kernel/init_task.c
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct files * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 47807c294..95bdbdc5c 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 1996, 1997 by Ralf Baechle
*
- * $Id: mips_ksyms.c,v 1.4 1997/12/01 17:57:28 ralf Exp $
+ * $Id: mips_ksyms.c,v 1.5 1998/03/17 22:07:35 ralf Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/in6.h>
+#include <linux/pci.h>
#include <asm/checksum.h>
#include <asm/dma.h>
@@ -98,3 +99,7 @@ EXPORT_SYMBOL(__compute_return_epc);
EXPORT_SYMBOL(register_fpe);
EXPORT_SYMBOL(unregister_fpe);
#endif
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index e9d4340cb..ac5cd123b 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -11,7 +11,7 @@
* Don't waste that much memory for empty entries in the syscall
* table.
*
- * $Id: syscall.c,v 1.5 1997/12/16 05:34:37 ralf Exp $
+ * $Id: syscall.c,v 1.6 1998/03/17 22:07:36 ralf Exp $
*/
#undef CONF_PRINT_SYSCALLS
#undef CONF_DEBUG_IRIX
@@ -23,6 +23,7 @@
#include <linux/smp_lock.h>
#include <linux/mman.h>
#include <linux/sched.h>
+#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/unistd.h>
#include <asm/branch.h>
@@ -59,19 +60,22 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
int flags, int fd, off_t offset)
{
struct file * file = NULL;
- unsigned long res;
+ unsigned long error = -EFAULT;
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- res = do_mmap(file, addr, len, prot, flags, offset);
-
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ error = do_mmap(file, addr, len, prot, flags, offset);
+ if (file)
+ fput(file);
+out:
unlock_kernel();
- return res;
+ return error;
}
asmlinkage int sys_idle(void)
diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c
index ab61c564a..e86f3e4eb 100644
--- a/arch/mips/mm/r4xx0.c
+++ b/arch/mips/mm/r4xx0.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r4xx0.c,v 1.19 1998/01/18 02:49:41 ralf Exp $
+ * $Id: r4xx0.c,v 1.12 1998/03/03 16:57:26 ralf Exp $
*
* To do:
*
@@ -2379,7 +2379,7 @@ static void probe_icache(unsigned long config)
ic_lsize = 16 << ((config >> 4) & 1);
printk("Primary instruction cache %dkb, linesize %d bytes)\n",
- icache_size, ic_lsize);
+ icache_size >> 10, ic_lsize);
}
static void probe_dcache(unsigned long config)
@@ -2388,7 +2388,7 @@ static void probe_dcache(unsigned long config)
dc_lsize = 16 << ((config >> 4) & 1);
printk("Primary data cache %dkb, linesize %d bytes)\n",
- dcache_size, dc_lsize);
+ dcache_size >> 10, dc_lsize);
}
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 6a244a72a..72bab8928 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -32,7 +32,7 @@ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
define_bool CONFIG_PCI y
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index ae97abde6..7e5caa71d 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -19,7 +19,7 @@ CONFIG_COMMON=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_OPTIMIZE is not set
CONFIG_PCI_OLD_PROC=y
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 8f3225d59..6ec6258ab 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -6,6 +6,7 @@
#include <linux/string.h>
#include <linux/bios32.h>
#include <linux/interrupt.h>
+#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -147,3 +148,7 @@ EXPORT_SYMBOL(get_property);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(note_scsi_host);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index b2a1478cb..7ffaf58c0 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -64,6 +64,7 @@ task_top(struct task_struct *tsk)
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
index 8cd90e2c4..529b33138 100644
--- a/arch/ppc/pmac_defconfig
+++ b/arch/ppc/pmac_defconfig
@@ -19,7 +19,7 @@ CONFIG_COMMON=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
CONFIG_PCI=y
CONFIG_NET=y
CONFIG_SYSCTL=y
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
index de686193d..147fa3005 100644
--- a/arch/ppc/prep_defconfig
+++ b/arch/ppc/prep_defconfig
@@ -19,7 +19,7 @@ CONFIG_COMMON=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_OPTIMIZE is not set
CONFIG_NET=y
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index d7902e886..4a087fca2 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -14,7 +14,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 5641663e5..38b6096cc 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -12,7 +12,7 @@ CONFIG_EXPERIMENTAL=y
#
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
#
# General setup
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
index d0fc09346..1829daeea 100644
--- a/arch/sparc/kernel/init_task.c
+++ b/arch/sparc/kernel/init_task.c
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct files * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 635623fb3..e50f308c7 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -550,9 +550,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
}
child->flags |= PF_PTRACED;
if(child->p_pptr != current) {
+ unsigned long flags;
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
}
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
@@ -851,6 +854,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+ unsigned long flags;
if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
@@ -858,9 +862,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
pt_succ_return(regs, 0);
goto out;
}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index df3eac300..92be6f74d 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -15,6 +15,7 @@
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/in6.h>
+#include <linux/pci.h>
#include <asm/oplib.h>
#include <asm/delay.h>
@@ -271,3 +272,7 @@ EXPORT_SYMBOL_DOT(mul);
EXPORT_SYMBOL_DOT(umul);
EXPORT_SYMBOL_DOT(div);
EXPORT_SYMBOL_DOT(udiv);
+
+#if CONFIG_PCI
+EXPORT_SYMBOL(pci_devices);
+#endif
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 868fc2162..aa85666c6 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -17,6 +17,7 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/swapctl.h>
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h>
#endif
@@ -172,9 +173,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
struct cache_palias *sparc_aliases;
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
extern void srmmu_frob_mem_map(unsigned long);
int physmem_mapped_contig = 1;
@@ -265,11 +263,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
initpages << (PAGE_SHIFT-10),
PAGE_OFFSET, end_mem);
- min_free_pages = nr_free_pages >> 7;
- if(min_free_pages < 16)
- min_free_pages = 16;
- free_pages_low = min_free_pages + (min_free_pages >> 1);
- free_pages_high = min_free_pages + min_free_pages;
+ freepages.min = nr_free_pages >> 7;
+ if(freepages.min < 16)
+ freepages.min = 16;
+ freepages.low = freepages.min + (freepages.min >> 1);
+ freepages.high = freepages.min + freepages.min;
}
void free_initmem (void)
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 0bb079f4e..4461cdea0 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -14,7 +14,7 @@ comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
+ bool 'Kernel module loader' CONFIG_KMOD
fi
endmenu
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 7232deff2..f3c2e2ca4 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -12,7 +12,7 @@ CONFIG_EXPERIMENTAL=y
#
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+CONFIG_KMOD=y
#
# General setup
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index d0fc09346..1829daeea 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -6,6 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
+static struct files * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index cde799d92..6e1d30990 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -26,8 +26,8 @@
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
/* #define SYSCALL_TRACING */
@@ -327,7 +327,7 @@ void do_fpother(struct pt_regs *regs)
case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */
#ifdef CONFIG_MATHEMU_MODULE
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!handle_mathemu)
request_module("math-emu");
#endif
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 54dc8f265..b564dc0dc 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/blk.h>
#include <linux/swap.h>
+#include <linux/swapctl.h>
#include <asm/head.h>
#include <asm/system.h>
@@ -864,10 +865,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
return device_scan (PAGE_ALIGN (start_mem));
}
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
-
__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
{
unsigned long addr, tmp2 = 0;
@@ -946,11 +943,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
initpages << (PAGE_SHIFT-10),
PAGE_OFFSET, end_mem);
- min_free_pages = nr_free_pages >> 7;
- if(min_free_pages < 16)
- min_free_pages = 16;
- free_pages_low = min_free_pages + (min_free_pages >> 1);
- free_pages_high = min_free_pages + min_free_pages;
+ freepages.low = nr_free_pages >> 7;
+ if(freepages.low < 16)
+ freepages.low = 16;
+ freepages.low = freepages.low + (freepages.low >> 1);
+ freepages.high = freepages.low + freepages.low;
}
void free_initmem (void)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 8823e4c97..088980ead 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -534,6 +534,8 @@ static struct floppy_struct *_floppy = floppy_type;
static unsigned char current_drive = 0;
static long current_count_sectors = 0;
static unsigned char sector_t; /* sector in track */
+static unsigned char in_sector_offset; /* offset within physical sector,
+ * expressed in units of 512 bytes */
#ifndef fd_eject
#define fd_eject(x) -EINVAL
@@ -2252,7 +2254,7 @@ static void request_done(int uptodate)
/* Interrupt handler evaluating the result of the r/w operation */
static void rw_interrupt(void)
{
- int nr_sectors, ssize, eoc;
+ int nr_sectors, ssize, eoc, heads;
if (!DRS->first_read_date)
DRS->first_read_date = jiffies;
@@ -2264,23 +2266,32 @@ static void rw_interrupt(void)
eoc = 1;
else
eoc = 0;
- nr_sectors = ((R_TRACK-TRACK)*_floppy->head+R_HEAD-HEAD) *
- _floppy->sect + ((R_SECTOR-SECTOR+eoc) << SIZECODE >> 2) -
- (sector_t % _floppy->sect) % ssize;
+
+ if(COMMAND & 0x80)
+ heads = 2;
+ else
+ heads = 1;
+
+ nr_sectors = (((R_TRACK-TRACK) * heads +
+ R_HEAD-HEAD) * SECT_PER_TRACK +
+ R_SECTOR-SECTOR + eoc) << SIZECODE >> 2;
#ifdef FLOPPY_SANITY_CHECK
- if (nr_sectors > current_count_sectors + ssize -
- (current_count_sectors + sector_t) % ssize +
- sector_t % ssize){
+ if (nr_sectors / ssize >
+ (in_sector_offset + current_count_sectors + ssize - 1)/ssize) {
DPRINT("long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
printk("rh=%d h=%d\n", R_HEAD, HEAD);
printk("rt=%d t=%d\n", R_TRACK, TRACK);
- printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
- sector_t, ssize);
+ printk("heads=%d eoc=%d\n", heads, eoc);
+ printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK,
+ sector_t, ssize);
+ printk("in_sector_offset=%d\n", in_sector_offset);
}
#endif
+
+ nr_sectors -= in_sector_offset;
INFBOUND(nr_sectors,0);
SUPBOUND(current_count_sectors, nr_sectors);
@@ -2473,7 +2484,7 @@ static inline int check_dma_crossing(char *start,
* does not work with MT, hence we can only transfer one head at
* a time
*/
-static int virtualdmabug_workaround() {
+static void virtualdmabug_workaround(void) {
int hard_sectors, end_sector;
if(CT(COMMAND) == FD_WRITE) {
COMMAND &= ~0x80; /* switch off multiple track mode */
@@ -2484,7 +2495,7 @@ static int virtualdmabug_workaround() {
if(end_sector > SECT_PER_TRACK) {
printk("too many sectors %d > %d\n",
end_sector, SECT_PER_TRACK);
- return 0;
+ return;
}
#endif
SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points
@@ -2595,7 +2606,8 @@ static int make_raw_rw_request(void)
max_sector = _floppy->sect;
}
- aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize;
+ in_sector_offset = (sector_t % _floppy->sect) % ssize;
+ aligned_sector_t = sector_t - in_sector_offset;
max_size = CURRENT->nr_sectors;
if ((raw_cmd->track == buffer_track) &&
(current_drive == buffer_drive) &&
@@ -2605,7 +2617,7 @@ static int make_raw_rw_request(void)
copy_buffer(1, max_sector, buffer_max);
return 1;
}
- } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){
+ } else if (in_sector_offset || CURRENT->nr_sectors < ssize){
if (CT(COMMAND) == FD_WRITE){
if (sector_t + CURRENT->nr_sectors > ssize &&
sector_t + CURRENT->nr_sectors < ssize + ssize)
@@ -2677,7 +2689,7 @@ static int make_raw_rw_request(void)
sector_t > buffer_max ||
sector_t < buffer_min ||
((CT(COMMAND) == FD_READ ||
- (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize))&&
+ (!in_sector_offset && CURRENT->nr_sectors >= ssize))&&
max_sector > 2 * max_buffer_sectors + buffer_min &&
max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
/* not enough space */){
@@ -2694,7 +2706,7 @@ static int make_raw_rw_request(void)
* is either aligned or the data already in the buffer
* (buffer will be overwritten) */
#ifdef FLOPPY_SANITY_CHECK
- if (sector_t != aligned_sector_t && buffer_track == -1)
+ if (in_sector_offset && buffer_track == -1)
DPRINT("internal error offset !=0 on write\n");
#endif
buffer_track = raw_cmd->track;
@@ -2705,7 +2717,7 @@ static int make_raw_rw_request(void)
2*max_buffer_sectors+buffer_min-aligned_sector_t);
/* round up current_count_sectors to get dma xfer size */
- raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t;
+ raw_cmd->length = in_sector_offset+current_count_sectors;
raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1;
raw_cmd->length <<= 9;
#ifdef FLOPPY_SANITY_CHECK
diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c
index 24f00c950..27b7d4c70 100644
--- a/drivers/block/ide-cd.c
+++ b/drivers/block/ide-cd.c
@@ -26,7 +26,6 @@
* (If you are using a cd changer, you may get errors in the kernel
* logs that are completly expected. Don't complain to me about this,
* unless you have a patch to fix it. I am working on it...)
- * -Implement ide_cdrom_select_speed using the generic cdrom interface
* -Fix ide_cdrom_reset so that it works (it does nothing right now)
* -Query the drive to find what features are available before trying to
* use them (like trying to close the tray in drives that can't).
@@ -189,10 +188,19 @@
* malloc'ed but never free'd when closing the device.
* -- Cleaned up the global namespace a bit by making more
* functions static that should already have been.
+ * 4.11 Mar 12, 1998 -- Added support for the CDROM_SELECT_SPEED ioctl
+ * based on a patch for 2.0.33 by Jelle Foks
+ * <jelle@scintilla.utwente.nl>, a patch for 2.0.33
+ * by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
+ * version, and my own efforts. -erik
+ * -- Fixed a stupid bug which egcs was kind enough to
+ * inform me of where "Illegal mode for this track"
+ * was never returned due to a comparison on data
+ * types of limited range.
*
*************************************************************************/
-#define IDECD_VERSION "4.10"
+#define IDECD_VERSION "4.11"
#include <linux/module.h>
#include <linux/types.h>
@@ -271,8 +279,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
printk (" Error code: 0x%02x\n", reqbuf->error_code);
- if (reqbuf->sense_key >= 0 &&
- reqbuf->sense_key < ARY_LEN (sense_key_texts))
+ if ( reqbuf->sense_key < ARY_LEN (sense_key_texts))
s = sense_key_texts[reqbuf->sense_key];
else
s = "(bad sense key)";
@@ -285,7 +292,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
s = buf;
} else {
int lo, hi;
- int key = (reqbuf->asc << 8);
+ unsigned short key = (reqbuf->asc << 8);
if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
key |= reqbuf->ascq;
@@ -496,7 +503,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
} else if (sense_key == UNIT_ATTENTION) {
/* Check for media change. */
cdrom_saw_media_change (drive);
- printk ("%s: media changed\n", drive->name);
+ /*printk("%s: media changed\n",drive->name);*/
return 0;
} else {
/* Otherwise, print an error. */
@@ -1518,7 +1525,6 @@ cdrom_startstop (ide_drive_t *drive, int startflag,
return cdrom_queue_packet_command (drive, &pc);
}
-
static int
cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity,
struct atapi_request_sense *reqbuf)
@@ -1721,7 +1727,6 @@ cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
return cdrom_queue_packet_command (drive, &pc);
}
-
static int
cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
struct atapi_request_sense *reqbuf)
@@ -1742,6 +1747,43 @@ cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
}
+/* Note that this takes speed in kbytes/second, so don't try requesting
+ silly speeds like 2 here. Common speeds include:
+ 176 kbytes/second -- 1x
+ 353 kbytes/second -- 2x
+ 387 kbytes/second -- 2.2x
+ 528 kbytes/second -- 3x
+ 706 kbytes/second -- 4x
+ 1400 kbytes/second -- 8x
+ 2800 kbytes/second -- 16x
+ ATAPI drives are free to select the speed you request or any slower
+ rate :-( Requesting too fast a speed will _not_ produce an error. */
+static int
+cdrom_select_speed (ide_drive_t *drive, int speed,
+ struct atapi_request_sense *reqbuf)
+{
+ struct packet_command pc;
+ memset (&pc, 0, sizeof (pc));
+ pc.sense_data = reqbuf;
+
+ if (speed < 1)
+ speed = 0xffff; /* set to max */
+ else
+ speed *= 177; /* Nx to kbytes/s */
+
+ pc.c[0] = SET_CD_SPEED;
+ /* Read Drive speed in kbytes/second MSB */
+ pc.c[2] = (speed >> 8) & 0xff;
+ /* Read Drive speed in kbytes/second LSB */
+ pc.c[3] = speed & 0xff;
+ /* Write Drive speed in kbytes/second MSB */
+ //pc.c[4] = (speed >> 8) & 0xff;
+ /* Write Drive speed in kbytes/second LSB */
+ //pc.c[5] = speed & 0xff;
+
+ return cdrom_queue_packet_command (drive, &pc);
+}
+
static int
cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end,
struct atapi_request_sense *reqbuf)
@@ -2429,6 +2471,44 @@ int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
return cdrom_lockdoor (drive, lock, NULL);
}
+static
+int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
+{
+ int stat, attempts = 3;
+ struct {
+ char pad[8];
+ struct atapi_capabilities_page cap;
+ } buf;
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct atapi_request_sense reqbuf;
+ stat=cdrom_select_speed (drive, speed, &reqbuf);
+ if (stat<0)
+ return stat;
+
+ /* Now that that is done, update the speed fields */
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ if (attempts-- <= 0)
+ return 0;
+ stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
+ (char *)&buf, sizeof (buf), NULL);
+ } while (stat);
+
+ /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
+ if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
+ CDROM_STATE_FLAGS (drive)->current_speed =
+ (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed =
+ (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+ } else {
+ CDROM_STATE_FLAGS (drive)->current_speed =
+ (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed =
+ (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+ }
+ cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+ return 0;
+}
+
static
int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot)
@@ -2668,14 +2748,14 @@ struct cdrom_device_ops ide_cdrom_dops = {
ide_cdrom_check_media_change_real, /* media_changed */
ide_cdrom_tray_move, /* tray_move */
ide_cdrom_lock_door, /* lock_door */
- NULL, /* select_speed */
+ ide_cdrom_select_speed, /* select_speed */
ide_cdrom_select_disc, /* select_disc */
ide_cdrom_get_last_session, /* get_last_session */
ide_cdrom_get_mcn, /* get_mcn */
ide_cdrom_reset, /* reset */
ide_cdrom_audio_ioctl, /* audio_ioctl */
ide_cdrom_dev_ioctl, /* dev_ioctl */
- CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK
+ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED
| CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN
| CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET
| CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */
@@ -2691,7 +2771,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
devinfo->dev = MKDEV (HWIF(drive)->major, minor);
devinfo->ops = &ide_cdrom_dops;
devinfo->mask = 0;
- *(int *)&devinfo->speed = CDROM_CONFIG_FLAGS (drive)->max_speed;
+ *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
*(int *)&devinfo->capacity = nslots;
devinfo->handle = (void *) drive;
strcpy(devinfo->name, drive->name);
@@ -2750,11 +2830,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
- CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
- CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+ CDROM_STATE_FLAGS (drive)->current_speed =
+ (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed =
+ (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
} else {
- CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176;
- CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+ CDROM_STATE_FLAGS (drive)->current_speed =
+ (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed =
+ (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
}
printk ("%s: ATAPI %dX CDROM",
diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h
index 53e38e1b1..140c4ccb6 100644
--- a/drivers/block/ide-cd.h
+++ b/drivers/block/ide-cd.h
@@ -71,7 +71,7 @@
#define MODE_SENSE_10 0x5a
#define MODE_SELECT_10 0x55
#define READ_CD 0xbe
-
+#define SET_CD_SPEED 0xbb
#define LOAD_UNLOAD 0xa6
#define MECHANISM_STATUS 0xbd
@@ -431,7 +431,7 @@ char *sense_key_texts[16] = {
with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */
struct {
- short asc_ascq;
+ unsigned short asc_ascq;
char *text;
} sense_data_texts[] = {
{ 0x0000, "No additional sense information" },
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 4ad8bf606..8c72c791d 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -16,9 +16,11 @@
* Version 1.02 remove ", LBA" from drive identification msgs
* Version 1.03 fix display of id->buf_size for big-endian
* Version 1.04 add /proc configurable settings and S.M.A.R.T support
+ * Version 1.05 add capacity support for ATA3 >= 8GB
+ * Version 1.06 get boot-up messages to show full cyl count
*/
-#define IDEDISK_VERSION "1.04"
+#define IDEDISK_VERSION "1.06"
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -83,6 +85,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
unsigned long chs_sects = id->cyls * id->heads * id->sectors;
unsigned long _10_percent = chs_sects / 10;
+ /* very large drives (8GB+) may lie about the number of cylinders */
+ if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+ id->cyls = lba_sects / (16 * 63); /* correct cyls */
+ return 1; /* lba_capacity is our only option */
+ }
/* perform a rough sanity check on lba_sects: within 10% is "okay" */
if ((lba_sects - chs_sects) < _10_percent)
return 1; /* lba_capacity is good */
@@ -439,6 +446,7 @@ static unsigned long idedisk_capacity (ide_drive_t *drive)
/* Determine capacity, and use LBA if the drive properly supports it */
if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
if (id->lba_capacity >= capacity) {
+ drive->cyl = id->lba_capacity / (drive->head * drive->sect);
capacity = id->lba_capacity;
drive->select.b.lba = 1;
}
@@ -698,6 +706,10 @@ static void idedisk_setup (ide_drive_t *drive)
drive->head = id->heads;
drive->sect = id->sectors;
}
+
+ /* calculate drive capacity, and select LBA if possible */
+ (void) idedisk_capacity (drive);
+
/* Correct the number of cyls if the bios value is too small */
if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
if (drive->cyl > drive->bios_cyl)
@@ -706,8 +718,6 @@ static void idedisk_setup (ide_drive_t *drive)
/* fix byte-ordering of buffer size field */
id->buf_size = le16_to_cpu(id->buf_size);
- (void) idedisk_capacity (drive); /* initialize LBA selection */
-
printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2,
drive->bios_cyl, drive->bios_head, drive->bios_sect);
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
index d8fa6edf5..9e8fd5127 100644
--- a/drivers/block/ide-pci.c
+++ b/drivers/block/ide-pci.c
@@ -24,7 +24,8 @@
#include "ide.h"
-#define DEVID_PIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1})
+#define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0})
+#define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1})
#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1})
#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB})
#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
@@ -87,7 +88,8 @@ typedef struct ide_pci_device_s {
} ide_pci_device_t;
static ide_pci_device_t ide_pci_chipsets[] __initdata = {
- {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIXb, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
{DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
{DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
{DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
@@ -360,6 +362,13 @@ static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
|| IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL)
|| pcibios_read_config_dword(bus, fn, 0x08, &ccode))
return;
+ /*
+ * workaround Intel Advanced/ZP with bios <= 1.04;
+ * these appear in some Dell Dimension XPS's
+ */
+ if (!hedt && IDE_PCI_DEVID_EQ(devid, DEVID_PIIXa))
+ hedt = 0x80;
+
for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
if (d->init_hwif == IDE_IGNORE)
printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 7ec27d45d..e10578508 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -134,9 +134,9 @@
#include "ide.h"
#include "ide_modes.h"
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif /* CONFIG_KERNELD */
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif /* CONFIG_KMOD */
static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
@@ -1505,10 +1505,10 @@ static void ide_init_module (int type)
module = module->next;
}
revalidate_drives();
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!found && type == IDE_PROBE_MODULE)
(void) request_module("ide-probe");
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
}
static int ide_open(struct inode * inode, struct file * filp)
@@ -1521,7 +1521,7 @@ static int ide_open(struct inode * inode, struct file * filp)
MOD_INC_USE_COUNT;
if (drive->driver == NULL)
ide_init_module(IDE_DRIVER_MODULE);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (drive->driver == NULL) {
if (drive->media == ide_disk)
(void) request_module("ide-disk");
@@ -1532,7 +1532,7 @@ static int ide_open(struct inode * inode, struct file * filp)
if (drive->media == ide_floppy)
(void) request_module("ide-floppy");
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
while (drive->busy)
sleep_on(&drive->wqueue);
drive->usage++;
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 01cf3923a..9f0db3b23 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -24,9 +24,6 @@
#include <linux/module.h>
-#define ATOMIC_ON() do { } while (0)
-#define ATOMIC_OFF() do { } while (0)
-
/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
@@ -419,8 +416,6 @@ void make_request(int major,int rw, struct buffer_head * bh)
* not to schedule or do something nonatomic
*/
spin_lock_irqsave(&io_request_lock,flags);
- ATOMIC_ON();
-
req = *get_queue(bh->b_rdev);
if (!req) {
/* MD and loop can't handle plugging without deadlocking */
@@ -480,7 +475,6 @@ void make_request(int major,int rw, struct buffer_head * bh)
continue;
mark_buffer_clean(bh);
- ATOMIC_OFF();
spin_unlock_irqrestore(&io_request_lock,flags);
return;
@@ -490,7 +484,6 @@ void make_request(int major,int rw, struct buffer_head * bh)
/* find an unused request. */
req = get_request(max_req, bh->b_rdev);
- ATOMIC_OFF();
spin_unlock_irqrestore(&io_request_lock,flags);
/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */
@@ -665,9 +658,7 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
} else {
unsigned long flags;
spin_lock_irqsave(&io_request_lock,flags);
- ATOMIC_ON();
req[j] = get_request(max_req, rdev);
- ATOMIC_OFF();
spin_unlock_irqrestore(&io_request_lock,flags);
if (req[j] == NULL)
break;
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 4feeb0ce9..4d0ccf401 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -12,6 +12,9 @@
RAID-1/RAID-5 extensions by:
Ingo Molnar, Miguel de Icaza, Gadi Oxman
+
+ Changes for kmod by:
+ Cyrus Durgin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -43,8 +46,8 @@
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/smp_lock.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <linux/errno.h>
#include <linux/init.h>
@@ -431,7 +434,7 @@ static int do_md_run (int minor, int repart)
}
if (!pers[pnum])
{
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
char module_name[80];
sprintf (module_name, "md-personality-%d", pnum);
request_module (module_name);
diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c
index 6fefac06d..2b0e97450 100644
--- a/drivers/block/raid5.c
+++ b/drivers/block/raid5.c
@@ -837,8 +837,11 @@ static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int d
struct raid5_data *raid_conf = sh->raid_conf;
struct buffer_head *bh_req;
- if (sh->bh_new[dd_idx])
+ if (sh->bh_new[dd_idx]) {
printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector);
+ printk("forcing oops.\n");
+ *(int*)0=0;
+ }
set_bit(BH_Lock, &bh->b_state);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index de17158a7..a133b70cc 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -35,6 +35,9 @@
*
* 4/25/96 : Made ramdisk size a parameter (default is now 4MB)
* - Chad Page
+ *
+ * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
+ *
*/
#include <linux/config.h>
@@ -344,7 +347,6 @@ identify_ramdisk_image(kdev_t device, struct file *fp, int start_block))
struct ext2_super_block *ext2sb;
struct romfs_super_block *romfsb;
int nblocks = -1;
- int max_blocks;
unsigned char *buf;
buf = kmalloc(size, GFP_KERNEL);
@@ -423,17 +425,6 @@ done:
fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0);
fp->f_pos = start_block * BLOCK_SIZE;
- if ((nblocks > 0) && blk_size[MAJOR(device)]) {
- max_blocks = blk_size[MAJOR(device)][MINOR(device)];
- max_blocks -= start_block;
- if (nblocks > max_blocks) {
- printk(KERN_NOTICE
- "RAMDISK: Restricting filesystem size "
- "from %d to %d blocks.\n",
- nblocks, max_blocks);
- nblocks = max_blocks;
- }
- }
kfree(buf);
return nblocks;
}
@@ -451,6 +442,7 @@ __initfunc(static void rd_load_image(kdev_t device,int offset))
int nblocks, i;
char *buf;
unsigned short rotate = 0;
+ unsigned short devblocks = 0;
char rotator[4] = { '|' , '/' , '-' , '\\' };
ram_device = MKDEV(MAJOR_NR, 0);
@@ -508,8 +500,31 @@ __initfunc(static void rd_load_image(kdev_t device,int offset))
goto done;
}
- printk(KERN_NOTICE "RAMDISK: Loading %d blocks into ram disk... ", nblocks);
+ if (blk_size[MAJOR(device)])
+ devblocks = blk_size[MAJOR(device)][MINOR(device)];
+
+ if (devblocks == 0) {
+ printk(KERN_ERR "RAMDISK: could not determine device size\n");
+ goto done;
+ }
+
+ printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk(s)] into ram disk... ", nblocks, nblocks/devblocks+1);
for (i=0; i < nblocks; i++) {
+ if (i && (i % devblocks == 0)) {
+ printk("done.\n");
+ rotate = 0;
+ invalidate_buffers(device);
+ if (infile.f_op->release)
+ infile.f_op->release(&inode, &infile);
+ printk("Please insert disk #%d and press ENTER\n", i/devblocks+1);
+ wait_for_keypress();
+ if (blkdev_open(&inode, &infile) != 0) {
+ printk("Error opening disk.\n");
+ goto done;
+ }
+ infile.f_pos = 0;
+ printk("Loading disk #%d... ", i/devblocks+1);
+ }
infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos);
outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);
if (!(i % 16)) {
diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog
index 56e762e71..95d6741c5 100644
--- a/drivers/char/ChangeLog
+++ b/drivers/char/ChangeLog
@@ -1,3 +1,11 @@
+Thu Feb 19 14:24:08 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * tty_io.c (tty_name): Remove the non-reentrant (and non-SMP safe)
+ version of tty_name, and rename the reentrant _tty_name
+ function to be tty_name.
+ (tty_open): Add a warning message stating callout devices
+ are deprecated.
+
Mon Dec 1 08:24:15 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
* tty_io.c (tty_get_baud_rate): Print a warning syslog if the
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index ffb6287a7..e17a220e6 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -110,11 +110,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
-if [ "$CONFIG_RTC" = "y" ]; then
- if [ "$ARCH" = "alpha" ]; then
- bool ' ARC console time' CONFIG_RTC_ARC y
- fi
-fi
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c
index b425ab694..94f13f8fd 100644
--- a/drivers/char/apm_bios.c
+++ b/drivers/char/apm_bios.c
@@ -1203,17 +1203,17 @@ __initfunc(void apm_bios_init(void))
* even though they are called in protected mode.
*/
set_base(gdt[APM_40 >> 3],
- 0xc0000000 + ((unsigned long)0x40 << 4));
+ __va((unsigned long)0x40 << 4));
set_limit(gdt[APM_40 >> 3], 4096 - (0x40 << 4));
apm_bios_entry.offset = apm_bios_info.offset;
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4));
+ __va((unsigned long)apm_bios_info.cseg << 4));
set_base(gdt[APM_CS_16 >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4));
+ __va((unsigned long)apm_bios_info.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
- 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4));
+ __va((unsigned long)apm_bios_info.dseg << 4));
if (apm_bios_info.version == 0x100) {
set_limit(gdt[APM_CS >> 3], 64 * 1024);
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 089ce7b2d..2ea9cb86f 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1384,7 +1384,7 @@ static void rs_throttle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -1406,7 +1406,7 @@ static void rs_unthrottle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ printk("unthrottle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c
index 19d10c95b..3b80c207f 100644
--- a/drivers/char/ftape/zftape/zftape-ctl.c
+++ b/drivers/char/ftape/zftape/zftape-ctl.c
@@ -29,9 +29,6 @@
#include <linux/mm.h>
#define __NO_VERSION__
#include <linux/module.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#include <linux/fcntl.h>
#include <linux/zftape.h>
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 0c8a6f9eb..78a857ace 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -30,8 +30,8 @@
#include <linux/signal.h>
#include <linux/major.h>
#include <linux/malloc.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <linux/fcntl.h>
#include <linux/wrapper.h>
@@ -391,7 +391,7 @@ struct zft_cmpr_ops *zft_cmpr_unregister(void)
int zft_cmpr_lock(int try_to_load)
{
if (zft_cmpr_ops == NULL) {
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (try_to_load) {
request_module("zft-compressor");
if (zft_cmpr_ops == NULL) {
diff --git a/drivers/char/ftape/zftape/zftape-read.c b/drivers/char/ftape/zftape/zftape-read.c
index c7d319fac..91ed51423 100644
--- a/drivers/char/ftape/zftape/zftape-read.c
+++ b/drivers/char/ftape/zftape/zftape-read.c
@@ -24,12 +24,8 @@
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#include <linux/zftape.h>
diff --git a/drivers/char/ftape/zftape/zftape-write.c b/drivers/char/ftape/zftape/zftape-write.c
index 46f1ecc09..03b126f49 100644
--- a/drivers/char/ftape/zftape/zftape-write.c
+++ b/drivers/char/ftape/zftape/zftape-write.c
@@ -24,12 +24,8 @@
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#include <linux/zftape.h>
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index a36903c7a..4a000e9aa 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -43,8 +43,8 @@
#include <linux/string.h>
#include <linux/init.h>
#include <asm/irq.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#ifdef CONFIG_AMIGA
@@ -365,7 +365,7 @@ static int lp_open(struct inode *inode, struct file *file)
if (dev >= MAX_LP)
return -ENODEV;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!lp_table[dev]) {
char modname[30];
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 665b9ec9d..b3b283015 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -26,6 +26,9 @@
* Idea by Jacques Gelinas <jack@solucorp.qc.ca>,
* adapted by Bjorn Ekwall <bj0rn@blox.se>
* corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * Changes for kmod (from kerneld):
+ Cyrus Durgin <cider@speakeasy.org>
*/
#include <linux/config.h>
@@ -46,8 +49,8 @@
#include <linux/tty.h>
#include <linux/selection.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
/*
@@ -109,7 +112,7 @@ static int misc_open(struct inode * inode, struct file * file)
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list) {
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
char modname[20];
sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
request_module(modname);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 3d2f2b18c..a434cf405 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -420,7 +420,7 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
tty->num_overrun++;
if (tty->overrun_time < (jiffies - HZ)) {
- printk("%s: %d input overrun(s)\n", _tty_name(tty, buf),
+ printk("%s: %d input overrun(s)\n", tty_name(tty, buf),
tty->num_overrun);
tty->overrun_time = jiffies;
tty->num_overrun = 0;
@@ -656,6 +656,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
const unsigned char *p;
char *f, flags = TTY_NORMAL;
int i;
+ char buf[64];
if (!tty->read_buf)
return;
@@ -693,8 +694,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
n_tty_receive_overrun(tty);
break;
default:
- printk("%s: unknown flag %d\n", tty_name(tty),
- flags);
+ printk("%s: unknown flag %d\n",
+ tty_name(tty, buf), flags);
break;
}
}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 26d15d182..9edca1683 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -48,7 +48,6 @@
* this driver.)
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -63,13 +62,6 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-/* Adjust starting epoch if ARC console time is being used */
-#ifdef CONFIG_RTC_ARC
-#define ARCFUDGE 20
-#else
-#define ARCFUDGE 0
-#endif
-
/*
* We sponge a minor off of the misc major. No need slurping
* up another valuable major dev number for this. If you add
@@ -126,12 +118,8 @@ unsigned char days_in_mo[] =
* so that there is no possibility of conflicting with the
* set_rtc_mmss() call that happens during some timer interrupts.
* (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
- *
- * On Alpha we won't get any interrupts anyway, as they all end up
- * in the system timer code.
*/
-#ifndef __alpha__
static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
/*
@@ -152,11 +140,9 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
add_timer(&rtc_irq_timer);
}
}
-#endif
/*
* Now all the various file operations that we export.
- * They are all useless on Alpha... *sigh*.
*/
static long long rtc_llseek(struct file *file, loff_t offset, int origin)
@@ -167,9 +153,6 @@ static long long rtc_llseek(struct file *file, loff_t offset, int origin)
static ssize_t rtc_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
-#ifdef __alpha__
- return -EIO;
-#else
struct wait_queue wait = { current, NULL };
unsigned long data;
ssize_t retval;
@@ -201,7 +184,6 @@ static ssize_t rtc_read(struct file *file, char *buf,
remove_wait_queue(&rtc_wait, &wait);
return retval;
-#endif
}
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -212,7 +194,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct rtc_time wtime;
switch (cmd) {
-#ifndef __alpha__
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
{
mask_rtc_irq_bit(RTC_AIE);
@@ -260,7 +241,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
set_rtc_irq_bit(RTC_UIE);
return 0;
}
-#endif
case RTC_ALM_READ: /* Read the present alarm time */
{
/*
@@ -335,7 +315,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
sizeof(struct rtc_time)))
return -EFAULT;
- yrs = rtc_tm.tm_year + 1900 + ARCFUDGE;
+ yrs = rtc_tm.tm_year + 1900;
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
day = rtc_tm.tm_mday;
hrs = rtc_tm.tm_hour;
@@ -400,7 +380,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
return put_user(rtc_freq, (unsigned long *)arg);
}
-#ifndef __alpha__
case RTC_IRQP_SET: /* Set periodic IRQ rate. */
{
int tmp = 0;
@@ -437,7 +416,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
restore_flags(flags);
return 0;
}
-#else /* __alpha__ */
+#ifdef __alpha__
case RTC_EPOCH_READ: /* Read the epoch. */
{
return put_user (epoch, (unsigned long *)arg);
@@ -467,18 +446,15 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
* We enforce only one user at a time here with the open/close.
* Also clear the previous interrupt data on an open, and clean
* up things on a close.
- * On Alpha we just open, for we don't mess with interrups anyway.
*/
static int rtc_open(struct inode *inode, struct file *file)
{
-#ifndef __alpha__
if(rtc_status & RTC_IS_OPEN)
return -EBUSY;
rtc_status |= RTC_IS_OPEN;
rtc_irq_data = 0;
-#endif
return 0;
}
@@ -489,7 +465,6 @@ static int rtc_release(struct inode *inode, struct file *file)
* in use, and clear the data.
*/
-#ifndef __alpha__
unsigned char tmp;
unsigned long flags;
@@ -510,11 +485,9 @@ static int rtc_release(struct inode *inode, struct file *file)
rtc_irq_data = 0;
rtc_status &= ~RTC_IS_OPEN;
-#endif
return 0;
}
-#ifndef __alpha__
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &rtc_wait, wait);
@@ -522,7 +495,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
return POLLIN | POLLRDNORM;
return 0;
}
-#endif
/*
* The various file operations we support.
@@ -533,11 +505,7 @@ static struct file_operations rtc_fops = {
rtc_read,
NULL, /* No write */
NULL, /* No readdir */
-#ifdef __alpha__
- NULL, /* No select on Alpha */
-#else
rtc_poll,
-#endif
rtc_ioctl,
NULL, /* No mmap */
rtc_open,
@@ -560,14 +528,12 @@ __initfunc(int rtc_init(void))
char *guess = NULL;
#endif
printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
-#ifndef __alpha__
if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
{
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
return -EIO;
}
-#endif
misc_register(&rtc_dev);
/* Check region? Naaah! Just snarf it up. */
request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
@@ -599,8 +565,8 @@ __initfunc(int rtc_init(void))
guess = "Digital UNIX";
}
if (guess)
- printk("rtc: %s epoch (%ld) detected\n", guess, epoch);
-#else
+ printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
+#endif
init_timer(&rtc_irq_timer);
rtc_irq_timer.function = rtc_dropped_irq;
rtc_wait = NULL;
@@ -610,7 +576,6 @@ __initfunc(int rtc_init(void))
CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
restore_flags(flags);
rtc_freq = 1024;
-#endif
return 0;
}
@@ -626,7 +591,6 @@ __initfunc(int rtc_init(void))
* for something that requires a steady > 1KHz signal anyways.)
*/
-#ifndef __alpha__
void rtc_dropped_irq(unsigned long data)
{
unsigned long flags;
@@ -643,7 +607,6 @@ void rtc_dropped_irq(unsigned long data)
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
restore_flags(flags);
}
-#endif
/*
* Info exported via "/proc/rtc".
@@ -672,9 +635,10 @@ int get_rtc_status(char *buf)
*/
p += sprintf(p,
"rtc_time\t: %02d:%02d:%02d\n"
- "rtc_date\t: %04d-%02d-%02d\n",
+ "rtc_date\t: %04d-%02d-%02d\n"
+ "rtc_epoch\t: %04lu\n",
tm.tm_hour, tm.tm_min, tm.tm_sec,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
get_rtc_alm_time(&tm);
@@ -788,12 +752,9 @@ void get_rtc_time(struct rtc_time *rtc_tm)
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
*/
- if ((rtc_tm->tm_year += epoch - 1900) <= 69)
+ if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
rtc_tm->tm_year += 100;
- /* if ARCFUDGE == 0, the optimizer should do away with this */
- rtc_tm->tm_year -= ARCFUDGE;
-
rtc_tm->tm_mon--;
}
@@ -832,7 +793,6 @@ void get_rtc_alm_time(struct rtc_time *alm_tm)
* meddles with the interrupt enable/disable bits.
*/
-#ifndef __alpha__
void mask_rtc_irq_bit(unsigned char bit)
{
unsigned char val;
@@ -862,4 +822,3 @@ void set_rtc_irq_bit(unsigned char bit)
rtc_irq_data = 0;
restore_flags(flags);
}
-#endif
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 7af575780..b81a8eb8f 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -1745,7 +1745,7 @@ static void rs_throttle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -1769,7 +1769,7 @@ static void rs_unthrottle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ printk("unthrottle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index dcc38830f..5d100bba4 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -87,8 +87,8 @@
#include <linux/vt_kern.h>
#include <linux/selection.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
@@ -127,11 +127,9 @@ static int tty_fasync(struct file * filp, int on);
#endif
/*
- * These two routines return the name of tty. tty_name() should NOT
- * be used in interrupt drivers, since it's not re-entrant. Use
- * _tty_name() instead.
+ * This routine returns the name of tty.
*/
-char *_tty_name(struct tty_struct *tty, char *buf)
+char *tty_name(struct tty_struct *tty, char *buf)
{
if (tty)
sprintf(buf, "%s%d", tty->driver.name,
@@ -142,13 +140,6 @@ char *_tty_name(struct tty_struct *tty, char *buf)
return buf;
}
-char *tty_name(struct tty_struct *tty)
-{
- static char buf[64];
-
- return(_tty_name(tty, buf));
-}
-
inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
const char *routine)
{
@@ -213,11 +204,13 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
int retval = 0;
struct tty_ldisc o_ldisc;
+ char buf[64];
if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
return -EINVAL;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
+ /* Cyrus Durgin <cider@speakeasy.org> */
if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
char modname [20];
sprintf(modname, "tty-ldisc-%d", ldisc);
@@ -254,7 +247,7 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (r < 0)
panic("Couldn't open N_TTY ldisc for "
"%s --- error %d.",
- tty_name(tty), r);
+ tty_name(tty, buf), r);
}
}
}
@@ -455,7 +448,9 @@ void do_tty_hangup(void *data)
void tty_hangup(struct tty_struct * tty)
{
#ifdef TTY_DEBUG_HANGUP
- printk("%s hangup...\n", tty_name(tty));
+ char buf[64];
+
+ printk("%s hangup...\n", tty_name(tty, buf));
#endif
queue_task(&tty->tq_hangup, &tq_timer);
}
@@ -463,7 +458,9 @@ void tty_hangup(struct tty_struct * tty)
void tty_vhangup(struct tty_struct * tty)
{
#ifdef TTY_DEBUG_HANGUP
- printk("%s vhangup...\n", tty_name(tty));
+ char buf[64];
+
+ printk("%s vhangup...\n", tty_name(tty, buf));
#endif
do_tty_hangup((void *) tty);
}
@@ -950,6 +947,7 @@ static void release_dev(struct file * filp)
struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
int idx;
+ char buf[64];
tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
@@ -990,7 +988,7 @@ static void release_dev(struct file * filp)
#endif
#ifdef TTY_DEBUG_HANGUP
- printk("release_dev of %s (tty count=%d)...", tty_name(tty),
+ printk("release_dev of %s (tty count=%d)...", tty_name(tty, buf),
tty->count);
#endif
@@ -1068,7 +1066,7 @@ static void release_dev(struct file * filp)
break;
printk("release_dev: %s: read/write wait queue active!\n",
- tty_name(tty));
+ tty_name(tty, buf));
schedule();
}
@@ -1084,13 +1082,13 @@ static void release_dev(struct file * filp)
if (pty_master) {
if (--o_tty->count < 0) {
printk("release_dev: bad pty slave count (%d) for %s\n",
- o_tty->count, tty_name(o_tty));
+ o_tty->count, tty_name(o_tty, buf));
o_tty->count = 0;
}
}
if (--tty->count < 0) {
printk("release_dev: bad tty->count (%d) for %s\n",
- tty->count, tty_name(tty));
+ tty->count, tty_name(tty, buf));
tty->count = 0;
}
@@ -1178,6 +1176,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int noctty, retval;
kdev_t device;
unsigned short saved_flags;
+ char buf[64];
saved_flags = filp->f_flags;
retry_open:
@@ -1245,7 +1244,7 @@ init_dev_done:
tty->driver.subtype == PTY_TYPE_MASTER)
noctty = 1;
#ifdef TTY_DEBUG_HANGUP
- printk("opening %s...", tty_name(tty));
+ printk("opening %s...", tty_name(tty, buf));
#endif
if (tty->driver.open)
retval = tty->driver.open(tty, filp);
@@ -1258,7 +1257,8 @@ init_dev_done:
if (retval) {
#ifdef TTY_DEBUG_HANGUP
- printk("error %d in opening %s...", retval, tty_name(tty));
+ printk("error %d in opening %s...", retval,
+ tty_name(tty, buf));
#endif
release_dev(filp);
@@ -1282,6 +1282,11 @@ init_dev_done:
tty->session = current->session;
tty->pgrp = current->pgrp;
}
+ if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&
+ (tty->driver.subtype == SERIAL_TYPE_CALLOUT)) {
+ printk("Warning, %s opened, is a deprecated tty "
+ "callout device\n", tty_name(tty, buf));
+ }
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 21c09384e..735a955fc 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -45,7 +45,9 @@ void tty_wait_until_sent(struct tty_struct * tty, int timeout)
struct wait_queue wait = { current, NULL };
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
- printk("%s wait until sent...\n", tty_name(tty));
+ char buf[64];
+
+ printk("%s wait until sent...\n", tty_name(tty, buf));
#endif
if (!tty->driver.chars_in_buffer)
return;
@@ -57,7 +59,8 @@ void tty_wait_until_sent(struct tty_struct * tty, int timeout)
current->timeout = (unsigned) -1;
do {
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
- printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
+ printk("waiting %s...(%d)\n", tty_name(tty, buf),
+ tty->driver.chars_in_buffer(tty));
#endif
current->state = TASK_INTERRUPTIBLE;
if (signal_pending(current))
diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c
index 3fc222ff9..31753dc1a 100644
--- a/drivers/misc/parport_init.c
+++ b/drivers/misc/parport_init.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/init.h>
-#include <linux/kerneld.h>
#ifndef MODULE
static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index 91fb8b0dc..bc39b351c 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.9 1998/03/16 23:44:45 ralf Exp $
+/* $Id: parport_share.c,v 1.10 1998/03/18 06:32:19 ralf Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -28,8 +28,8 @@
#include <asm/spinlock.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#undef PARPORT_PARANOID
@@ -44,14 +44,14 @@ void (*parport_probe_hook)(struct parport *port) = NULL;
/* Return a list of all the ports we know about. */
struct parport *parport_enumerate(void)
{
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (portlist == NULL) {
request_module("parport_lowlevel");
#ifdef CONFIG_PNP_PARPORT_MODULE
request_module("parport_probe");
#endif /* CONFIG_PNP_PARPORT_MODULE */
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
return portlist;
}
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index ea97a5bc1..c3bcd09c5 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -49,10 +49,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
tristate 'WD80*3 support' CONFIG_WD80x3
if [ "$CONFIG_MCA" = "y" ]; then
- tristate 'SMC Ultra MCA support' CONFIG_ULTRA
- else
- tristate 'SMC Ultra support' CONFIG_ULTRA
+ tristate 'SMC Ultra MCA support' CONFIG_ULTRAMCA
fi
+ tristate 'SMC Ultra support' CONFIG_ULTRA
tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32
tristate 'SMC 9194 support' CONFIG_SMC9194
fi
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5856b0f35..8d3f1f40b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -158,9 +158,6 @@ endif
ifeq ($(CONFIG_ULTRA),y)
L_OBJS += smc-ultra.o
CONFIG_8390_BUILTIN = y
- ifeq ($(CONFIG_MCA),y)
- L_OBJS += smc-mca.o
- endif
else
ifeq ($(CONFIG_ULTRA),m)
CONFIG_8390_MODULE = y
@@ -168,6 +165,16 @@ else
endif
endif
+ifeq ($(CONFIG_ULTRAMCA),y)
+L_OBJS += smc-mca.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ULTRAMCA),m)
+ CONFIG_8390_MODULE = y
+ M_OBJS += smc-mca.o
+ endif
+endif
+
ifeq ($(CONFIG_ULTRA32),y)
L_OBJS += smc-ultra32.o
CONFIG_8390_BUILTIN = y
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index e5a98378b..9d880aa4d 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -43,6 +43,7 @@
extern int tulip_probe(struct device *dev);
extern int hp100_probe(struct device *dev);
extern int ultra_probe(struct device *dev);
+extern int ultra32_probe(struct device *dev);
extern int ultramca_probe(struct device *dev);
extern int wd_probe(struct device *dev);
extern int el2_probe(struct device *dev);
@@ -135,13 +136,13 @@ __initfunc(static int ethif_probe(struct device *dev))
#endif
#if defined(CONFIG_ULTRA)
&& ultra_probe(dev)
-#if defined(CONFIG_MCA)
+#endif
+#if defined(CONFIG_ULTRAMCA)
&& ultramca_probe(dev)
#endif
#if defined(CONFIG_ULTRA32)
&& ultra32_probe(dev)
#endif
-#endif
#if defined(CONFIG_SMC9194)
&& smc_init(dev)
#endif
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index ed2652b96..6bd5be8b7 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -213,7 +213,7 @@
insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
- For a compiled in driver, somewhere in this file, place e.g.
+ For a compiled in driver, at or above line 526, place e.g.
#define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
Yes, I know full duplex isn't permissible on BNC or AUI; they're just
@@ -371,11 +371,14 @@
0.533 9-Jan-98 Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
0.534 24-Jan-98 Fix last (?) endian bug from
<Geert.Uytterhoeven@cs.kuleuven.ac.be>
+ 0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040.
+ 0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure.
+ **Incompatible with 2.0.x from here.**
=========================================================================
*/
-static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n";
#include <linux/module.h>
@@ -390,11 +393,15 @@ static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.co
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -408,31 +415,6 @@ static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.co
#include "de4x5.h"
#define c_char const char
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
-# define __initfunc(__arginit) __arginit
-# define test_and_set_bit set_bit
-# define net_device_stats enet_statistics
-# define copy_to_user(a,b,c) memcpy_tofs(a,b,c)
-# define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
-# define le16_to_cpu(a) cpu_to_le16(a)
-# define le32_to_cpu(a) cpu_to_le32(a)
-# ifdef __powerpc__
-# define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
-# define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
- (((a) & 0x0000ff00U) << 8) |\
- (((a) & 0x00ff0000U) >> 8) |\
- (((a) & 0xff000000U) >> 24))
-# else
-# define cpu_to_le16(a) (a)
-# define cpu_to_le32(a) (a)
-# endif /* __powerpc__ */
-# include <asm/segment.h>
-#else
-# include <asm/uaccess.h>
-# include <linux/init.h>
-#endif /* LINUX_VERSION_CODE */
#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
/*
@@ -538,8 +520,8 @@ static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
**
** For a compiled in driver, place e.g.
-** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
-** somewhere in this file above this point.
+** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
+** here
*/
#ifdef DE4X5_PARM
static char *args = DE4X5_PARM;
@@ -592,6 +574,12 @@ struct parameters {
#define DE4X5_NAME_LENGTH 8
/*
+** Ethernet PROM defines for DC21040
+*/
+#define PROBE_LENGTH 32
+#define ETH_PROM_SIG 0xAA5500FFUL
+
+/*
** PCI Bus defines
*/
#define PCI_MAX_BUS_NUM 8
@@ -912,6 +900,7 @@ static int test_tp(struct device *dev, s32 msec);
static int EISA_signature(char *name, s32 eisa_id);
static int PCI_signature(char *name, struct bus_type *lp);
static void DevicePresent(u_long iobase);
+static void enet_addr_rst(u_long aprom_addr);
static int de4x5_bad_srom(struct bus_type *lp);
static short srom_rd(u_long address, u_char offset);
static void srom_latch(u_int command, u_long address);
@@ -981,11 +970,9 @@ static struct device *insert_device(struct device *dev, u_long iobase,
int (*init)(struct device *));
static int count_adapters(void);
static int loading_module = 1;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
MODULE_PARM(de4x5_debug, "i");
MODULE_PARM(dec_only, "i");
MODULE_PARM(args, "s");
-#endif /* LINUX_VERSION_CODE */
# else
static int loading_module = 0;
#endif /* MODULE */
@@ -1507,9 +1494,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
cli();
test_and_set_bit(0, (void*)&dev->tbusy);
load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
lp->stats.tx_bytes += skb->len;
-#endif
outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -1559,9 +1544,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
DISABLE_IRQs; /* Ensure non re-entrancy */
-#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
synchronize_irq();
-#endif
dev->interrupt = MASK_INTERRUPTS;
for (limit=0; limit<8; limit++) {
@@ -1659,9 +1642,7 @@ de4x5_rx(struct device *dev)
/* Update stats */
lp->stats.rx_packets++;
-#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
lp->stats.rx_bytes += pkt_len;
-#endif
de4x5_local_stats(dev, skb->data, pkt_len);
}
}
@@ -2042,7 +2023,7 @@ eisa_probe(struct device *dev, u_long ioaddr))
outl(0x00006000, PCI_CFLT);
outl(iobase, PCI_CBIO);
- DevicePresent(DE4X5_APROM);
+ DevicePresent(EISA_APROM);
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
dev->irq = irq;
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
@@ -2081,11 +2062,12 @@ eisa_probe(struct device *dev, u_long ioaddr))
__initfunc(static void
pci_probe(struct device *dev, u_long ioaddr))
{
- u_char pb, pbus, dev_num, dnum, dev_fn, timer, tirq;
- u_short dev_id, vendor, index, status;
- u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+ u_char pb, pbus, dev_num, dnum, dev_fn, timer;
+ u_short vendor, index, status;
+ u_int irq = 0, device, class = DE4X5_CLASS_CODE;
u_long iobase = 0; /* Clear upper 32 bits in Alphas */
struct bus_type *lp = &bus;
+ struct pci_dev *pdev;
if (lastPCI == NO_MORE_PCI) return;
@@ -2109,96 +2091,77 @@ pci_probe(struct device *dev, u_long ioaddr))
(pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
index++) {
dev_num = PCI_SLOT(dev_fn);
- if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
-#ifdef __sparc_v9__
- struct pci_dev *pdev;
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
- }
-#endif
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
-
- /* Search for an SROM on this bus */
- if (lp->bus_num != pb) {
- lp->bus_num = pb;
- srom_search(index);
- }
+ if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+ }
- /* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
- /* Set the device number information */
- lp->device = dev_num;
+ /* Search for an SROM on this bus */
+ if (lp->bus_num != pb) {
lp->bus_num = pb;
+ srom_search(index);
+ }
+
+ /* Get the chip configuration revision register */
+ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+
+ /* Set the device number information */
+ lp->device = dev_num;
+ lp->bus_num = pb;
- /* Set the chipset information */
- if (is_DC2114x) device |= (cfrv & CFRV_RN);
- lp->chipset = device;
+ /* Set the chipset information */
+ if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ lp->chipset = device;
- /* Get the board I/O address (64 bits on sparc64) */
-#ifndef __sparc_v9__
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
- iobase = tmp;
-#else
- iobase = pdev->base_address[0];
-#endif
- iobase &= CBIO_MASK;
+ /* Get the board I/O address (64 bits on sparc64) */
+ iobase = pdev->base_address[0] & CBIO_MASK;
- /* Fetch the IRQ to be used */
-#ifndef __sparc_v9__
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
- irq = tirq;
-#else
- irq = pdev->irq;
-#endif
- if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+ /* Fetch the IRQ to be used */
+ irq = pdev->irq;
+ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
- /* Check if I/O accesses and Bus Mastering are enabled */
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ /* Check if I/O accesses and Bus Mastering are enabled */
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
#ifdef __powerpc__
- if (!(status & PCI_COMMAND_IO)) {
- status |= PCI_COMMAND_IO;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
+ if (!(status & PCI_COMMAND_IO)) {
+ status |= PCI_COMMAND_IO;
+ pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ }
#endif /* __powerpc__ */
- if (!(status & PCI_COMMAND_IO)) continue;
+ if (!(status & PCI_COMMAND_IO)) continue;
- if (!(status & PCI_COMMAND_MASTER)) {
- status |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
- if (!(status & PCI_COMMAND_MASTER)) continue;
+ if (!(status & PCI_COMMAND_MASTER)) {
+ status |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ }
+ if (!(status & PCI_COMMAND_MASTER)) continue;
- /* Check the latency timer for values >= 0x60 */
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
- if (timer < 0x60) {
- pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
- }
+ /* Check the latency timer for values >= 0x60 */
+ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
+ if (timer < 0x60) {
+ pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
+ }
- DevicePresent(DE4X5_APROM);
- if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
- dev->irq = irq;
- if ((status = de4x5_hw_init(dev, iobase)) == 0) {
- num_de4x5s++;
- if (loading_module) {
- link_modules(lastModule, dev);
- lastPCI = index;
- }
- return;
+ DevicePresent(DE4X5_APROM);
+ if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+ dev->irq = irq;
+ if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+ num_de4x5s++;
+ if (loading_module) {
+ link_modules(lastModule, dev);
+ lastPCI = index;
}
- } else if (ioaddr != 0) {
- printk("%s: region already allocated at 0x%04lx.\n", dev->name,
- iobase);
+ return;
}
+ } else if (ioaddr != 0) {
+ printk("%s: region already allocated at 0x%04lx.\n", dev->name,
+ iobase);
}
}
@@ -2216,12 +2179,13 @@ pci_probe(struct device *dev, u_long ioaddr))
__initfunc(static void
srom_search(int index))
{
- u_char pb, dev_fn, tirq;
- u_short dev_id, dev_num, vendor, status;
- u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+ u_char pb, dev_fn;
+ u_short dev_num, vendor, status;
+ u_int irq = 0, device, class = DE4X5_CLASS_CODE;
u_long iobase = 0; /* Clear upper 32 bits in Alphas */
int i, j;
struct bus_type *lp = &bus;
+ struct pci_dev *pdev;
for (;
(pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
@@ -2229,20 +2193,13 @@ srom_search(int index))
if (lp->bus_num != pb) return;
dev_num = PCI_SLOT(dev_fn);
-#ifdef __sparc_v9__
- struct pci_dev *pdev;
for (pdev = pci_devices; pdev; pdev = pdev->next) {
if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break;
}
-#endif
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
+
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
/* Get the chip configuration revision register */
pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
@@ -2256,21 +2213,10 @@ srom_search(int index))
lp->chipset = device;
/* Get the board I/O address (64 bits on sparc64) */
-#ifndef __sparc_v9__
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
- iobase = tmp;
-#else
- iobase = pdev->base_address[0];
-#endif
- iobase &= CBIO_MASK;
+ iobase = pdev->base_address[0] & CBIO_MASK;
/* Fetch the IRQ to be used */
-#ifndef __sparc_v9__
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
- irq = tirq;
-#else
irq = pdev->irq;
-#endif
if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
/* Check if I/O accesses are enabled */
@@ -3982,7 +3928,11 @@ DevicePresent(u_long aprom_addr)
struct bus_type *lp = &bus;
if (lp->chipset == DC21040) {
- outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
+ if (lp->bus == EISA) {
+ enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */
+ } else {
+ outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
+ }
} else { /* Read new srom */
u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
for (i=0; i<(ETH_ALEN>>1); i++) {
@@ -4006,6 +3956,45 @@ DevicePresent(u_long aprom_addr)
}
/*
+** Since the write on the Enet PROM register doesn't seem to reset the PROM
+** pointer correctly (at least on my DE425 EISA card), this routine should do
+** it...from depca.c.
+*/
+static void
+enet_addr_rst(u_long aprom_addr)
+{
+ union {
+ struct {
+ u32 a;
+ u32 b;
+ } llsig;
+ char Sig[sizeof(u32) << 1];
+ } dev;
+ short sigLength=0;
+ s8 data;
+ int i, j;
+
+ dev.llsig.a = ETH_PROM_SIG;
+ dev.llsig.b = ETH_PROM_SIG;
+ sigLength = sizeof(u32) << 1;
+
+ for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+ data = inb(aprom_addr);
+ if (dev.Sig[j] == data) { /* track signature */
+ j++;
+ } else { /* lost signature; begin search again */
+ if (data == dev.Sig[0]) { /* rare case.... */
+ j=1;
+ } else {
+ j=0;
+ }
+ }
+ }
+
+ return;
+}
+
+/*
** For the bad status case and no SROM, then add one to the previous
** address. However, need to add one backwards in case we have 0xff
** as one or more of the bytes. Only the last 3 bytes should be checked
@@ -5665,9 +5654,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
#define LP(a) ((struct de4x5_private *)(a))
static struct device *mdev = NULL;
static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED */
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
MODULE_PARM(io, "i");
-#endif /* LINUX_VERSION_CODE */
int
init_module(void)
@@ -5730,16 +5717,18 @@ unlink_modules(struct device *p)
static int
count_adapters(void)
{
- int i, j;
+ int i, j=0;
char name[DE4X5_STRLEN];
- u_char pb, dev_fn, dev_num;
- u_short dev_id, vendor;
+ u_char pb, dev_fn;
+ u_short vendor;
u_int class = DE4X5_CLASS_CODE;
u_int device;
+ struct pci_dev *pdev;
+
#ifndef __sparc_v9__
u_long iobase = 0x1000;
- for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+ for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID)) j++;
}
#endif
@@ -5748,12 +5737,12 @@ count_adapters(void)
for (i=0;
(pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
i++) {
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+ }
+
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 9a33ea3a4..156a07ba2 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1348,7 +1348,7 @@ speedo_rx(struct device *dev)
#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
if (! rx_in_place) {
skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if defined(__i386) && notyet
+#if defined(__i386__) && notyet
/* Packet is in one chunk -- we can copy + cksum. */
eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
pkt_len, 0);
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index cb6b1bb69..0f1bdd3c7 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1,51 +1,77 @@
/*
- ** hp100.c
- ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
- **
- ** $Id: hp100.c,v 1.14 1997/11/16 13:57:28 alan Exp $
- **
- ** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
- ** Extended for new busmaster capable chipsets by
- ** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
- **
- ** Maintained by: Jaroslav Kysela <perex@jcu.cz>
- **
- ** This driver has only been tested with
- ** -- HP J2585B 10/100 Mbit/s PCI Busmaster
- ** -- HP J2585A 10/100 Mbit/s PCI
- ** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC
- ** -- HP J2973 10 Mbit/s PCI 10base-T
- ** -- HP J2573 10/100 ISA
- ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
- **
- ** but it should also work with the other CASCADE based adapters.
- **
- ** TODO:
- ** - J2573 seems to hang sometimes when in shared memory mode.
- ** - Mode for Priority TX
- ** - Check PCI registers, performance might be improved?
- ** - To reduce interrupt load in busmaster, one could switch off
- ** the interrupts that are used to refill the queues whenever the
- ** queues are filled up to more than a certain threshold.
- **
- **
- ** This source/code is public free; you can distribute it and/or modify
- ** it under terms of the GNU General Public License (published by the
- ** Free Software Foundation) either version two of this License, or any
- ** later version.
- **
- */
-
-#define HP100_DEFAULT_PRIORITY_TX 0
+** hp100.c
+** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
+**
+** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $
+**
+** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
+** Extended for new busmaster capable chipsets by
+** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
+**
+** Maintained by: Jaroslav Kysela <perex@jcu.cz>
+**
+** This driver has only been tested with
+** -- HP J2585B 10/100 Mbit/s PCI Busmaster
+** -- HP J2585A 10/100 Mbit/s PCI
+** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC
+** -- HP J2973 10 Mbit/s PCI 10base-T
+** -- HP J2573 10/100 ISA
+** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
+** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI
+**
+** but it should also work with the other CASCADE based adapters.
+**
+** TODO:
+** - J2573 seems to hang sometimes when in shared memory mode.
+** - Mode for Priority TX
+** - Check PCI registers, performance might be improved?
+** - To reduce interrupt load in busmaster, one could switch off
+** the interrupts that are used to refill the queues whenever the
+** queues are filled up to more than a certain threshold.
+** - some updates for EISA version of card
+**
+**
+** This source/code is public free; you can distribute it and/or modify
+** it under terms of the GNU General Public License (published by the
+** Free Software Foundation) either version two of this License, or any
+** later version.
+**
+** 1.55 -> 1.56
+** - removed printk in misc. interrupt and update statistics to allow
+** monitoring of card status
+** - timing changes in xmit routines, relogin to 100VG hub added when
+** driver does reset
+** - included fix for Compex FreedomLine PCI adapter
+**
+** 1.54 -> 1.55
+** - fixed bad initialization in init_module
+** - added Compex FreedomLine adapter
+** - some fixes in card initialization
+**
+** 1.53 -> 1.54
+** - added hardware multicast filter support (doesn't work)
+** - little changes in hp100_sense_lan routine
+** - added support for Coax and AUI (J2970)
+** - fix for multiple cards and hp100_mode parameter (insmod)
+** - fix for shared IRQ
+**
+** 1.52 -> 1.53
+** - fixed bug in multicast support
+**
+*/
+
+#define HP100_DEFAULT_PRIORITY_TX 0
#undef HP100_DEBUG
-#undef HP100_DEBUG_B /* Trace */
-#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */
+#undef HP100_DEBUG_B /* Trace */
+#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */
-#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */
-#undef HP100_DEBUG_TX
-#undef HP100_DEBUG_IRQ
-#undef HP100_DEBUG_RX
+#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */
+#undef HP100_DEBUG_TX
+#undef HP100_DEBUG_IRQ
+#undef HP100_DEBUG_RX
+
+#undef HP100_MULTICAST_FILTER /* Need to be debugged... */
#include <linux/version.h>
#include <linux/module.h>
@@ -58,7 +84,6 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/bios32.h>
-#include <linux/init.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -67,7 +92,7 @@
#include <linux/skbuff.h>
#include <linux/types.h>
-#include <linux/config.h> /* for CONFIG_PCI */
+#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/delay.h>
#if LINUX_VERSION_CODE < 0x020100
@@ -79,6 +104,12 @@ typedef struct enet_statistics hp100_stats_t;
typedef struct net_device_stats hp100_stats_t;
#endif
+#ifndef __initfunc
+#define __initfunc(__initarg) __initarg
+#else
+#include <linux/init.h>
+#endif
+
#include "hp100.h"
/*
@@ -98,8 +129,14 @@ typedef struct net_device_stats hp100_stats_t;
#ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4
#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
#endif
+#ifndef PCI_VENDOR_ID_COMPEX2
+#define PCI_VENDOR_ID_COMPEX2 0x101a
+#endif
+#ifndef PCI_DEVICE_ID_COMPEX2_100VG
+#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
+#endif
-#define HP100_REGION_SIZE 0x20 /* for ioports */
+#define HP100_REGION_SIZE 0x20 /* for ioports */
#define HP100_MAX_PACKET_SIZE (1536+4)
#define HP100_MIN_PACKET_SIZE 60
@@ -119,135 +156,167 @@ typedef struct net_device_stats hp100_stats_t;
*/
struct hp100_eisa_id {
- u_int id;
- const char *name;
- u_char bus;
+ u_int id;
+ const char *name;
+ u_char bus;
+};
+
+struct hp100_pci_id {
+ u_short vendor;
+ u_short device;
};
struct hp100_private {
- struct hp100_eisa_id *id;
- u_short chip;
- u_short soft_model;
- u_int memory_size;
- u_short rx_ratio; /* 1 - 99 */
- u_short priority_tx; /* != 0 - priority tx */
- u_short mode; /* PIO, Shared Mem or Busmaster */
- u_char bus;
- u_char pci_bus;
- u_char pci_device_fn;
- short mem_mapped; /* memory mapped access */
- u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
- u_int *mem_ptr_phys; /* physical memory mapped area */
- short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
- int hub_status; /* was login to hub successful? */
- u_char mac1_mode;
- u_char mac2_mode;
- hp100_stats_t stats;
-
- /* Rings for busmaster mode: */
- hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */
- hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */
- hp100_ring_t *txrhead; /* Head (oldest) index into txring */
- hp100_ring_t *txrtail; /* Tail (newest) index into txring */
-
- hp100_ring_t rxring[MAX_RX_PDL];
- hp100_ring_t txring[MAX_TX_PDL];
-
- u_int *page_vaddr; /* Virtual address of allocated page */
- u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
- int rxrcommit; /* # Rx PDLs commited to adapter */
- int txrcommit; /* # Tx PDLs commited to adapter */
+ struct hp100_eisa_id *id;
+ u_short chip;
+ u_short soft_model;
+ u_int memory_size;
+ u_int virt_memory_size;
+ u_short rx_ratio; /* 1 - 99 */
+ u_short priority_tx; /* != 0 - priority tx */
+ u_short mode; /* PIO, Shared Mem or Busmaster */
+ u_char bus;
+ u_char pci_bus;
+ u_char pci_device_fn;
+ short mem_mapped; /* memory mapped access */
+ u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */
+ u_int *mem_ptr_phys; /* physical memory mapped area */
+ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
+ int hub_status; /* was login to hub successful? */
+ u_char mac1_mode;
+ u_char mac2_mode;
+ u_char hash_bytes[ 8 ];
+ hp100_stats_t stats;
+
+ /* Rings for busmaster mode: */
+ hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */
+ hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */
+ hp100_ring_t *txrhead; /* Head (oldest) index into txring */
+ hp100_ring_t *txrtail; /* Tail (newest) index into txring */
+
+ hp100_ring_t rxring[ MAX_RX_PDL ];
+ hp100_ring_t txring[ MAX_TX_PDL ];
+
+ u_int *page_vaddr; /* Virtual address of allocated page */
+ u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
+ int rxrcommit; /* # Rx PDLs commited to adapter */
+ int txrcommit; /* # Tx PDLs commited to adapter */
};
/*
* variables
*/
-static struct hp100_eisa_id hp100_eisa_ids[] =
-{
+static struct hp100_eisa_id hp100_eisa_ids[] = {
/* 10/100 EISA card with revision A Cascade chip */
- {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA},
+ { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA },
/* 10/100 ISA card with revision A Cascade chip */
- {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA},
+ { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA },
/* 10 only EISA card with Cascade chip */
- {0x2019F022, "HP 27248B", HP100_BUS_EISA},
+ { 0x2019F022, "HP 27248B", HP100_BUS_EISA },
/* 10/100 EISA card with Cascade chip */
- {0x4019F022, "HP J2577", HP100_BUS_EISA},
+ { 0x4019F022, "HP J2577", HP100_BUS_EISA },
/* 10/100 ISA card with Cascade chip */
- {0x5019F022, "HP J2573", HP100_BUS_ISA},
+ { 0x5019F022, "HP J2573", HP100_BUS_ISA },
/* 10/100 PCI card - old J2585A */
- {0x1030103c, "HP J2585A", HP100_BUS_PCI},
+ { 0x1030103c, "HP J2585A", HP100_BUS_PCI },
/* 10/100 PCI card - new J2585B - master capable */
- {0x1041103c, "HP J2585B", HP100_BUS_PCI},
+ { 0x1041103c, "HP J2585B", HP100_BUS_PCI },
/* 10 Mbit Combo Adapter */
- {0x1042103c, "HP J2970", HP100_BUS_PCI},
+ { 0x1042103c, "HP J2970", HP100_BUS_PCI },
/* 10 Mbit 10baseT Adapter */
- {0x1040103c, "HP J2973", HP100_BUS_PCI},
+ { 0x1040103c, "HP J2973", HP100_BUS_PCI },
/* 10/100 EISA card from Compex */
- {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA},
-
+ { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA },
+
+ /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */
+ /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */
+ /* version of adapter, too... */
+ { 0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA },
+
+ /* 10/100 PCI card from Compex - FreedomLine
+ *
+ * I think this card doesn't like aic7178 scsi controller, but
+ * I haven't tested this much. It works fine on diskless machines.
+ * Jacek Lipkowski <sq5bpf@acid.ch.pw.edu.pl>
+ */
+ { 0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI },
+
/* 10/100 PCI card from Compex (J2585A compatible) */
- {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI}
+ { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI }
+
};
+#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id))
+
+static struct hp100_pci_id hp100_pci_ids[] = {
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A },
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B },
+ { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4 },
+ { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG }
+};
+
+#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id))
+
static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
static int hp100_mode = 1;
#ifdef LINUX_2_1
-MODULE_PARM(hp100_rx_ratio, "1i");
-MODULE_PARM(hp100_priority_tx, "1i");
-MODULE_PARM(hp100_mode, "1i");
+MODULE_PARM( hp100_rx_ratio, "1i" );
+MODULE_PARM( hp100_priority_tx, "1i" );
+MODULE_PARM( hp100_mode, "1i" );
#endif
/*
* prototypes
*/
-static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn);
-static int hp100_open(struct device *dev);
-static int hp100_close(struct device *dev);
-static int hp100_start_xmit(struct sk_buff *skb, struct device *dev);
-static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev);
-static void hp100_rx(struct device *dev);
-static hp100_stats_t *hp100_get_stats(struct device *dev);
-static void hp100_update_stats(struct device *dev);
-static void hp100_clear_stats(int ioaddr);
-static void hp100_set_multicast_list(struct device *dev);
-static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void hp100_start_interface(struct device *dev);
-static void hp100_stop_interface(struct device *dev);
-static void hp100_load_eeprom(struct device *dev);
-static int hp100_sense_lan(struct device *dev);
-static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin);
-static int hp100_down_vg_link(struct device *dev);
-static void hp100_cascade_reset(struct device *dev, u_short enable);
-static void hp100_BM_shutdown(struct device *dev);
-static void hp100_mmuinit(struct device *dev);
-static void hp100_init_pdls(struct device *dev);
-static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u_int * pdlptr);
-static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u_int * pdlptr);
-static void hp100_rxfill(struct device *dev);
-static void hp100_hwinit(struct device *dev);
-static void hp100_clean_txring(struct device *dev);
+static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn );
+static int hp100_open( struct device *dev );
+static int hp100_close( struct device *dev );
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev );
+static void hp100_rx( struct device *dev );
+static hp100_stats_t *hp100_get_stats( struct device *dev );
+static void hp100_misc_interrupt( struct device *dev );
+static void hp100_update_stats( struct device *dev );
+static void hp100_clear_stats( int ioaddr );
+static void hp100_set_multicast_list( struct device *dev);
+static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs );
+static void hp100_start_interface( struct device *dev );
+static void hp100_stop_interface( struct device *dev );
+static void hp100_load_eeprom( struct device *dev, u_short ioaddr );
+static int hp100_sense_lan( struct device *dev );
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin );
+static int hp100_down_vg_link( struct device *dev );
+static void hp100_cascade_reset( struct device *dev, u_short enable );
+static void hp100_BM_shutdown( struct device *dev );
+static void hp100_mmuinit( struct device *dev );
+static void hp100_init_pdls( struct device *dev );
+static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr);
+static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr);
+static void hp100_rxfill( struct device *dev );
+static void hp100_hwinit( struct device *dev );
+static void hp100_clean_txring( struct device *dev );
#ifdef HP100_DEBUG
-static void hp100_RegisterDump(struct device *dev);
+static void hp100_RegisterDump( struct device *dev );
#endif
/* TODO: This function should not really be needed in a good design... */
-static void wait(void)
+static void wait( void )
{
- udelay(1000);
+ udelay( 1000 );
}
/*
@@ -255,863 +324,984 @@ static void wait(void)
* These functions should - if possible - avoid doing write operations
* since this could cause problems when the card is not installed.
*/
-
-__initfunc(int hp100_probe(struct device *dev))
+
+__initfunc(int hp100_probe( struct device *dev ))
{
- int base_addr = dev ? dev->base_addr : 0;
- int ioaddr = 0;
+ int base_addr = dev ? dev -> base_addr : 0;
+ int ioaddr = 0;
#ifdef CONFIG_PCI
- int pci_start_index = 0;
+ int pci_start_index = 0;
#endif
#ifdef HP100_DEBUG_B
- hp100_outw(0x4200, TRACE);
- printk("hp100: probe\n");
-#endif
-
- if (base_addr > 0xff) { /* Check a single specified location. */
- if (check_region(base_addr, HP100_REGION_SIZE))
- return -EINVAL;
- if (base_addr < 0x400)
- return hp100_probe1(dev, base_addr, HP100_BUS_ISA, 0, 0);
- else
- return hp100_probe1(dev, base_addr, HP100_BUS_EISA, 0, 0);
- } else
+ hp100_outw( 0x4200, TRACE );
+ printk( "hp100: %s: probe\n", dev->name );
+#endif
+
+ if ( base_addr > 0xff ) /* Check a single specified location. */
+ {
+ if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL;
+ if ( base_addr < 0x400 )
+ return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 );
+ if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 )
+ return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 );
+#ifdef CONFIG_PCI
+ printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name );
+ return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 );
+#else
+ return -ENODEV;
+#endif
+ }
+ else
#ifdef CONFIG_PCI
- if (base_addr > 0 && base_addr < 8 + 1)
- pci_start_index = 0x100 | (base_addr - 1);
- else
+ if ( base_addr > 0 && base_addr < 8 + 1 )
+ pci_start_index = 0x100 | ( base_addr - 1 );
+ else
#endif
- if (base_addr != 0)
- return -ENXIO;
+ if ( base_addr != 0 ) return -ENXIO;
- /* at first - scan PCI bus(es) */
+ /* at first - scan PCI bus(es) */
#ifdef CONFIG_PCI
- if (pcibios_present()) {
- int pci_index;
+ if ( pcibios_present() )
+ {
+ int pci_index;
#ifdef HP100_DEBUG_PCI
- printk("hp100: PCI BIOS is present, checking for devices..\n");
-#endif
- for (pci_index = pci_start_index & 7; pci_index < 8; pci_index++) {
- u_char pci_bus, pci_device_fn;
- u_short pci_command;
-
- if ((pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A,
- pci_index, &pci_bus,
- &pci_device_fn) != 0) &&
- (pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B,
- pci_index, &pci_bus,
- &pci_device_fn) != 0) &&
- (pcibios_find_device(PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4,
- pci_index, &pci_bus,
- &pci_device_fn) != 0))
- break;
-
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &ioaddr);
-
- ioaddr &= ~3; /* remove I/O space marker in bit 0. */
-
- if (check_region(ioaddr, HP100_REGION_SIZE))
- continue;
-
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if (!(pci_command & PCI_COMMAND_MASTER)) {
-#ifdef HP100_DEBUG
- printk("hp100: PCI Master Bit has not been set. Setting...\n");
+ printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name );
#endif
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
-#ifdef HP100_DEBUG
- printk("hp100: PCI adapter found at 0x%x\n", ioaddr);
-#endif
- if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn) == 0)
- return 0;
- }
- }
- if (pci_start_index > 0)
- return -ENODEV;
-#endif /* CONFIG_PCI */
-
- /* Second: Probe all EISA possible port regions (if EISA bus present) */
- for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) {
- if (check_region(ioaddr, HP100_REGION_SIZE))
- continue;
- if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, 0, 0) == 0)
- return 0;
- }
+ for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ )
+ {
+ u_char pci_bus, pci_device_fn;
+ u_short pci_command;
+ int pci_id_index;
- /* Third Probe all ISA possible port regions */
- for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
- if (check_region(ioaddr, HP100_REGION_SIZE))
- continue;
- if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, 0, 0) == 0)
- return 0;
- }
+ for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ )
+ if ( pcibios_find_device( hp100_pci_ids[ pci_id_index ].vendor,
+ hp100_pci_ids[ pci_id_index ].device,
+ pci_index, &pci_bus,
+ &pci_device_fn ) == 0 ) goto __pci_found;
+ break;
- return -ENODEV;
+ __pci_found:
+ pcibios_read_config_dword( pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &ioaddr );
+
+ ioaddr &= ~3; /* remove I/O space marker in bit 0. */
+
+ if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+
+ pcibios_read_config_word( pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command );
+ if ( !( pci_command & PCI_COMMAND_IO ) )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name );
+#endif
+ pci_command |= PCI_COMMAND_IO;
+ pcibios_write_config_word( pci_bus, pci_device_fn,
+ PCI_COMMAND, pci_command );
+ }
+ if ( !( pci_command & PCI_COMMAND_MASTER ) )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name );
+#endif
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word( pci_bus, pci_device_fn,
+ PCI_COMMAND, pci_command );
+ }
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr );
+#endif
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 )
+ return 0;
+ }
+ }
+ if ( pci_start_index > 0 ) return -ENODEV;
+#endif /* CONFIG_PCI */
+
+ /* Second: Probe all EISA possible port regions (if EISA bus present) */
+ for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
+ {
+ if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0;
+ }
+
+ /* Third Probe all ISA possible port regions */
+ for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
+ {
+ if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue;
+ if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0;
+ }
+
+ return -ENODEV;
}
-
-__initfunc(static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn))
+
+__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ))
{
- int i;
-
- u_char uc, uc_1;
- u_int eisa_id;
- u_int chip;
- u_int memory_size = 0;
- short mem_mapped;
- u_int *mem_ptr_phys, *mem_ptr_virt;
- struct hp100_private *lp;
- struct hp100_eisa_id *eid;
+ int i;
+
+ u_char uc, uc_1;
+ u_int eisa_id;
+ u_int chip;
+ u_int memory_size = 0, virt_memory_size = 0;
+ u_short local_mode, lsw;
+ short mem_mapped;
+ u_int *mem_ptr_phys, *mem_ptr_virt;
+ struct hp100_private *lp;
+ struct hp100_eisa_id *eid;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4201, TRACE);
- printk("hp100: probe1\n");
+ hp100_outw( 0x4201, TRACE );
+ printk("hp100: %s: probe1\n",dev->name);
#endif
- if (dev == NULL) {
+ if ( dev == NULL )
+ {
#ifdef HP100_DEBUG
- printk("hp100_probe1: dev == NULL ?\n");
-#endif
- return EIO;
+ printk( "hp100_probe1: %s: dev == NULL ?\n", dev->name );
+#endif
+ return EIO;
+ }
+
+ if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE )
+ {
+ return -ENODEV;
+ }
+ else
+ {
+ chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK;
+#ifdef HP100_DEBUG
+ if ( chip == HP100_CHIPID_SHASTA )
+ printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name);
+ else if ( chip == HP100_CHIPID_RAINIER )
+ printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name);
+ else if ( chip == HP100_CHIPID_LASSEN )
+ printk("hp100: %s: Lassen Chip detected.\n", dev->name);
+ else
+ printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n",dev->name,chip);
+#endif
+ }
+
+ dev->base_addr = ioaddr;
+
+ hp100_page( ID_MAC_ADDR );
+ for ( i = uc = eisa_id = 0; i < 4; i++ )
+ {
+ eisa_id >>= 8;
+ uc_1 = hp100_inb( BOARD_ID + i );
+ eisa_id |= uc_1 << 24;
+ uc += uc_1;
+ }
+ uc += hp100_inb( BOARD_ID + 4 );
+
+ if ( uc != 0xff ) /* bad checksum? */
+ {
+ printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr );
+ return -ENODEV;
+ }
+
+ for ( i=0; i < HP100_EISA_IDS_SIZE; i++)
+ if ( hp100_eisa_ids[ i ].id == eisa_id )
+ break;
+ if ( i >= HP100_EISA_IDS_SIZE ) {
+ for ( i = 0; i < HP100_EISA_IDS_SIZE; i++)
+ if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
+ break;
+ if ( i >= HP100_EISA_IDS_SIZE ) {
+ printk( "hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev -> name, ioaddr, eisa_id );
+ return -ENODEV;
+ }
+ }
+ eid = &hp100_eisa_ids[ i ];
+ if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+ {
+ printk( "hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n",
+ dev->name, eid->name, ioaddr );
+ return -ENODEV;
+ }
+
+ for ( i = uc = 0; i < 7; i++ )
+ uc += hp100_inb( LAN_ADDR + i );
+ if ( uc != 0xff )
+ {
+ printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n",
+ dev->name, eid->name, ioaddr );
+ return -EIO;
+ }
+
+ /* Make sure, that all registers are correctly updated... */
+
+ hp100_load_eeprom( dev, ioaddr );
+ wait();
+
+ /*
+ * Determine driver operation mode
+ *
+ * Use the variable "hp100_mode" upon insmod or as kernel parameter to
+ * force driver modes:
+ * hp100_mode=1 -> default, use busmaster mode if configured.
+ * hp100_mode=2 -> enable shared memory mode
+ * hp100_mode=3 -> force use of i/o mapped mode.
+ * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
+ */
+
+ /*
+ * LSW values:
+ * 0x2278 -> J2585B, PnP shared memory mode
+ * 0x2270 -> J2585B, shared memory mode, 0xdc000
+ * 0xa23c -> J2585B, I/O mapped mode
+ * 0x2240 -> EISA COMPEX, BusMaster (Shasta Chip)
+ * 0x2220 -> EISA HP, I/O (Shasta Chip)
+ * 0x2260 -> EISA HP, BusMaster (Shasta Chip)
+ */
+
+#if 0
+ local_mode = 0x2270;
+ hp100_outw(0xfefe,OPTION_LSW);
+ hp100_outw(local_mode|HP100_SET_LB|HP100_SET_HB,OPTION_LSW);
+#endif
+
+ /* hp100_mode value maybe used in future by another card */
+ local_mode=hp100_mode;
+ if ( local_mode < 1 || local_mode > 4 )
+ local_mode = 1; /* default */
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: original LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) );
+#endif
+
+ if(local_mode==3)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: %s: IO mapped mode forced.\n", dev->name);
+ }
+ else if(local_mode==2)
+ {
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW);
+ hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW);
+ printk("hp100: %s: Shared memory mode requested.\n", dev->name);
+ }
+ else if(local_mode==4)
+ {
+ if(chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_outw(HP100_BM_WRITE|
+ HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
+ hp100_outw(HP100_IO_EN |
+ HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
+ printk("hp100: %s: Busmaster mode requested.\n",dev->name);
}
- if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) {
- return -ENODEV;
- } else {
- chip = hp100_inw(PAGING) & HP100_CHIPID_MASK;
+ local_mode=1;
+ }
+
+ if(local_mode==1) /* default behaviour */
+ {
+ lsw = hp100_inw(OPTION_LSW);
+
+ if ( (lsw & HP100_IO_EN) &&
+ (~lsw & HP100_MEM_EN) &&
+ (~lsw & (HP100_BM_WRITE|HP100_BM_READ)) )
+ {
#ifdef HP100_DEBUG
- if (chip == HP100_CHIPID_SHASTA)
- printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n");
- else if (chip == HP100_CHIPID_RAINIER)
- printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n");
- else if (chip == HP100_CHIPID_LASSEN)
- printk("hp100: Lassen Chip detected.\n");
- else
- printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n", chip);
+ printk("hp100: %s: IO_EN bit is set on card.\n",dev->name);
#endif
+ local_mode=3;
}
-
- dev->base_addr = ioaddr;
-
- hp100_page(ID_MAC_ADDR);
- for (i = uc = eisa_id = 0; i < 4; i++) {
- eisa_id >>= 8;
- uc_1 = hp100_inb(BOARD_ID + i);
- eisa_id |= uc_1 << 24;
- uc += uc_1;
+ else if ( chip == HP100_CHIPID_LASSEN &&
+ ( lsw & (HP100_BM_WRITE|HP100_BM_READ) ) ==
+ (HP100_BM_WRITE|HP100_BM_READ) )
+ {
+ printk("hp100: %s: Busmaster mode enabled.\n",dev->name);
+ hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW);
}
- uc += hp100_inb(BOARD_ID + 4);
-
- if (uc != 0xff) { /* bad checksum? */
- printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr);
- return -ENODEV;
- }
- for (i = 0; i < sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id); i++)
- if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff))
- break;
- if (i >= sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id)) {
- printk("hp100_probe1: card at port 0x%x isn't known (id = 0x%x)\n", ioaddr, eisa_id);
- return -ENODEV;
- }
- eid = &hp100_eisa_ids[i];
- if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) {
- printk("hp100_probe1: newer version of card %s at port 0x%x - unsupported\n",
- eid->name, ioaddr);
- return -ENODEV;
- }
- for (i = uc = 0; i < 7; i++)
- uc += hp100_inb(LAN_ADDR + i);
- if (uc != 0xff) {
- printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
- eid->name, ioaddr);
- return -EIO;
- }
- /* Determine driver operation mode
-
- * Use the variable "hp100_mode" upon insmod or as kernel parameter to
- * force driver modes:
- * hp100_mode=1 -> default, use busmaster mode if configured.
- * hp100_mode=2 -> enable shared memory mode
- * hp100_mode=3 -> force use of i/o mapped mode.
- * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
- */
-
- if (hp100_mode == 3) {
- hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
- hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
- hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
- printk("hp100: IO mapped mode forced.\n");
- } else if (hp100_mode == 2) {
- hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
- hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
- hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
- printk("hp100: Shared memory mode requested.\n");
- } else if (hp100_mode == 4) {
- if (chip == HP100_CHIPID_LASSEN) {
- hp100_outw(HP100_BM_WRITE |
- HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
- hp100_outw(HP100_IO_EN |
- HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
- printk("hp100: Busmaster mode requested.\n");
- }
- hp100_mode = 1;
- }
- if (hp100_mode == 1) { /* default behaviour */
- if ((hp100_inw(OPTION_LSW) & HP100_IO_EN) &&
- (~hp100_inw(OPTION_LSW) & HP100_MEM_EN) &&
- (~hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ))
- ) {
-#ifdef HP100_DEBUG
- printk("hp100: IO_EN bit is set on card.\n");
-#endif
- hp100_mode = 3;
- } else if ((chip == HP100_CHIPID_LASSEN) &&
- ((hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) ==
- (HP100_BM_WRITE | HP100_BM_READ))) {
- printk("hp100: Busmaster mode enabled.\n");
- hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
- } else {
+ else
+ {
#ifdef HP100_DEBUG
- printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n");
+ printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name );
+ printk("hp100: %s: Trying shared memory mode.\n", dev->name);
#endif
- /* In this case, try shared memory mode */
- hp100_mode = 2;
- hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
- /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
- }
+ /* In this case, try shared memory mode */
+ local_mode=2;
+ hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW);
+ /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
}
- /* Check for shared memory on the card, eventually remap it */
- hp100_page(HW_MAP);
- mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0);
- mem_ptr_phys = mem_ptr_virt = NULL;
- memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07));
-
- /* For memory mapped or busmaster mode, we want the memory address */
- if (mem_mapped || (hp100_mode == 1)) {
- mem_ptr_phys = (u_int *) (hp100_inw(MEM_MAP_LSW) |
- (hp100_inw(MEM_MAP_MSW) << 16));
- (u_int) mem_ptr_phys &= ~0x1fff; /* 8k alignment */
-
- if (bus == HP100_BUS_ISA && ((u_long) mem_ptr_phys & ~0xfffff) != 0) {
- printk("hp100: Can only use programmed i/o mode.\n");
- mem_ptr_phys = NULL;
- mem_mapped = 0;
- hp100_mode = 3; /* Use programmed i/o */
- }
- /* We do not need access to shared memory in busmaster mode */
- /* However in slave mode we need to remap high (>1GB) card memory */
- if (hp100_mode != 1) { /* = not busmaster */
- if (bus == HP100_BUS_PCI) {
- /* We try with smaller memory sizes, if ioremap fails */
- for (; memory_size > 16383; memory_size = memory_size / 2) {
- if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, memory_size)) == NULL) {
+ }
+
#ifdef HP100_DEBUG
- printk("hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long) mem_ptr_phys);
+ printk( "hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) );
+#endif
+
+ /* Check for shared memory on the card, eventually remap it */
+ hp100_page( HW_MAP );
+ mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0);
+ mem_ptr_phys = mem_ptr_virt = NULL;
+ memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07));
+ virt_memory_size = 0;
+
+ /* For memory mapped or busmaster mode, we want the memory address */
+ if ( mem_mapped || (local_mode==1))
+ {
+ mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) |
+ ( hp100_inw( MEM_MAP_MSW ) << 16 ) );
+ (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */
+
+ if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 )
+ {
+ printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name);
+ mem_ptr_phys = NULL;
+ mem_mapped = 0;
+ local_mode=3; /* Use programmed i/o */
+ }
+
+ /* We do not need access to shared memory in busmaster mode */
+ /* However in slave mode we need to remap high (>1GB) card memory */
+ if(local_mode!=1) /* = not busmaster */
+ {
+ if ( bus == HP100_BUS_PCI && mem_ptr_phys >= (u_int *)0x100000 )
+ {
+ /* We try with smaller memory sizes, if ioremap fails */
+ for(virt_memory_size = memory_size; virt_memory_size>16383; virt_memory_size>>=1)
+ {
+ if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,virt_memory_size))==NULL)
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys );
#endif
- } else {
+ }
+ else
+ {
#ifdef HP100_DEBUG
- printk("hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long) mem_ptr_phys, (u_long) mem_ptr_virt);
-#endif
- break;
- }
- }
-
- if (mem_ptr_virt == NULL) { /* all ioremap tries failed */
- printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n");
- hp100_mode = 3;
- memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07));
- }
- }
+ printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt);
+#endif
+ break;
+ }
}
+
+ if(mem_ptr_virt==NULL) /* all ioremap tries failed */
+ {
+ printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name);
+ local_mode=3;
+ virt_memory_size = 0;
+ }
+ }
}
- if (hp100_mode == 3) { /* io mapped forced */
- mem_mapped = 0;
- mem_ptr_phys = mem_ptr_virt = NULL;
- printk("hp100: Using (slow) programmed i/o mode.\n");
- }
- /* Initialise the "private" data structure for this card. */
- if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct hp100_private));
-
- lp = (struct hp100_private *) dev->priv;
- lp->id = eid;
- lp->chip = chip;
- lp->mode = hp100_mode;
- lp->pci_bus = pci_bus;
- lp->bus = bus;
- lp->pci_device_fn = pci_device_fn;
- lp->priority_tx = hp100_priority_tx;
- lp->rx_ratio = hp100_rx_ratio;
- lp->mem_ptr_phys = mem_ptr_phys;
- lp->mem_ptr_virt = mem_ptr_virt;
- hp100_page(ID_MAC_ADDR);
- lp->soft_model = hp100_inb(SOFT_MODEL);
- lp->mac1_mode = HP100_MAC1MODE3;
- lp->mac2_mode = HP100_MAC2MODE3;
-
- dev->base_addr = ioaddr;
-
- lp->memory_size = memory_size;
- lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
-
- /* memory region for programmed i/o */
- request_region(dev->base_addr, HP100_REGION_SIZE, eid->name);
-
- dev->open = hp100_open;
- dev->stop = hp100_close;
-
- if (lp->mode == 1) /* busmaster */
- dev->hard_start_xmit = hp100_start_xmit_bm;
- else
- dev->hard_start_xmit = hp100_start_xmit;
-
- dev->get_stats = hp100_get_stats;
- dev->set_multicast_list = &hp100_set_multicast_list;
-
- /* Ask the card for which IRQ line it is configured */
- hp100_page(HW_MAP);
- dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK;
- if (dev->irq == 2)
- dev->irq = 9;
-
- if (lp->mode == 1) /* busmaster */
- dev->dma = 4;
-
- /* Ask the card for its MAC address and store it for later use. */
- hp100_page(ID_MAC_ADDR);
- for (i = uc = 0; i < 6; i++)
- dev->dev_addr[i] = hp100_inb(LAN_ADDR + i);
-
- /* Reset statistics (counters) */
- hp100_clear_stats(ioaddr);
-
- ether_setup(dev);
-
- /* If busmaster mode is wanted, a dma-capable memory area is needed for
- * the rx and tx PDLs
- * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
- * needed for the allocation of the memory area.
- */
-
- /* TODO: We do not need this with old cards, where PDLs are stored
- * in the cards shared memory area. But currently, busmaster has been
- * implemented/tested only with the lassen chip anyway... */
- if (lp->mode == 1) { /* busmaster */
- /* Get physically continous memory for TX & RX PDLs */
- if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f));
- memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f);
+
+ }
+
+ if(local_mode==3) /* io mapped forced */
+ {
+ mem_mapped = 0;
+ mem_ptr_phys = mem_ptr_virt = NULL;
+ printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name);
+ }
+
+ /* Initialise the "private" data structure for this card. */
+ if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset( dev->priv, 0, sizeof(struct hp100_private) );
+
+ lp = (struct hp100_private *)dev->priv;
+ lp->id = eid;
+ lp->chip = chip;
+ lp->mode = local_mode;
+ lp->pci_bus = pci_bus;
+ lp->bus = bus;
+ lp->pci_device_fn = pci_device_fn;
+ lp->priority_tx = hp100_priority_tx;
+ lp->rx_ratio = hp100_rx_ratio;
+ lp->mem_ptr_phys = mem_ptr_phys;
+ lp->mem_ptr_virt = mem_ptr_virt;
+ hp100_page( ID_MAC_ADDR );
+ lp->soft_model = hp100_inb( SOFT_MODEL );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
+ memset( &lp->hash_bytes, 0x00, 8 );
+
+ dev->base_addr = ioaddr;
+
+ lp->memory_size = memory_size;
+ lp->virt_memory_size = virt_memory_size;
+ lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
+
+ /* memory region for programmed i/o */
+ request_region( dev->base_addr, HP100_REGION_SIZE, eid->name );
+
+ dev->open = hp100_open;
+ dev->stop = hp100_close;
+
+ if (lp->mode==1) /* busmaster */
+ dev->hard_start_xmit = hp100_start_xmit_bm;
+ else
+ dev->hard_start_xmit = hp100_start_xmit;
+
+ dev->get_stats = hp100_get_stats;
+ dev->set_multicast_list = &hp100_set_multicast_list;
+
+ /* Ask the card for which IRQ line it is configured */
+ hp100_page( HW_MAP );
+ dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK;
+ if ( dev->irq == 2 )
+ dev->irq = 9;
+
+ if(lp->mode==1) /* busmaster */
+ dev->dma=4;
+
+ /* Ask the card for its MAC address and store it for later use. */
+ hp100_page( ID_MAC_ADDR );
+ for ( i = uc = 0; i < 6; i++ )
+ dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+
+ /* Reset statistics (counters) */
+ hp100_clear_stats( ioaddr );
+
+ ether_setup( dev );
+
+ /* If busmaster mode is wanted, a dma-capable memory area is needed for
+ * the rx and tx PDLs
+ * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
+ * needed for the allocation of the memory area.
+ */
+
+ /* TODO: We do not need this with old cards, where PDLs are stored
+ * in the cards shared memory area. But currently, busmaster has been
+ * implemented/tested only with the lassen chip anyway... */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Get physically continous memory for TX & RX PDLs */
+ if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL)
+ return -ENOMEM;
+ lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f));
+ memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f);
#ifdef HP100_DEBUG_BM
- printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n",
- (u_int) lp->page_vaddr_algn,
- (u_int) lp->page_vaddr_algn + MAX_RINGSIZE);
-#endif
- lp->rxrcommit = lp->txrcommit = 0;
- lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
- lp->txrhead = lp->txrtail = &(lp->txring[0]);
- }
- /* Initialise the card. */
- /* (I'm not really sure if it's a good idea to do this during probing, but
- * like this it's assured that the lan connection type can be sensed
- * correctly)
- */
- hp100_hwinit(dev);
-
- /* Try to find out which kind of LAN the card is connected to. */
- lp->lan_type = hp100_sense_lan(dev);
-
- /* Print out a message what about what we think we have probed. */
- printk("hp100: %s: %s at 0x%x, IRQ %d, ",
- dev->name, lp->id->name, ioaddr, dev->irq);
- switch (bus) {
- case HP100_BUS_EISA:
- printk("EISA");
- break;
- case HP100_BUS_PCI:
- printk("PCI");
- break;
- default:
- printk("ISA");
- break;
- }
- printk(" bus, %dk SRAM (rx/tx %d%%).\n",
- lp->memory_size >> 10, lp->rx_ratio);
-
- if (lp->mode == 2) { /* memory mapped */
- printk("%s: Memory area at 0x%lx-0x%lx",
- dev->name, (u_long) mem_ptr_phys, (u_long) mem_ptr_phys + (u_long) lp->memory_size);
- if (mem_ptr_virt)
- printk(" (virtual base 0x%lx)", (u_long) mem_ptr_virt);
- printk(".\n");
-
- /* Set for info when doing ifconfig */
- dev->mem_start = (u_long) mem_ptr_phys;
- dev->mem_end = (u_long) mem_ptr_phys + (u_long) lp->memory_size;
- }
- printk("%s: ", dev->name);
- if (lp->lan_type != HP100_LAN_ERR)
- printk("Adapter is attached to ");
- switch (lp->lan_type) {
- case HP100_LAN_100:
- printk("100Mb/s Voice Grade AnyLAN network.\n");
- break;
- case HP100_LAN_10:
- printk("10Mb/s network.\n");
- break;
- default:
- printk("Warning! Link down.\n");
- }
- return 0;
+ printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n",
+ dev->name,
+ (u_int)lp->page_vaddr_algn,
+ (u_int)lp->page_vaddr_algn+MAX_RINGSIZE);
+#endif
+ lp->rxrcommit = lp->txrcommit = 0;
+ lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
+ lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ }
+
+ /* Initialise the card. */
+ /* (I'm not really sure if it's a good idea to do this during probing, but
+ * like this it's assured that the lan connection type can be sensed
+ * correctly)
+ */
+ hp100_hwinit( dev );
+
+ /* Try to find out which kind of LAN the card is connected to. */
+ lp->lan_type = hp100_sense_lan( dev );
+
+ /* Print out a message what about what we think we have probed. */
+ printk( "hp100: %s: %s at 0x%x, IRQ %d, ",
+ dev->name, lp->id->name, ioaddr, dev->irq );
+ switch ( bus ) {
+ case HP100_BUS_EISA: printk( "EISA" ); break;
+ case HP100_BUS_PCI: printk( "PCI" ); break;
+ default: printk( "ISA" ); break;
+ }
+ printk( " bus, %dk SRAM (rx/tx %d%%).\n",
+ lp->memory_size >> 10, lp->rx_ratio );
+
+ if ( lp->mode==2 ) /* memory mapped */
+ {
+ printk( "hp100: %s: Memory area at 0x%lx-0x%lx",
+ dev->name,(u_long)mem_ptr_phys,
+ ((u_long)mem_ptr_phys+(mem_ptr_phys>(u_int *)0x100000?(u_long)lp->memory_size:16*1024))-1 );
+ if ( mem_ptr_virt )
+ printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt );
+ printk( ".\n" );
+
+ /* Set for info when doing ifconfig */
+ dev->mem_start = (u_long)mem_ptr_phys;
+ dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size;
+ }
+ printk( "hp100: %s: ", dev->name );
+ if ( lp->lan_type != HP100_LAN_ERR )
+ printk( "Adapter is attached to " );
+ switch ( lp->lan_type ) {
+ case HP100_LAN_100:
+ printk( "100Mb/s Voice Grade AnyLAN network.\n" );
+ break;
+ case HP100_LAN_10:
+ printk( "10Mb/s network.\n" );
+ break;
+ default:
+ printk( "Warning! Link down.\n" );
+ }
+
+ return 0;
}
-
+
/* This procedure puts the card into a stable init state */
-static void hp100_hwinit(struct device *dev)
+static void hp100_hwinit( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4202, TRACE);
- printk("hp100: hwinit\n");
-#endif
-
- /* Initialise the card. -------------------------------------------- */
-
- /* Clear all pending Ints and disable Ints */
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */
-
- hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
- hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
-
- if (lp->mode == 1) {
- hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */
- wait();
- } else {
- hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
- hp100_cascade_reset(dev, TRUE);
- hp100_page(MAC_CTRL);
- hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);
- }
-
- /* Initiate EEPROM reload */
- hp100_load_eeprom(dev);
-
- wait();
-
- /* Go into reset again. */
- hp100_cascade_reset(dev, TRUE);
-
- /* Set Option Registers to a safe state */
- hp100_outw(HP100_DEBUG_EN |
- HP100_RX_HDR |
- HP100_EE_EN |
- HP100_BM_WRITE |
- HP100_BM_READ | HP100_RESET_HB |
- HP100_FAKE_INT |
- HP100_INT_EN |
- HP100_MEM_EN |
- HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
-
- hp100_outw(HP100_TRI_INT |
- HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW);
-
- hp100_outb(HP100_PRIORITY_TX |
- HP100_ADV_NXT_PKT |
- HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW);
-
- /* TODO: Configure MMU for Ram Test. */
- /* TODO: Ram Test. */
-
- /* Re-check if adapter is still at same i/o location */
- /* (If the base i/o in eeprom has been changed but the */
- /* registers had not been changed, a reload of the eeprom */
- /* would move the adapter to the address stored in eeprom */
-
- /* TODO: Code to implement. */
-
- /* Until here it was code from HWdiscover procedure. */
- /* Next comes code from mmuinit procedure of SCO BM driver which is
- * called from HWconfigure in the SCO driver. */
-
- /* Initialise MMU, eventually switch on Busmaster Mode, initialise
- * multicast filter...
- */
- hp100_mmuinit(dev);
-
- /* We don't turn the interrupts on here - this is done by start_interface. */
- wait(); /* TODO: Do we really need this? */
-
- /* Enable Hardware (e.g. unreset) */
- hp100_cascade_reset(dev, FALSE);
-
- /* ------- initialisation complete ----------- */
-
- /* Finally try to log in the Hub if there may be a VG connection. */
- if (lp->lan_type != HP100_LAN_10)
- hp100_login_to_vg_hub(dev, FALSE); /* relogin */
+ hp100_outw( 0x4202, TRACE );
+ printk("hp100: %s: hwinit\n", dev->name);
+#endif
+
+ /* Initialise the card. -------------------------------------------- */
+
+ /* Clear all pending Ints and disable Ints */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */
+
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */
+ wait();
+ }
+ else
+ {
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+ hp100_cascade_reset( dev, TRUE );
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1);
+ }
+
+ /* Initiate EEPROM reload */
+ hp100_load_eeprom( dev, 0 );
+
+ wait();
+
+ /* Go into reset again. */
+ hp100_cascade_reset( dev, TRUE );
+
+ /* Set Option Registers to a safe state */
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN |
+ HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB |
+ HP100_FAKE_INT |
+ HP100_INT_EN |
+ HP100_MEM_EN |
+ HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
+
+ hp100_outw( HP100_TRI_INT |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+
+ hp100_outb( HP100_PRIORITY_TX |
+ HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* TODO: Configure MMU for Ram Test. */
+ /* TODO: Ram Test. */
+
+ /* Re-check if adapter is still at same i/o location */
+ /* (If the base i/o in eeprom has been changed but the */
+ /* registers had not been changed, a reload of the eeprom */
+ /* would move the adapter to the address stored in eeprom */
+
+ /* TODO: Code to implement. */
+
+ /* Until here it was code from HWdiscover procedure. */
+ /* Next comes code from mmuinit procedure of SCO BM driver which is
+ * called from HWconfigure in the SCO driver. */
+
+ /* Initialise MMU, eventually switch on Busmaster Mode, initialise
+ * multicast filter...
+ */
+ hp100_mmuinit( dev );
+
+ /* We don't turn the interrupts on here - this is done by start_interface. */
+ wait(); /* TODO: Do we really need this? */
+
+ /* Enable Hardware (e.g. unreset) */
+ hp100_cascade_reset( dev, FALSE );
+
+ /* ------- initialisation complete ----------- */
+
+ /* Finally try to log in the Hub if there may be a VG connection. */
+ if( lp->lan_type != HP100_LAN_10 )
+ hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
}
-
+
/*
* mmuinit - Reinitialise Cascade MMU and MAC settings.
* Note: Must already be in reset and leaves card in reset.
*/
-static void hp100_mmuinit(struct device *dev)
+static void hp100_mmuinit( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- int i;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int i;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4203, TRACE);
- printk("hp100: mmuinit\n");
+ hp100_outw( 0x4203, TRACE );
+ printk("hp100: %s: mmuinit\n",dev->name);
#endif
#ifdef HP100_DEBUG
- if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) {
- printk("hp100: Not in reset when entering mmuinit. Fix me.\n");
- return;
- }
-#endif
-
- /* Make sure IRQs are masked off and ack'ed. */
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
-
- /*
- * Enable Hardware
- * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
- * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
- * - Clear Priority, Advance Pkt and Xmit Cmd
- */
-
- hp100_outw(HP100_DEBUG_EN |
- HP100_RX_HDR |
- HP100_EE_EN | HP100_RESET_HB |
- HP100_IO_EN |
- HP100_FAKE_INT |
- HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-
- hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
-
- if (lp->mode == 1) { /* busmaster */
- hp100_outw(HP100_BM_WRITE |
- HP100_BM_READ |
- HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW);
- } else if (lp->mode == 2) { /* memory mapped */
- hp100_outw(HP100_BM_WRITE |
- HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
- hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW);
- hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
- hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
- } else if (lp->mode == 3) { /* i/o mapped mode */
- hp100_outw(HP100_MMAP_DIS | HP100_SET_HB |
- HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
- }
- hp100_page(HW_MAP);
- hp100_outb(0, EARLYRXCFG);
- hp100_outw(0, EARLYTXCFG);
-
- /*
- * Enable Bus Master mode
- */
- if (lp->mode == 1) { /* busmaster */
- /* Experimental: Set some PCI configuration bits */
- hp100_page(HW_MAP);
- hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */
- hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */
-
- /* PCI Bus failures should result in a Misc. Interrupt */
- hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2);
-
- hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW);
- hp100_page(HW_MAP);
- /* Use Burst Mode and switch on PAGE_CK */
- hp100_orb(HP100_BM_BURST_RD |
- HP100_BM_BURST_WR, BM);
- if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA))
- hp100_orb(HP100_BM_PAGE_CK, BM);
- hp100_orb(HP100_BM_MASTER, BM);
- } else { /* not busmaster */
- hp100_page(HW_MAP);
- hp100_andb(~HP100_BM_MASTER, BM);
- }
-
- /*
- * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
- */
- hp100_page(MMU_CFG);
- if (lp->mode == 1) { /* only needed for Busmaster */
- int xmit_stop, recv_stop;
-
- if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) {
- int pdl_stop;
-
- /*
- * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
- * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded
- * to the next higher 1k boundary) bytes for the rx-pdl's
- * Note: For non-etr chips the transmit stop register must be
- * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
- */
- pdl_stop = lp->memory_size;
- xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff);
- recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff);
- hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP);
+ if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) )
+ {
+ printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n",dev->name);
+ return;
+ }
+#endif
+
+ /* Make sure IRQs are masked off and ack'ed. */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /*
+ * Enable Hardware
+ * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
+ * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
+ * - Clear Priority, Advance Pkt and Xmit Cmd
+ */
+
+ hp100_outw( HP100_DEBUG_EN |
+ HP100_RX_HDR |
+ HP100_EE_EN | HP100_RESET_HB |
+ HP100_IO_EN |
+ HP100_FAKE_INT |
+ HP100_INT_EN | HP100_RESET_LB, OPTION_LSW );
+
+ hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
+
+ if(lp->mode==1) /* busmaster */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ |
+ HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ }
+ else if(lp->mode==2) /* memory mapped */
+ {
+ hp100_outw( HP100_BM_WRITE |
+ HP100_BM_READ | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
+ hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW );
+ hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
+ else if( lp->mode==3 ) /* i/o mapped mode */
+ {
+ hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
+ HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ }
+
+ hp100_page( HW_MAP );
+ hp100_outb( 0, EARLYRXCFG );
+ hp100_outw( 0, EARLYTXCFG );
+
+ /*
+ * Enable Bus Master mode
+ */
+ if(lp->mode==1) /* busmaster */
+ {
+ /* Experimental: Set some PCI configuration bits */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */
+ hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */
+
+ /* PCI Bus failures should result in a Misc. Interrupt */
+ hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2);
+
+ hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW );
+ hp100_page( HW_MAP );
+ /* Use Burst Mode and switch on PAGE_CK */
+ hp100_orb( HP100_BM_BURST_RD |
+ HP100_BM_BURST_WR, BM);
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ hp100_orb( HP100_BM_PAGE_CK, BM );
+ hp100_orb( HP100_BM_MASTER, BM );
+ }
+ else /* not busmaster */
+ {
+ hp100_page(HW_MAP);
+ hp100_andb(~HP100_BM_MASTER, BM );
+ }
+
+ /*
+ * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
+ */
+ hp100_page( MMU_CFG );
+ if(lp->mode==1) /* only needed for Busmaster */
+ {
+ int xmit_stop, recv_stop;
+
+ if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA))
+ {
+ int pdl_stop;
+
+ /*
+ * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
+ * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded
+ * to the next higher 1k boundary) bytes for the rx-pdl's
+ * Note: For non-etr chips the transmit stop register must be
+ * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
+ */
+ pdl_stop = lp->memory_size;
+ xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff);
+ recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff);
+ hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP );
#ifdef HP100_DEBUG_BM
- printk("hp100: PDL_STOP = 0x%x\n", pdl_stop);
+ printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop);
#endif
- } else { /* ETR chip (Lassen) in busmaster mode */
- xmit_stop = (lp->memory_size) - 1;
- recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff);
- }
+ }
+ else /* ETR chip (Lassen) in busmaster mode */
+ {
+ xmit_stop = ( lp->memory_size ) - 1;
+ recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff);
+ }
- hp100_outw(xmit_stop >> 4, TX_MEM_STOP);
- hp100_outw(recv_stop >> 4, RX_MEM_STOP);
+ hp100_outw( xmit_stop>>4 , TX_MEM_STOP );
+ hp100_outw( recv_stop>>4 , RX_MEM_STOP );
#ifdef HP100_DEBUG_BM
- printk("hp100: TX_STOP = 0x%x\n", xmit_stop >> 4);
- printk("hp100: RX_STOP = 0x%x\n", recv_stop >> 4);
-#endif
- } else { /* Slave modes (memory mapped and programmed io) */
- hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP);
- hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP);
+ printk("hp100: %s: TX_STOP = 0x%x\n",dev->name,xmit_stop>>4);
+ printk("hp100: %s: RX_STOP = 0x%x\n",dev->name,recv_stop>>4);
+#endif
+ }
+ else /* Slave modes (memory mapped and programmed io) */
+ {
+ hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP );
+ hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP );
#ifdef HP100_DEBUG
- printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP));
- printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP));
-#endif
- }
-
- /* Write MAC address into page 1 */
- hp100_page(MAC_ADDRESS);
- for (i = 0; i < 6; i++)
- hp100_outb(dev->dev_addr[i], MAC_ADDR + i);
-
- /* Zero the multicast hash registers */
- for (i = 0; i < 8; i++)
- hp100_outb(0x0, HASH_BYTE0 + i);
-
- /* Set up MAC defaults */
- hp100_page(MAC_CTRL);
-
- /* Go to LAN Page and zero all filter bits */
- /* Zero accept error, accept multicast, accept broadcast and accept */
- /* all directed packet bits */
- hp100_andb(~(HP100_RX_EN |
- HP100_TX_EN |
- HP100_ACC_ERRORED |
- HP100_ACC_MC |
- HP100_ACC_BC |
- HP100_ACC_PHY), MAC_CFG_1);
-
- hp100_outb(0x00, MAC_CFG_2);
-
- /* Zero the frame format bit. This works around a training bug in the */
- /* new hubs. */
- hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */
-
- if (lp->priority_tx)
- hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW);
- else
- hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW);
-
- hp100_outb(HP100_ADV_NXT_PKT |
- HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW);
-
- /* If busmaster, initialize the PDLs */
- if (lp->mode == 1)
- hp100_init_pdls(dev);
-
- /* Go to performance page and initalize isr and imr registers */
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
+ printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(TX_MEM_STOP));
+ printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(RX_MEM_STOP));
+#endif
+ }
+
+ /* Write MAC address into page 1 */
+ hp100_page( MAC_ADDRESS );
+ for ( i = 0; i < 6; i++ )
+ hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i );
+
+ /* Zero the multicast hash registers */
+ for ( i = 0; i < 8; i++ )
+ hp100_outb( 0x0, HASH_BYTE0 + i );
+
+ /* Set up MAC defaults */
+ hp100_page( MAC_CTRL );
+
+ /* Go to LAN Page and zero all filter bits */
+ /* Zero accept error, accept multicast, accept broadcast and accept */
+ /* all directed packet bits */
+ hp100_andb( ~(HP100_RX_EN|
+ HP100_TX_EN|
+ HP100_ACC_ERRORED|
+ HP100_ACC_MC|
+ HP100_ACC_BC|
+ HP100_ACC_PHY), MAC_CFG_1 );
+
+ hp100_outb( 0x00, MAC_CFG_2 );
+
+ /* Zero the frame format bit. This works around a training bug in the */
+ /* new hubs. */
+ hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */
+
+ if(lp->priority_tx)
+ hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW );
+ else
+ hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW );
+
+ hp100_outb( HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+
+ /* If busmaster, initialize the PDLs */
+ if(lp->mode==1)
+ hp100_init_pdls( dev );
+
+ /* Go to performance page and initalize isr and imr registers */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
}
-
+
/*
* open/close functions
*/
-static int hp100_open(struct device *dev)
+static int hp100_open( struct device *dev )
{
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- int ioaddr = dev->base_addr;
+ int ioaddr=dev->base_addr;
#endif
#ifdef HP100_DEBUG_B
- hp100_outw(0x4204, TRACE);
- printk("hp100: open\n");
-#endif
-
- /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
- if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) {
- if (request_irq(dev->irq, hp100_interrupt, SA_SHIRQ, lp->id->name, dev)) {
- printk("%s: unable to get IRQ %d\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- } else if (request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, dev)) {
- printk("%s: unable to get IRQ %d\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- MOD_INC_USE_COUNT;
-
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- dev->interrupt = 0;
- dev->start = 1;
-
- lp->lan_type = hp100_sense_lan(dev);
- lp->mac1_mode = HP100_MAC1MODE3;
- lp->mac2_mode = HP100_MAC2MODE3;
-
- hp100_stop_interface(dev);
-
- hp100_hwinit(dev);
-
- hp100_start_interface(dev); /* sets mac modes, enables interrupts */
-
- return 0;
+ hp100_outw( 0x4204, TRACE );
+ printk("hp100: %s: open\n",dev->name);
+#endif
+
+ /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
+ if ( request_irq(dev->irq, hp100_interrupt,
+ lp->bus==HP100_BUS_PCI||lp->bus==HP100_BUS_EISA?SA_SHIRQ:SA_INTERRUPT,
+ lp->id->name, dev))
+ {
+ printk( "hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ lp->lan_type = hp100_sense_lan( dev );
+ lp->mac1_mode = HP100_MAC1MODE3;
+ lp->mac2_mode = HP100_MAC2MODE3;
+ memset( &lp->hash_bytes, 0x00, 8 );
+
+ hp100_stop_interface( dev );
+
+ hp100_hwinit( dev );
+
+ hp100_start_interface( dev ); /* sets mac modes, enables interrupts */
+
+ return 0;
}
-
+
/* The close function is called when the interface is to be brought down */
-static int hp100_close(struct device *dev)
+static int hp100_close( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4205, TRACE);
- printk("hp100:close\n");
+ hp100_outw( 0x4205, TRACE );
+ printk("hp100: %s: close\n", dev->name);
#endif
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */
+
+ hp100_stop_interface( dev );
+
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status=hp100_login_to_vg_hub( dev, FALSE );
- hp100_stop_interface(dev);
+ dev->tbusy = 1;
+ dev->start = 0;
- if (lp->lan_type == HP100_LAN_100)
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE);
+ free_irq( dev->irq, dev );
- dev->tbusy = 1;
- dev->start = 0;
+#ifdef HP100_DEBUG
+ printk( "hp100: %s: close LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) );
+#endif
- if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA))
- free_irq(dev->irq, dev);
- else
- free_irq(dev->irq, NULL);
- MOD_DEC_USE_COUNT;
- return 0;
+ MOD_DEC_USE_COUNT;
+ return 0;
}
-
+
/*
* Configure the PDL Rx rings and LAN
*/
-static void hp100_init_pdls(struct device *dev)
+static void hp100_init_pdls( struct device *dev )
{
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- hp100_ring_t *ringptr;
- u_int *pageptr;
- int i;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
+ u_int *pageptr;
+ int i;
#ifdef HP100_DEBUG_B
- int ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
#endif
#ifdef HP100_DEBUG_B
- hp100_outw(0x4206, TRACE);
- printk("hp100: init pdls\n");
-#endif
-
- if (0 == lp->page_vaddr_algn)
- printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n");
- else {
- /* pageptr shall point into the DMA accessible memory region */
- /* we use this pointer to status the upper limit of allocated */
- /* memory in the allocated page. */
- /* note: align the pointers to the pci cache line size */
- memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */
- pageptr = lp->page_vaddr_algn;
-
- lp->rxrcommit = 0;
- ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
-
- /* Initialise Rx Ring */
- for (i = MAX_RX_PDL - 1; i >= 0; i--) {
- lp->rxring[i].next = ringptr;
- ringptr = &(lp->rxring[i]);
- pageptr += hp100_init_rxpdl(ringptr, pageptr);
- }
-
- /* Initialise Tx Ring */
- lp->txrcommit = 0;
- ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
- for (i = MAX_TX_PDL - 1; i >= 0; i--) {
- lp->txring[i].next = ringptr;
- ringptr = &(lp->txring[i]);
- pageptr += hp100_init_txpdl(ringptr, pageptr);
- }
- }
+ hp100_outw( 0x4206, TRACE );
+ printk("hp100: %s: init pdls\n", dev->name);
+#endif
+
+ if(0==lp->page_vaddr_algn)
+ printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n",dev->name);
+ else
+ {
+ /* pageptr shall point into the DMA accessible memory region */
+ /* we use this pointer to status the upper limit of allocated */
+ /* memory in the allocated page. */
+ /* note: align the pointers to the pci cache line size */
+ memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */
+ pageptr=lp->page_vaddr_algn;
+
+ lp->rxrcommit =0;
+ ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]);
+
+ /* Initialise Rx Ring */
+ for (i=MAX_RX_PDL-1; i>=0; i--)
+ {
+ lp->rxring[i].next = ringptr;
+ ringptr=&(lp->rxring[i]);
+ pageptr+=hp100_init_rxpdl(dev, ringptr, pageptr);
+ }
+
+ /* Initialise Tx Ring */
+ lp->txrcommit = 0;
+ ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
+ for (i=MAX_TX_PDL-1; i>=0; i--)
+ {
+ lp->txring[i].next = ringptr;
+ ringptr=&(lp->txring[i]);
+ pageptr+=hp100_init_txpdl(dev, ringptr, pageptr);
+ }
+ }
}
-
+
/* These functions "format" the entries in the pdl structure */
/* They return how much memory the fragments need. */
-static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u32 * pdlptr)
+static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr )
{
- /* pdlptr is starting adress for this pdl */
+ /* pdlptr is starting adress for this pdl */
- if (0 != (((unsigned) pdlptr) & 0xf))
- printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr);
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned)pdlptr);
- ringptr->pdl = pdlptr + 1;
- ringptr->pdl_paddr = virt_to_bus(pdlptr + 1);
- ringptr->skb = (void *) NULL;
+ ringptr->pdl = pdlptr+1;
+ ringptr->pdl_paddr = virt_to_bus(pdlptr+1);
+ ringptr->skb = (void *) NULL;
- /*
- * Write address and length of first PDL Fragment (which is used for
- * storing the RX-Header
- * We use the 4 bytes _before_ the PDH in the pdl memory area to
- * store this information. (PDH is at offset 0x04)
- */
- /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
+ /*
+ * Write address and length of first PDL Fragment (which is used for
+ * storing the RX-Header
+ * We use the 4 bytes _before_ the PDH in the pdl memory area to
+ * store this information. (PDH is at offset 0x04)
+ */
+ /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
- *(pdlptr + 2) = (u_int) virt_to_bus(pdlptr); /* Address Frag 1 */
- *(pdlptr + 3) = 4; /* Length Frag 1 */
+ *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */
+ *(pdlptr+3) = 4; /* Length Frag 1 */
- return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4);
+ return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 );
}
-static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlptr)
+static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr )
{
- if (0 != (((unsigned) pdlptr) & 0xf))
- printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr);
-
- ringptr->pdl = pdlptr; /* +1; */
- ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */
- ringptr->skb = (void *) NULL;
-
- return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4);
+ if( 0!=( ((unsigned)pdlptr) & 0xf) )
+ printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned) pdlptr);
+
+ ringptr->pdl = pdlptr; /* +1; */
+ ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */
+ ringptr->skb = (void *) NULL;
+
+ return((((MAX_TX_FRAG*2+2)+3)/4)*4);
}
-
+
/*
* hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
* for possible odd word alignment rounding up to next dword and set PDL
@@ -1119,77 +1309,80 @@ static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlp
* Returns: 0 if unable to allocate skb_buff
* 1 if successful
*/
-int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev)
+int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev )
{
#ifdef HP100_DEBUG_B
- int ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
#endif
#ifdef HP100_DEBUG_BM
- u_int *p;
+ u_int *p;
#endif
#ifdef HP100_DEBUG_B
- hp100_outw(0x4207, TRACE);
- printk("hp100: build rx pdl\n");
-#endif
-
- /* Allocate skb buffer of maximum size */
- /* Note: This depends on the alloc_skb functions allocating more
- * space than requested, i.e. aligning to 16bytes */
-
- ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4);
-
- if (NULL != ringptr->skb) {
- /*
- * Reserve 2 bytes at the head of the buffer to land the IP header
- * on a long word boundary (According to the Network Driver section
- * in the Linux KHG, this should help to increase performance.)
- */
- skb_reserve(ringptr->skb, 2);
-
- ringptr->skb->dev = dev;
- ringptr->skb->data = (u_char *) skb_put(ringptr->skb, MAX_ETHER_SIZE);
-
- /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
- /* Note: 1st Fragment is used for the 4 byte packet status
- * (receive header). Its PDL entries are set up by init_rxpdl. So
- * here we only have to set up the PDL fragment entries for the data
- * part. Those 4 bytes will be stored in the DMA memory region
- * directly before the PDL.
- */
+ hp100_outw( 0x4207, TRACE );
+ printk("hp100: %s: build rx pdl\n", dev->name);
+#endif
+
+ /* Allocate skb buffer of maximum size */
+ /* Note: This depends on the alloc_skb functions allocating more
+ * space than requested, i.e. aligning to 16bytes */
+
+ ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 );
+
+ if(NULL!=ringptr->skb)
+ {
+ /*
+ * Reserve 2 bytes at the head of the buffer to land the IP header
+ * on a long word boundary (According to the Network Driver section
+ * in the Linux KHG, this should help to increase performance.)
+ */
+ skb_reserve(ringptr->skb, 2);
+
+ ringptr->skb->dev=dev;
+ ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE );
+
+ /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
+ /* Note: 1st Fragment is used for the 4 byte packet status
+ * (receive header). Its PDL entries are set up by init_rxpdl. So
+ * here we only have to set up the PDL fragment entries for the data
+ * part. Those 4 bytes will be stored in the DMA memory region
+ * directly before the PDL.
+ */
#ifdef HP100_DEBUG_BM
- printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
- (u_int) ringptr->pdl,
- ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4,
- (unsigned int) ringptr->skb->data);
+ printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
+ dev->name,
+ (u_int) ringptr->pdl,
+ ((MAX_ETHER_SIZE+2+3)/4)*4,
+ (unsigned int) ringptr->skb->data);
#endif
- ringptr->pdl[0] = 0x00020000; /* Write PDH */
- ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data));
- ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
-
+ ringptr->pdl[0] = 0x00020000; /* Write PDH */
+ ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data));
+ ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
+
#ifdef HP100_DEBUG_BM
- for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++)
- printk("Adr 0x%.8x = 0x%.8x\n", (u_int) p, (u_int) * p);
-#endif
- return (1);
- }
- /* else: */
- /* alloc_skb failed (no memory) -> still can receive the header
- * fragment into PDL memory. make PDL safe by clearing msgptr and
- * making the PDL only 1 fragment (i.e. the 4 byte packet status)
- */
+ for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++)
+ printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n",dev->name,(u_int) p,(u_int) *p );
+#endif
+ return(1);
+ }
+ /* else: */
+ /* alloc_skb failed (no memory) -> still can receive the header
+ * fragment into PDL memory. make PDL safe by clearing msgptr and
+ * making the PDL only 1 fragment (i.e. the 4 byte packet status)
+ */
#ifdef HP100_DEBUG_BM
- printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n",
- (u_int) ringptr->pdl);
+ printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n",
+ dev->name,
+ (u_int) ringptr->pdl);
#endif
- ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */
+ ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */
- return (0);
+ return(0);
}
-
+
/*
* hp100_rxfill - attempt to fill the Rx Ring will empty skb's
*
@@ -1200,246 +1393,279 @@ int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev)
* b. Put the physical address of the buffer into the PDL.
* c. Output physical address of PDL to adapter.
*/
-static void hp100_rxfill(struct device *dev)
+static void hp100_rxfill( struct device *dev )
{
- int ioaddr = dev->base_addr;
+ int ioaddr=dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- hp100_ring_t *ringptr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4208, TRACE);
- printk("hp100: rxfill\n");
-#endif
-
- hp100_page(PERFORMANCE);
-
- while (lp->rxrcommit < MAX_RX_PDL) {
- /*
- ** Attempt to get a buffer and build a Rx PDL.
- */
- ringptr = lp->rxrtail;
- if (0 == hp100_build_rx_pdl(ringptr, dev)) {
- return; /* None available, return */
- }
- /* Hand this PDL over to the card */
- /* Note: This needs performance page selected! */
+ hp100_outw( 0x4208, TRACE );
+ printk("hp100: %s: rxfill\n",dev->name);
+#endif
+
+ hp100_page( PERFORMANCE );
+
+ while (lp->rxrcommit < MAX_RX_PDL)
+ {
+ /*
+ ** Attempt to get a buffer and build a Rx PDL.
+ */
+ ringptr = lp->rxrtail;
+ if (0 == hp100_build_rx_pdl( ringptr, dev ))
+ {
+ return; /* None available, return */
+ }
+
+ /* Hand this PDL over to the card */
+ /* Note: This needs performance page selected! */
#ifdef HP100_DEBUG_BM
- printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
- lp->rxrcommit,
- (u_int) ringptr->pdl,
- (u_int) ringptr->pdl_paddr,
- (u_int) ringptr->pdl[3]);
-#endif
-
- hp100_outl((u32) ringptr->pdl_paddr, RX_PDA);
-
- lp->rxrcommit += 1;
- lp->rxrtail = ringptr->next;
- }
+ printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
+ dev->name,
+ lp->rxrcommit,
+ (u_int)ringptr->pdl,
+ (u_int)ringptr->pdl_paddr,
+ (u_int)ringptr->pdl[3]);
+#endif
+
+ hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA);
+
+ lp->rxrcommit += 1;
+ lp->rxrtail = ringptr->next;
+ }
}
-
+
/*
* BM_shutdown - shutdown bus mastering and leave chip in reset state
*/
-static void hp100_BM_shutdown(struct device *dev)
+static void hp100_BM_shutdown( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- unsigned long time;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ unsigned long time;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4209, TRACE);
- printk("hp100: bm shutdown\n");
-#endif
-
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */
-
- /* Ensure Interrupts are off */
- hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-
- /* Disable all MAC activity */
- hp100_page(MAC_CTRL);
- hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */
-
- /* If cascade MMU is not already in reset */
- if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) {
- /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
- * MMU pointers will not be reset out from underneath
- */
- hp100_page(MAC_CTRL);
- for (time = 0; time < 5000; time++) {
- if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) ==
- (HP100_TX_IDLE | HP100_RX_IDLE))
- break;
- }
-
- /* Shutdown algorithm depends on the generation of Cascade */
- if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */
- /* Disable Busmaster mode and wait for bit to go to zero. */
- hp100_page(HW_MAP);
- hp100_andb(~HP100_BM_MASTER, BM);
- /* 100 ms timeout */
- for (time = 0; time < 32000; time++) {
- if (0 == (hp100_inb(BM) & HP100_BM_MASTER))
- break;
- }
- } else { /* Shasta or Rainier Shutdown/Reset */
- /* To ensure all bus master inloading activity has ceased,
- * wait for no Rx PDAs or no Rx packets on card.
- */
- hp100_page(PERFORMANCE);
- /* 100 ms timeout */
- for (time = 0; time < 10000; time++) {
- /* RX_PDL: PDLs not executed. */
- /* RX_PKT_CNT: RX'd packets on card. */
- if ((hp100_inb(RX_PDL) == 0) &&
- (hp100_inb(RX_PKT_CNT) == 0))
- break;
- }
-
- if (time >= 10000)
- printk("hp100: BM shutdown error.\n");
-
- /* To ensure all bus master outloading activity has ceased,
- * wait until the Tx PDA count goes to zero or no more Tx space
- * available in the Tx region of the card.
- */
- /* 100 ms timeout */
- for (time = 0; time < 10000; time++) {
- if ((0 == hp100_inb(TX_PKT_CNT)) &&
- (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE)))
- break;
- }
-
- /* Disable Busmaster mode */
- hp100_page(HW_MAP);
- hp100_andb(~HP100_BM_MASTER, BM);
- } /* end of shutdown procedure for non-etr parts */
-
- hp100_cascade_reset(dev, TRUE);
- }
- hp100_page(PERFORMANCE);
- hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW);
- /* Busmaster mode should be shut down now. */
+ hp100_outw( 0x4209, TRACE );
+ printk("hp100: %s: bm shutdown\n",dev->name);
+#endif
+
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */
+
+ /* Ensure Interrupts are off */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW );
+
+ /* Disable all MAC activity */
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+
+ /* If cascade MMU is not already in reset */
+ if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) )
+ {
+ /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
+ * MMU pointers will not be reset out from underneath
+ */
+ hp100_page( MAC_CTRL );
+ for(time=0; time<5000; time++)
+ {
+ if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))==
+ (HP100_TX_IDLE|HP100_RX_IDLE) ) break;
+ }
+
+ /* Shutdown algorithm depends on the generation of Cascade */
+ if( lp->chip==HP100_CHIPID_LASSEN )
+ { /* ETR shutdown/reset */
+ /* Disable Busmaster mode and wait for bit to go to zero. */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ /* 100 ms timeout */
+ for(time=0; time<32000; time++)
+ {
+ if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break;
+ }
+ }
+ else
+ { /* Shasta or Rainier Shutdown/Reset */
+ /* To ensure all bus master inloading activity has ceased,
+ * wait for no Rx PDAs or no Rx packets on card.
+ */
+ hp100_page( PERFORMANCE );
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++)
+ {
+ /* RX_PDL: PDLs not executed. */
+ /* RX_PKT_CNT: RX'd packets on card. */
+ if ( (hp100_inb( RX_PDL ) == 0) &&
+ (hp100_inb( RX_PKT_CNT ) == 0) ) break;
+ }
+
+ if(time>=10000)
+ printk("hp100: %s: BM shutdown error.\n", dev->name);
+
+ /* To ensure all bus master outloading activity has ceased,
+ * wait until the Tx PDA count goes to zero or no more Tx space
+ * available in the Tx region of the card.
+ */
+ /* 100 ms timeout */
+ for(time=0; time<10000; time++) {
+ if ( (0 == hp100_inb( TX_PKT_CNT )) &&
+ (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break;
+ }
+
+ /* Disable Busmaster mode */
+ hp100_page(HW_MAP);
+ hp100_andb( ~HP100_BM_MASTER, BM );
+ } /* end of shutdown procedure for non-etr parts */
+
+ hp100_cascade_reset( dev, TRUE );
+ }
+ hp100_page( PERFORMANCE );
+ /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */
+ /* Busmaster mode should be shut down now. */
}
-
+
/*
* transmit functions
*/
/* tx function for busmaster mode */
-static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev)
+static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev )
{
- int i, ok_flag;
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- hp100_ring_t *ringptr;
+ unsigned long flags;
+ int i, ok_flag;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ringptr;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4210, TRACE);
- printk("hp100: start_xmit_bm\n");
-#endif
-
- /* Get Tx ring tail pointer */
- if (lp->txrtail->next == lp->txrhead) {
- /* No memory. */
+ hp100_outw( 0x4210, TRACE );
+ printk("hp100: %s: start_xmit_bm\n",dev->name);
+#endif
+
+ if ( skb==NULL )
+ {
+#ifndef LINUX_2_1
+ dev_tint( dev );
+#endif
+ return 0;
+ }
+
+ if ( skb->len <= 0 ) return 0;
+
+ /* Get Tx ring tail pointer */
+ if( lp->txrtail->next==lp->txrhead )
+ {
+ /* No memory. */
#ifdef HP100_DEBUG
- printk("hp100: start_xmit_bm: No TX PDL available.\n");
-#endif
- /* not waited long enough since last tx? */
- if (jiffies - dev->trans_start < HZ / 10)
- return -EAGAIN;
-
- if (lp->lan_type < 0) { /* no LAN type detected yet? */
- hp100_stop_interface(dev);
- if ((lp->lan_type = hp100_sense_lan(dev)) < 0) {
- printk("%s: no connection found - check wire\n", dev->name);
- hp100_start_interface(dev); /* 10Mb/s RX pkts maybe handled */
- return -EIO;
- }
- if (lp->lan_type == HP100_LAN_100)
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */
- hp100_start_interface(dev);
- }
- if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0)
- /* we have a 100Mb/s adapter but it isn't connected to hub */
- {
- printk("%s: login to 100Mb/s hub retry\n", dev->name);
- hp100_stop_interface(dev);
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE);
- hp100_start_interface(dev);
- } else {
- hp100_ints_off();
- i = hp100_sense_lan(dev);
- hp100_page(PERFORMANCE);
- hp100_ints_on();
- if (i == HP100_LAN_ERR)
- printk("%s: link down detected\n", dev->name);
- else if (lp->lan_type != i) { /* cable change! */
- /* it's very hard - all network setting must be changed!!! */
- printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);
- lp->lan_type = i;
- hp100_stop_interface(dev);
- if (lp->lan_type == HP100_LAN_100)
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE);
- hp100_start_interface(dev);
- } else {
- printk("%s: interface reset\n", dev->name);
- hp100_stop_interface(dev);
- hp100_start_interface(dev);
- }
- }
-
- dev->trans_start = jiffies;
- return -EAGAIN;
+ printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);
+#endif
+ /* not waited long enough since last tx? */
+ if ( jiffies - dev->trans_start < HZ ) return -EAGAIN;
+
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
+ {
+ hp100_stop_interface( dev );
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
+ {
+ printk( "hp100: %s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */
+ return -EIO;
+ }
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
+ hp100_start_interface( dev );
}
- /*
- * we have to turn int's off before modifying this, otherwise
- * a tx_pdl_cleanup could occur at the same time
- */
- cli();
- ringptr = lp->txrtail;
- lp->txrtail = ringptr->next;
-
- /* Check whether packet has minimal packet size */
- ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
- i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
-
- ringptr->skb = skb;
- ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */
- ringptr->pdl[1] = (u32) virt_to_bus(skb->data); /* 1st Frag: Adr. of data */
- if (lp->chip == HP100_CHIPID_SHASTA) {
- /* TODO:Could someone who has the EISA card please check if this works? */
- ringptr->pdl[2] = i;
- } else { /* Lassen */
- /* In the PDL, don't use the padded size but the real packet size: */
- ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */
+
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
+ {
+ printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name );
+ hp100_stop_interface( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ hp100_ints_off();
+ i = hp100_sense_lan( dev );
+ hp100_ints_on();
+ if ( i == HP100_LAN_ERR )
+ printk( "hp100: %s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "hp100: %s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
}
- /* Hand this PDL to the card. */
- hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */
-
- lp->txrcommit++;
- sti();
-
- /* Update statistics */
- lp->stats.tx_packets++;
+ dev->trans_start = jiffies;
+ return -EAGAIN;
+ }
+
+ /*
+ * we have to turn int's off before modifying this, otherwise
+ * a tx_pdl_cleanup could occur at the same time
+ */
+ save_flags( flags );
+ cli();
+ ringptr=lp->txrtail;
+ lp->txrtail=ringptr->next;
+
+ /* Check whether packet has minimal packet size */
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ ringptr->skb=skb;
+ ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */
+ ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */
+ if(lp->chip==HP100_CHIPID_SHASTA)
+ {
+ /* TODO:Could someone who has the EISA card please check if this works? */
+ ringptr->pdl[2]=i;
+ }
+ else /* Lassen */
+ {
+ /* In the PDL, don't use the padded size but the real packet size: */
+ ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */
+ }
+
+ /* Hand this PDL to the card. */
+ hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */
+
+ lp->txrcommit++;
+ restore_flags( flags );
+
+ /* Update statistics */
+ lp->stats.tx_packets++;
#ifdef LINUX_2_1
- lp->stats.tx_bytes += skb->len;
+ lp->stats.tx_bytes += skb->len;
#endif
- dev->trans_start = jiffies;
-
- return 0;
+ dev->trans_start = jiffies;
+
+ return 0;
}
-
+
/* clean_txring checks if packets have been sent by the card by reading
* the TX_PDL register from the performance page and comparing it to the
* number of commited packets. It then frees the skb's of the packets that
@@ -1447,168 +1673,209 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev)
*
* Needs the PERFORMANCE page selected.
*/
-static void hp100_clean_txring(struct device *dev)
+static void hp100_clean_txring( struct device *dev )
{
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- int ioaddr = dev->base_addr;
- int donecount;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int donecount;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4211, TRACE);
- printk("hp100: clean txring\n");
+ hp100_outw( 0x4211, TRACE );
+ printk("hp100: %s: clean txring\n", dev->name);
#endif
- /* How many PDLs have been transmitted? */
- donecount = (lp->txrcommit) - hp100_inb(TX_PDL);
+ /* How many PDLs have been transmitted? */
+ donecount=(lp->txrcommit)-hp100_inb(TX_PDL);
#ifdef HP100_DEBUG
- if (donecount > MAX_TX_PDL)
- printk("hp100: Warning: More PDLs transmitted than commited to card???\n");
+ if(donecount>MAX_TX_PDL)
+ printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n",dev->name);
#endif
- for (; 0 != donecount; donecount--) {
+ for( ; 0!=donecount; donecount-- )
+ {
#ifdef HP100_DEBUG_BM
- printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
- (u_int) lp->txrhead->skb->data,
- lp->txrcommit,
- hp100_inb(TX_PDL),
- donecount);
-#endif
- dev_kfree_skb(lp->txrhead->skb);
- lp->txrhead->skb = (void *) NULL;
- lp->txrhead = lp->txrhead->next;
- lp->txrcommit--;
- }
+ printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
+ dev->name,
+ (u_int) lp->txrhead->skb->data,
+ lp->txrcommit,
+ hp100_inb(TX_PDL),
+ donecount);
+#endif
+#ifdef LINUX_2_1
+ dev_kfree_skb( lp->txrhead->skb );
+#else
+ dev_kfree_skb( lp->txrhead->skb, FREE_WRITE );
+#endif
+ lp->txrhead->skb=(void *)NULL;
+ lp->txrhead=lp->txrhead->next;
+ lp->txrcommit--;
+ }
}
-
+
/* tx function for slave modes */
-static int hp100_start_xmit(struct sk_buff *skb, struct device *dev)
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
{
- int i, ok_flag;
- int ioaddr = dev->base_addr;
- u_short val;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ int i, ok_flag;
+ int ioaddr = dev->base_addr;
+ u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4212, TRACE);
- printk("hp100: start_xmit\n");
-#endif
-
- if (lp->lan_type < 0) { /* no LAN type detected yet? */
- hp100_stop_interface(dev);
- if ((lp->lan_type = hp100_sense_lan(dev)) < 0) {
- printk("%s: no connection found - check wire\n", dev->name);
- hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */
- return -EIO;
- }
- if (lp->lan_type == HP100_LAN_100)
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */
- hp100_start_interface(dev);
- }
- /* If there is not enough free memory on the card... */
- i = hp100_inl(TX_MEM_FREE) & 0x7fffffff;
- if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) {
+ hp100_outw( 0x4212, TRACE );
+ printk("hp100: %s: start_xmit\n", dev->name);
+#endif
+
+ if ( skb==NULL )
+ {
+#ifndef LINUX_2_1
+ dev_tint( dev );
+#endif
+ return 0;
+ }
+
+ if ( skb->len <= 0 ) return 0;
+
+ if ( lp->lan_type < 0 ) /* no LAN type detected yet? */
+ {
+ hp100_stop_interface( dev );
+ if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
+ {
+ printk( "hp100: %s: no connection found - check wire\n", dev->name );
+ hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */
+ return -EIO;
+ }
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */
+ hp100_start_interface( dev );
+ }
+
+ /* If there is not enough free memory on the card... */
+ i=hp100_inl(TX_MEM_FREE)&0x7fffffff;
+ if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) )
+ {
#ifdef HP100_DEBUG
- printk("hp100_start_xmit: tx free mem = 0x%x\n", i);
+ printk( "hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i );
#endif
- /* not waited long enough since last failed tx try? */
- if (jiffies - dev->trans_start < HZ / 2) {
+ /* not waited long enough since last failed tx try? */
+ if ( jiffies - dev->trans_start < HZ )
+ {
#ifdef HP100_DEBUG
- printk("hp100: trans_start timing problem\n");
+ printk("hp100: %s: trans_start timing problem\n", dev->name);
#endif
- return -EAGAIN;
- }
- if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0)
- /* we have a 100Mb/s adapter but it isn't connected to hub */
- {
- printk("%s: login to 100Mb/s hub retry\n", dev->name);
- hp100_stop_interface(dev);
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE);
- hp100_start_interface(dev);
- } else {
- hp100_ints_off();
- i = hp100_sense_lan(dev);
- hp100_page(PERFORMANCE);
- hp100_ints_on();
- if (i == HP100_LAN_ERR)
- printk("%s: link down detected\n", dev->name);
- else if (lp->lan_type != i) { /* cable change! */
- /* it's very hard - all network setting must be changed!!! */
- printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);
- lp->lan_type = i;
- hp100_stop_interface(dev);
- if (lp->lan_type == HP100_LAN_100)
- lp->hub_status = hp100_login_to_vg_hub(dev, FALSE);
- hp100_start_interface(dev);
- } else {
- printk("%s: interface reset\n", dev->name);
- hp100_stop_interface(dev);
- hp100_start_interface(dev);
- udelay(1000);
- }
- }
- dev->trans_start = jiffies;
- return -EAGAIN;
+ return -EAGAIN;
}
- for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) {
+ if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 )
+ /* we have a 100Mb/s adapter but it isn't connected to hub */
+ {
+ printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name );
+ hp100_stop_interface( dev );
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ hp100_ints_off();
+ i = hp100_sense_lan( dev );
+ hp100_ints_on();
+ if ( i == HP100_LAN_ERR )
+ printk( "hp100: %s: link down detected\n", dev->name );
+ else
+ if ( lp->lan_type != i ) /* cable change! */
+ {
+ /* it's very hard - all network setting must be changed!!! */
+ printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name );
+ lp->lan_type = i;
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ }
+ else
+ {
+ printk( "hp100: %s: interface reset\n", dev->name );
+ hp100_stop_interface( dev );
+ if ( lp->lan_type == HP100_LAN_100 )
+ lp->hub_status = hp100_login_to_vg_hub( dev, FALSE );
+ hp100_start_interface( dev );
+ udelay(1000);
+ }
+ }
+ dev->trans_start = jiffies;
+ return -EAGAIN;
+ }
+
+ for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+ {
#ifdef HP100_DEBUG_TX
- printk("hp100_start_xmit: busy\n");
-#endif
- }
-
- hp100_ints_off();
- val = hp100_inw(IRQ_STATUS);
- /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
- * when the current packet being transmitted on the wire is completed. */
- hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS);
+ printk( "hp100: %s: start_xmit: busy\n", dev->name );
+#endif
+ }
+
+ hp100_ints_off();
+ val = hp100_inw( IRQ_STATUS );
+ /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
+ * when the current packet being transmitted on the wire is completed. */
+ hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS );
#ifdef HP100_DEBUG_TX
- printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", val, hp100_inw(IRQ_MASK), (int) skb->len);
-#endif
-
- ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
- i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
-
- hp100_outw(i, DATA32); /* tell card the total packet length */
- hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */
-
- if (lp->mode == 2) { /* memory mapped */
- if (lp->mem_ptr_virt) { /* high pci memory was remapped */
- /* Note: The J2585B needs alignment to 32bits here! */
- memcpy(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3);
- if (!ok_flag)
- memset(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len);
- } else {
- memcpy_toio(lp->mem_ptr_phys, skb->data, skb->len);
- if (!ok_flag)
- memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len);
- }
- } else { /* programmed i/o */
- outsl(ioaddr + HP100_REG_DATA32, skb->data, (skb->len + 3) >> 2);
- if (!ok_flag)
- for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4)
- hp100_outl(0, DATA32);
+ printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",dev->name,val,hp100_inw(IRQ_MASK),(int)skb->len );
+#endif
+
+ ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
+ i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
+
+ hp100_outw( i, DATA32 ); /* tell card the total packet length */
+ hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */
+
+ if ( lp->mode==2 ) /* memory mapped */
+ {
+ if ( lp->mem_ptr_virt ) /* high pci memory was remapped */
+ {
+ /* Note: The J2585B needs alignment to 32bits here! */
+ memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 );
+ if ( !ok_flag )
+ memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len );
}
-
- hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */
-
- lp->stats.tx_packets++;
+ else
+ {
+ /* Note: The J2585B needs alignment to 32bits here! */
+ memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 );
+ if ( !ok_flag )
+ memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len );
+ }
+ }
+ else /* programmed i/o */
+ {
+ outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 );
+ if ( !ok_flag )
+ for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+ hp100_outl( 0, DATA32 );
+ }
+
+ hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+
+ lp->stats.tx_packets++;
#ifdef LINUX_2_1
- lp->stats.tx_bytes += skb->len;
+ lp->stats.tx_bytes += skb->len;
#endif
- dev->trans_start = jiffies;
- hp100_ints_on();
-
- dev_kfree_skb(skb);
-
+ dev->trans_start=jiffies;
+ hp100_ints_on();
+
+#ifdef LINUX_2_1
+ dev_kfree_skb( skb );
+#else
+ dev_kfree_skb( skb, FREE_WRITE );
+#endif
+
#ifdef HP100_DEBUG_TX
- printk("hp100_start_xmit: end\n");
+ printk( "hp100: %s: start_xmit: end\n", dev->name );
#endif
-
- return 0;
+
+ return 0;
}
-
+
/*
* Receive Function (Non-Busmaster mode)
* Called when an "Receive Packet" interrupt occurs, i.e. the receive
@@ -1618,981 +1885,1163 @@ static int hp100_start_xmit(struct sk_buff *skb, struct device *dev)
* and netif_rx.
*/
-static void hp100_rx(struct device *dev)
+static void hp100_rx( struct device *dev )
{
- int packets, pkt_len;
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- u_int header;
- struct sk_buff *skb;
+ int packets, pkt_len;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ u_int header;
+ struct sk_buff *skb;
#ifdef DEBUG_B
- hp100_outw(0x4213, TRACE);
- printk("hp100: rx\n");
+ hp100_outw( 0x4213, TRACE );
+ printk("hp100: %s: rx\n", dev->name);
#endif
- /* First get indication of received lan packet */
- /* RX_PKT_CND indicates the number of packets which have been fully */
- /* received onto the card but have not been fully transfered of the card */
- packets = hp100_inb(RX_PKT_CNT);
+ /* First get indication of received lan packet */
+ /* RX_PKT_CND indicates the number of packets which have been fully */
+ /* received onto the card but have not been fully transfered of the card */
+ packets = hp100_inb( RX_PKT_CNT );
#ifdef HP100_DEBUG_RX
- if (packets > 1)
- printk("hp100_rx: waiting packets = %d\n", packets);
+ if ( packets > 1 )
+ printk( "hp100: %s: rx: waiting packets = %d\n", dev->name,packets );
#endif
- while (packets-- > 0) {
- /* If ADV_NXT_PKT is still set, we have to wait until the card has */
- /* really advanced to the next packet. */
- for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT);
- pkt_len++) {
+ while ( packets-- > 0 )
+ {
+ /* If ADV_NXT_PKT is still set, we have to wait until the card has */
+ /* really advanced to the next packet. */
+ for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT);
+ pkt_len++ )
+ {
#ifdef HP100_DEBUG_RX
- printk("hp100_rx: busy, remaining packets = %d\n", packets);
-#endif
- }
-
- /* First we get the header, which contains information about the */
- /* actual length of the received packet. */
- if (lp->mode == 2) { /* memory mapped mode */
- if (lp->mem_ptr_virt) /* if memory was remapped */
- header = *(__u32 *) lp->mem_ptr_virt;
- else
- header = readl(lp->mem_ptr_phys);
- } else /* programmed i/o */
- header = hp100_inl(DATA32);
-
- pkt_len = header & HP100_PKT_LEN_MASK;
+ printk( "hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets );
+#endif
+ }
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+ if( lp->mode==2 ) /* memory mapped mode */
+ {
+ if ( lp->mem_ptr_virt ) /* if memory was remapped */
+ header = *(__u32 *)lp->mem_ptr_virt;
+ else
+ header = readl( lp->mem_ptr_phys );
+ }
+ else /* programmed i/o */
+ header = hp100_inl( DATA32 );
+
+ pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3;
#ifdef HP100_DEBUG_RX
- printk("hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
- header & HP100_PKT_LEN_MASK, (header >> 16) & 0xfff8,
- (header >> 16) & 7);
-#endif
-
- /* Now we allocate the skb and transfer the data into it. */
- /* NOTE! This (and the skb_put() below) depends on the skb-functions
- * allocating more than asked (notably, aligning the request up to
- * the next 16-byte length).
- */
- skb = dev_alloc_skb(pkt_len);
- if (skb == NULL) { /* Not enough memory->drop packet */
+ printk( "hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
+ dev->name,
+ header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8,
+ (header>>16)&7);
+#endif
+
+ /* Now we allocate the skb and transfer the data into it. */
+ skb = dev_alloc_skb( pkt_len );
+ if ( skb == NULL ) /* Not enough memory->drop packet */
+ {
#ifdef HP100_DEBUG
- printk("hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len);
+ printk( "hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", dev->name, pkt_len );
#endif
- lp->stats.rx_dropped++;
- } else { /* skb successfully allocated */
- u_char *ptr;
-
- skb->dev = dev;
-
- /* ptr to start of the sk_buff data area */
- ptr = (u_char *) skb_put(skb, pkt_len);
-
- /* Now transfer the data from the card into that area */
- if (lp->mode == 2) {
- if (lp->mem_ptr_virt)
- memcpy(ptr, lp->mem_ptr_virt, (pkt_len + 3) & ~3);
- /* Note alignment to 32bit transfers */
- else
- memcpy_fromio(ptr, lp->mem_ptr_phys, (pkt_len + 3) & ~3);
- } else /* io mapped */
- insl(ioaddr + HP100_REG_DATA32, ptr, (pkt_len + 3) >> 2);
-
- skb->protocol = eth_type_trans(skb, dev);
-
- netif_rx(skb);
- lp->stats.rx_packets++;
+ lp->stats.rx_dropped++;
+ }
+ else /* skb successfully allocated */
+ {
+ u_char *ptr;
+
+ skb->dev = dev;
+
+ /* ptr to start of the sk_buff data area */
+ ptr = (u_char *)skb_put( skb, pkt_len );
+
+ /* Now transfer the data from the card into that area */
+ if ( lp->mode==2 )
+ {
+ if ( lp->mem_ptr_virt )
+ memcpy( ptr, lp->mem_ptr_virt, pkt_len );
+ /* Note alignment to 32bit transfers */
+ else
+ memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len );
+ }
+ else /* io mapped */
+ insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 );
+
+ skb->protocol = eth_type_trans( skb, dev );
+
+ netif_rx( skb );
+ lp->stats.rx_packets++;
#ifdef LINUX_2_1
- lp->stats.rx_bytes += skb->len;
+ lp->stats.rx_bytes += skb->len;
#endif
-
+
#ifdef HP100_DEBUG_RX
- printk("rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
- ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11]);
+ printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ dev->name,
+ ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
+ ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
#endif
- }
-
- /* Indicate the card that we have got the packet */
- hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW);
-
- switch (header & 0x00070000) {
- case (HP100_MULTI_ADDR_HASH << 16):
- case (HP100_MULTI_ADDR_NO_HASH << 16):
- lp->stats.multicast++;
- break;
- }
- } /* end of while(there are packets) loop */
+ }
+
+ /* Indicate the card that we have got the packet */
+ hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+
+ switch ( header & 0x00070000 ) {
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
+ }
+ } /* end of while(there are packets) loop */
#ifdef HP100_DEBUG_RX
- printk("hp100_rx: end\n");
+ printk( "hp100_rx: %s: end\n", dev->name );
#endif
}
-
+
/*
* Receive Function for Busmaster Mode
*/
-static void hp100_rx_bm(struct device *dev)
+static void hp100_rx_bm( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- hp100_ring_t *ptr;
- u_int header;
- int pkt_len;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ hp100_ring_t *ptr;
+ u_int header;
+ int pkt_len;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4214, TRACE);
- printk("hp100: rx_bm\n");
+ hp100_outw( 0x4214, TRACE );
+ printk("hp100: %s: rx_bm\n", dev->name);
#endif
#ifdef HP100_DEBUG
- if (0 == lp->rxrcommit) {
- printk("hp100: rx_bm called although no PDLs were committed to adapter?\n");
- return;
- } else
- /* RX_PKT_CNT states how many PDLs are currently formatted and available to
- * the cards BM engine */
- if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) {
- printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit);
- return;
- }
-#endif
-
- while ((lp->rxrcommit > hp100_inb(RX_PDL))) {
- /*
- * The packet was received into the pdl pointed to by lp->rxrhead (
- * the oldest pdl in the ring
- */
-
- /* First we get the header, which contains information about the */
- /* actual length of the received packet. */
-
- ptr = lp->rxrhead;
-
- header = *(ptr->pdl - 1);
- pkt_len = (header & HP100_PKT_LEN_MASK);
+ if(0==lp->rxrcommit)
+ {
+ printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name);
+ return;
+ }
+ else
+
+ /* RX_PKT_CNT states how many PDLs are currently formatted and available to
+ * the cards BM engine */
+ if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit)
+ {
+ printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", dev->name, hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit);
+ return;
+ }
+#endif
+
+ while( (lp->rxrcommit > hp100_inb(RX_PDL)) )
+ {
+ /*
+ * The packet was received into the pdl pointed to by lp->rxrhead (
+ * the oldest pdl in the ring
+ */
+
+ /* First we get the header, which contains information about the */
+ /* actual length of the received packet. */
+
+ ptr=lp->rxrhead;
+
+ header = *(ptr->pdl-1);
+ pkt_len = (header & HP100_PKT_LEN_MASK);
#ifdef HP100_DEBUG_BM
- printk("hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
- (u_int) (ptr->pdl - 1), (u_int) header,
- pkt_len,
- (header >> 16) & 0xfff8,
- (header >> 16) & 7);
- printk("hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
- hp100_inb(RX_PDL),
- hp100_inb(TX_PDL),
- hp100_inb(RX_PKT_CNT),
- (u_int) * (ptr->pdl),
- (u_int) * (ptr->pdl + 3),
- (u_int) * (ptr->pdl + 4));
-#endif
-
- if ((pkt_len >= MIN_ETHER_SIZE) &&
- (pkt_len <= MAX_ETHER_SIZE)) {
- if (ptr->skb == NULL) {
- printk("hp100: rx_bm: skb null\n");
- /* can happen if we only allocated room for the pdh due to memory shortage. */
- lp->stats.rx_dropped++;
- } else {
- skb_trim(ptr->skb, pkt_len); /* Shorten it */
- ptr->skb->protocol = eth_type_trans(ptr->skb, dev);
-
- netif_rx(ptr->skb); /* Up and away... */
-
- lp->stats.rx_packets++;
+ printk( "hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
+ dev->name,
+ (u_int) (ptr->pdl-1),(u_int) header,
+ pkt_len,
+ (header>>16)&0xfff8,
+ (header>>16)&7);
+ printk( "hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
+ dev->name,
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PDL ),
+ hp100_inb( RX_PKT_CNT ),
+ (u_int) *(ptr->pdl),
+ (u_int) *(ptr->pdl+3),
+ (u_int) *(ptr->pdl+4));
+#endif
+
+ if( (pkt_len>=MIN_ETHER_SIZE) &&
+ (pkt_len<=MAX_ETHER_SIZE) )
+ {
+ if(ptr->skb==NULL)
+ {
+ printk("hp100: %s: rx_bm: skb null\n", dev->name);
+ /* can happen if we only allocated room for the pdh due to memory shortage. */
+ lp->stats.rx_dropped++;
+ }
+ else
+ {
+ skb_trim( ptr->skb, pkt_len ); /* Shorten it */
+ ptr->skb->protocol = eth_type_trans( ptr->skb, dev );
+
+ netif_rx( ptr->skb ); /* Up and away... */
+
+ lp->stats.rx_packets++;
#ifdef LINUX_2_1
- lp->stats.rx_bytes += ptr->skb->len;
-#endif
- }
-
- switch (header & 0x00070000) {
- case (HP100_MULTI_ADDR_HASH << 16):
- case (HP100_MULTI_ADDR_NO_HASH << 16):
- lp->stats.multicast++;
- break;
- }
- } else {
+ lp->stats.rx_bytes += ptr->skb->len;
+#endif
+ }
+
+ switch ( header & 0x00070000 ) {
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp->stats.multicast++; break;
+ }
+ }
+ else
+ {
#ifdef HP100_DEBUG
- printk("hp100: rx_bm: Received bad packet (length=%d)\n", pkt_len);
+ printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n",dev->name,pkt_len);
#endif
- if (ptr->skb != NULL)
- dev_kfree_skb(ptr->skb);
- lp->stats.rx_errors++;
- }
-
- lp->rxrhead = lp->rxrhead->next;
-
- /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
- if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) {
- /* No space for skb, header can still be received. */
-#ifdef HP100_DEBUG
- printk("hp100: rx_bm: No space for new PDL.\n");
+ if(ptr->skb!=NULL)
+#ifdef LINUX_2_1
+ dev_kfree_skb( ptr->skb );
+#else
+ dev_kfree_skb( ptr->skb, FREE_READ );
#endif
- return;
- } else { /* successfully allocated new PDL - put it in ringlist at tail. */
- hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA);
- lp->rxrtail = lp->rxrtail->next;
- }
+ lp->stats.rx_errors++;
+ }
+
+ lp->rxrhead=lp->rxrhead->next;
+ /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
+ if (0 == hp100_build_rx_pdl( lp->rxrtail, dev ))
+ {
+ /* No space for skb, header can still be received. */
+#ifdef HP100_DEBUG
+ printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name);
+#endif
+ return;
+ }
+ else
+ { /* successfully allocated new PDL - put it in ringlist at tail. */
+ hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA);
+ lp->rxrtail=lp->rxrtail->next;
}
+
+ }
}
-
+
/*
* statistics
*/
-static hp100_stats_t *hp100_get_stats(struct device *dev)
+static hp100_stats_t *hp100_get_stats( struct device *dev )
{
- int ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4215, TRACE);
+ hp100_outw( 0x4215, TRACE );
#endif
- hp100_ints_off();
- hp100_update_stats(dev);
- hp100_ints_on();
- return &((struct hp100_private *) dev->priv)->stats;
+ hp100_ints_off();
+ hp100_update_stats( dev );
+ hp100_ints_on();
+ return &((struct hp100_private *)dev->priv)->stats;
}
-static void hp100_update_stats(struct device *dev)
+static void hp100_update_stats( struct device *dev )
{
- int ioaddr = dev->base_addr;
- u_short val;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4216, TRACE);
- printk("hp100: update-stats\n");
-#endif
-
- /* Note: Statistics counters clear when read. */
- hp100_page(MAC_CTRL);
- val = hp100_inw(DROPPED) & 0x0fff;
- lp->stats.rx_errors += val;
- lp->stats.rx_over_errors += val;
- val = hp100_inb(CRC);
- lp->stats.rx_errors += val;
- lp->stats.rx_crc_errors += val;
- val = hp100_inb(ABORT);
- lp->stats.tx_errors += val;
- lp->stats.tx_aborted_errors += val;
- hp100_page(PERFORMANCE);
+ hp100_outw( 0x4216, TRACE );
+ printk("hp100: %s: update-stats\n", dev->name);
+#endif
+
+ /* Note: Statistics counters clear when read. */
+ hp100_page( MAC_CTRL );
+ val = hp100_inw( DROPPED ) & 0x0fff;
+ lp->stats.rx_errors += val;
+ lp->stats.rx_over_errors += val;
+ val = hp100_inb( CRC );
+ lp->stats.rx_errors += val;
+ lp->stats.rx_crc_errors += val;
+ val = hp100_inb( ABORT );
+ lp->stats.tx_errors += val;
+ lp->stats.tx_aborted_errors += val;
+ hp100_page( PERFORMANCE );
}
-static void hp100_clear_stats(int ioaddr)
+static void hp100_misc_interrupt( struct device *dev )
{
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+
#ifdef HP100_DEBUG_B
- hp100_outw(0x4217, TRACE);
- printk("hp100: clear_stats\n");
+ hp100_outw( 0x4216, TRACE );
+ printk("hp100: %s: misc_interrupt\n", dev->name);
#endif
- cli();
- hp100_page(MAC_CTRL); /* get all statistics bytes */
- hp100_inw(DROPPED);
- hp100_inb(CRC);
- hp100_inb(ABORT);
- hp100_page(PERFORMANCE);
- sti();
+ /* Note: Statistics counters clear when read. */
+ lp->stats.rx_errors++;
+ lp->stats.tx_errors++;
+}
+
+static void hp100_clear_stats( int ioaddr )
+{
+ unsigned long flags;
+
+#ifdef HP100_DEBUG_B
+ hp100_outw( 0x4217, TRACE );
+ printk("hp100: %s: clear_stats\n", dev->name);
+#endif
+
+ save_flags( flags );
+ cli();
+ hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ hp100_inw( DROPPED );
+ hp100_inb( CRC );
+ hp100_inb( ABORT );
+ hp100_page( PERFORMANCE );
+ restore_flags( flags );
}
-
+
/*
* multicast setup
*/
/*
* Set or clear the multicast filter for this adapter.
- * TODO: Currently when in multicast mode, card accepts all multicast packets
- * for all MC addresses. Should better use the list on the card.
*/
-
-static void hp100_set_multicast_list(struct device *dev)
+
+static void hp100_set_multicast_list( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ unsigned long flags;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4218, TRACE);
- printk("hp100: set_mc_list\n");
-#endif
-
- cli();
- hp100_ints_off();
- hp100_page(MAC_CTRL);
- hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */
-
- if (dev->flags & IFF_PROMISC) {
- lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */
- lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */
- } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
- lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */
- lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */
- } else {
- lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */
- lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
- }
-
- if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) ||
- (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) {
- hp100_outb(lp->mac2_mode, MAC_CFG_2);
- hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */
- hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */
-
- if (lp->lan_type == HP100_LAN_100) {
+ hp100_outw( 0x4218, TRACE );
+ printk("hp100: %s: set_mc_list\n", dev->name);
+#endif
+
+ save_flags( flags );
+ cli();
+ hp100_ints_off();
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+
+ if ( dev->flags & IFF_PROMISC )
+ {
+ lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */
+ lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */
+ memset( &lp->hash_bytes, 0xff, 8 );
+ }
+ else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) )
+ {
+ lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */
+ lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */
+#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */
+ if ( dev -> flags & IFF_ALLMULTI )
+ {
+ /* set hash filter to receive all multicast packets */
+ memset( &lp->hash_bytes, 0xff, 8 );
+ }
+ else
+ {
+ int i, j, idx;
+ u_char *addrs;
+ struct dev_mc_list *dmi;
+
+ memset( &lp->hash_bytes, 0x00, 8 );
+#ifdef HP100_DEBUG
+ printk("hp100: %s: computing hash filter - mc_count = %i\n", dev -> name, dev -> mc_count );
+#endif
+ for ( i = 0, dmi = dev -> mc_list; i < dev -> mc_count; i++, dmi = dmi -> next )
+ {
+ addrs = dmi -> dmi_addr;
+ if ( ( *addrs & 0x01 ) == 0x01 ) /* multicast address? */
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ",
+ dev -> name,
+ addrs[ 0 ], addrs[ 1 ], addrs[ 2 ],
+ addrs[ 3 ], addrs[ 4 ], addrs[ 5 ] );
+#endif
+ for ( j = idx = 0; j < 6; j++ )
+ {
+ idx ^= *addrs++ & 0x3f;
+ printk( ":%02x:", idx );
+ }
#ifdef HP100_DEBUG
- printk("hp100: 100VG MAC settings have changed - relogin.\n");
+ printk("idx = %i\n", idx );
#endif
- lp->hub_status = hp100_login_to_vg_hub(dev, TRUE); /* force a relogin to the hub */
- }
- }
- hp100_page(MAC_CTRL);
- hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
- HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */
-
- hp100_page(PERFORMANCE);
- hp100_ints_on();
- sti();
+ lp->hash_bytes[ idx >> 3 ] |= ( 1 << ( idx & 7 ) );
+ }
+ }
+ }
+#else
+ memset( &lp->hash_bytes, 0xff, 8 );
+#endif
+ }
+ else
+ {
+ lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */
+ lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
+ memset( &lp->hash_bytes, 0x00, 8 );
+ }
+
+ if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) ||
+ ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) )
+ {
+ int i;
+
+ hp100_outb( lp->mac2_mode, MAC_CFG_2 );
+ hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */
+ hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */
+
+ hp100_page( MAC_ADDRESS );
+ for ( i = 0; i < 8; i++ )
+ hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i );
+#ifdef HP100_DEBUG
+ printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, lp->mac1_mode, lp->mac2_mode,
+ lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ],
+ lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ],
+ lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ],
+ lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ]
+ );
+#endif
+
+ if(lp->lan_type==HP100_LAN_100)
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name);
+#endif
+ lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */
+ }
+ }
+ else
+ {
+ int i;
+ u_char old_hash_bytes[ 8 ];
+
+ hp100_page( MAC_ADDRESS );
+ for ( i = 0; i < 8; i++ )
+ old_hash_bytes[ i ] = hp100_inb( HASH_BYTE0 + i );
+ if ( memcmp( old_hash_bytes, &lp->hash_bytes, 8 ) )
+ {
+ for ( i = 0; i < 8; i++ )
+ hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i );
+#ifdef HP100_DEBUG
+ printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name,
+ lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ],
+ lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ],
+ lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ],
+ lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ]
+ );
+#endif
+
+ if(lp->lan_type==HP100_LAN_100)
+ {
+#ifdef HP100_DEBUG
+ printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name);
+#endif
+ lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */
+ }
+ }
+ }
+
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
+ HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+
+ hp100_page( PERFORMANCE );
+ hp100_ints_on();
+ restore_flags( flags );
}
-
+
/*
* hardware interrupt handling
*/
-static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs )
{
- struct device *dev = dev_id;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ struct device *dev = (struct device *)dev_id;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
- int ioaddr;
- u_int val;
+ int ioaddr;
+ u_int val;
- if (dev == NULL)
- return;
- ioaddr = dev->base_addr;
+ if ( dev == NULL ) return;
+ ioaddr = dev->base_addr;
- if (dev->interrupt)
- printk("%s: re-entering the interrupt handler\n", dev->name);
- hp100_ints_off();
- dev->interrupt = 1; /* mark that we are inside the handler */
+ if ( dev->interrupt )
+ printk( "hp100: %s: re-entering the interrupt handler\n", dev->name );
+ hp100_ints_off();
+ dev->interrupt = 1; /* mark that we are inside the handler */
#ifdef HP100_DEBUG_B
- hp100_outw(0x4219, TRACE);
+ hp100_outw( 0x4219, TRACE );
#endif
- /* hp100_page( PERFORMANCE ); */
- val = hp100_inw(IRQ_STATUS);
+ /* hp100_page( PERFORMANCE ); */
+ val = hp100_inw( IRQ_STATUS );
#ifdef HP100_DEBUG_IRQ
- printk("hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
- lp->mode,
- (u_int) val,
- hp100_inb(RX_PKT_CNT),
- hp100_inb(RX_PDL),
- hp100_inb(TX_PKT_CNT),
- hp100_inb(TX_PDL)
- );
-#endif
-
- if (val == 0) { /* might be a shared interrupt */
- dev->interrupt = 0;
- hp100_ints_on();
- return;
+ printk( "hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
+ dev->name,
+ lp->mode,
+ (u_int)val,
+ hp100_inb( RX_PKT_CNT ),
+ hp100_inb( RX_PDL ),
+ hp100_inb( TX_PKT_CNT ),
+ hp100_inb( TX_PDL )
+ );
+#endif
+
+ if(val==0) /* might be a shared interrupt */
+ {
+ dev->interrupt=0;
+ hp100_ints_on();
+ return;
+ }
+ /* We're only interested in those interrupts we really enabled. */
+ /* val &= hp100_inw( IRQ_MASK ); */
+
+ /*
+ * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
+ * is considered executed whenever the RX_PDL data structure is no longer
+ * needed.
+ */
+ if ( val & HP100_RX_PDL_FILL_COMPL )
+ {
+ if(lp->mode==1)
+ hp100_rx_bm( dev );
+ else
+ {
+ printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name);
}
- /* We're only interested in those interrupts we really enabled. */
- /* val &= hp100_inw( IRQ_MASK ); */
-
- /*
- * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
- * is considered executed whenever the RX_PDL data structure is no longer
- * needed.
- */
- if (val & HP100_RX_PDL_FILL_COMPL) {
- if (lp->mode == 1)
- hp100_rx_bm(dev);
- else
- printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n");
+ }
+
+ /*
+ * The RX_PACKET interrupt is set, when the receive packet counter is
+ * non zero. We use this interrupt for receiving in slave mode. In
+ * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
+ * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
+ * we somehow have missed a rx_pdl_fill_compl interrupt.
+ */
+
+ if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */
+ {
+ if(lp->mode!=1) /* non busmaster */
+ hp100_rx( dev );
+ else if ( !(val & HP100_RX_PDL_FILL_COMPL ))
+ {
+ /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */
+ hp100_rx_bm( dev );
}
- /*
- * The RX_PACKET interrupt is set, when the receive packet counter is
- * non zero. We use this interrupt for receiving in slave mode. In
- * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
- * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
- * we somehow have missed a rx_pdl_fill_compl interrupt.
- */
-
- if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */
- if (lp->mode != 1) /* non busmaster */
- hp100_rx(dev);
- else if (!(val & HP100_RX_PDL_FILL_COMPL)) {
- /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */
- hp100_rx_bm(dev);
- }
- }
- /*
- * Ack. that we have noticed the interrupt and thereby allow next one.
- * Note that this is now done after the slave rx function, since first
- * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
- * on the J2573.
- */
- hp100_outw(val, IRQ_STATUS);
-
- /*
- * RX_ERROR is set when a packet is dropped due to no memory resources on
- * the card or when a RCV_ERR occurs.
- * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
- * only in the 802.3 MAC and happens when 16 collisions occur during a TX
- */
- if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) {
+ }
+
+ /*
+ * Ack. that we have noticed the interrupt and thereby allow next one.
+ * Note that this is now done after the slave rx function, since first
+ * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
+ * on the J2573.
+ */
+ hp100_outw( val, IRQ_STATUS );
+
+ /*
+ * RX_ERROR is set when a packet is dropped due to no memory resources on
+ * the card or when a RCV_ERR occurs.
+ * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
+ * only in the 802.3 MAC and happens when 16 collisions occur during a TX
+ */
+ if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+ {
#ifdef HP100_DEBUG_IRQ
- printk("hp100: TX/RX Error IRQ\n");
+ printk("hp100: %s: TX/RX Error IRQ\n", dev->name);
#endif
- hp100_update_stats(dev);
- if (lp->mode == 1) {
- hp100_rxfill(dev);
- hp100_clean_txring(dev);
- }
+ hp100_update_stats( dev );
+ if(lp->mode==1)
+ {
+ hp100_rxfill( dev );
+ hp100_clean_txring( dev );
}
- /*
- * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
- */
- if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO)))
- hp100_rxfill(dev);
-
- /*
- * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
- * is completed
- */
- if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE)))
- hp100_clean_txring(dev);
-
- /*
- * MISC_ERROR is set when either the LAN link goes down or a detected
- * bus error occurs.
- */
- if (val & HP100_MISC_ERROR) { /* New for J2585B */
- printk("hp100: Misc. Error Interrupt - Check cabling.\n");
- if (lp->mode == 1) {
- hp100_clean_txring(dev);
- hp100_rxfill(dev);
- }
+ }
+
+ /*
+ * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
+ */
+ if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) )
+ hp100_rxfill( dev );
+
+ /*
+ * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
+ * is completed
+ */
+ if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) )
+ hp100_clean_txring( dev );
+
+ /*
+ * MISC_ERROR is set when either the LAN link goes down or a detected
+ * bus error occurs.
+ */
+ if ( val & HP100_MISC_ERROR ) /* New for J2585B */
+ {
+#ifdef HP100_DEBUG_IRQ
+ printk("hp100: %s: Misc. Error Interrupt - Check cabling.\n", dev->name);
+#endif
+ if(lp->mode==1)
+ {
+ hp100_clean_txring( dev );
+ hp100_rxfill( dev );
}
- dev->interrupt = 0;
- hp100_ints_on();
+ hp100_misc_interrupt( dev );
+ }
+
+ dev->interrupt = 0;
+ hp100_ints_on();
}
-
+
/*
* some misc functions
*/
-static void hp100_start_interface(struct device *dev)
+static void hp100_start_interface( struct device *dev )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ unsigned long flags;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4220, TRACE);
- printk("hp100: hp100_start_interface %s\n", dev->name);
-#endif
-
- cli();
-
- /* Ensure the adapter does not want to request an interrupt when */
- /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */
- hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
- /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
- hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW);
-
- if (lp->mode == 1) {
- /* Make sure BM bit is set... */
- hp100_page(HW_MAP);
- hp100_orb(HP100_BM_MASTER, BM);
- hp100_rxfill(dev);
- } else if (lp->mode == 2) {
- /* Enable memory mapping. Note: Don't do this when busmaster. */
- hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW);
- }
- hp100_page(PERFORMANCE);
- hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */
- hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
-
- /* enable a few interrupts: */
- if (lp->mode == 1) { /* busmaster mode */
- hp100_outw(HP100_RX_PDL_FILL_COMPL |
- HP100_RX_PDA_ZERO |
- HP100_RX_ERROR |
- /* HP100_RX_PACKET | */
- /* HP100_RX_EARLY_INT | */ HP100_SET_HB |
- /* HP100_TX_PDA_ZERO | */
- HP100_TX_COMPLETE |
- /* HP100_MISC_ERROR | */
- HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK);
- } else {
- hp100_outw(HP100_RX_PACKET |
- HP100_RX_ERROR | HP100_SET_HB |
- HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK);
- }
-
- /* Enable MAC Tx and RX, set MAC modes, ... */
- /* Note: This function also turns on the interrupts. */
- hp100_set_multicast_list(dev);
+ hp100_outw( 0x4220, TRACE );
+ printk("hp100: %s: hp100_start_interface\n",dev->name);
+#endif
+
+ save_flags( flags );
+ cli();
+
+ /* Ensure the adapter does not want to request an interrupt when */
+ /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */
+ hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW);
+ /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
+ hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
+
+ if(lp->mode==1)
+ {
+ /* Make sure BM bit is set... */
+ hp100_page(HW_MAP);
+ hp100_orb( HP100_BM_MASTER, BM );
+ hp100_rxfill( dev );
+ }
+ else if(lp->mode==2)
+ {
+ /* Enable memory mapping. Note: Don't do this when busmaster. */
+ hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW );
+ }
+
+ hp100_page(PERFORMANCE);
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */
+
+ /* enable a few interrupts: */
+ if(lp->mode==1) /* busmaster mode */
+ {
+ hp100_outw( HP100_RX_PDL_FILL_COMPL |
+ HP100_RX_PDA_ZERO |
+ HP100_RX_ERROR |
+ /* HP100_RX_PACKET | */
+ /* HP100_RX_EARLY_INT | */ HP100_SET_HB |
+ /* HP100_TX_PDA_ZERO | */
+ HP100_TX_COMPLETE |
+ /* HP100_MISC_ERROR | */
+ HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK );
+ }
+ else
+ {
+ hp100_outw( HP100_RX_PACKET |
+ HP100_RX_ERROR | HP100_SET_HB |
+ HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK );
+ }
+
+ /* Enable MAC Tx and RX, set MAC modes, ... */
+ hp100_set_multicast_list( dev );
+
+ restore_flags( flags );
}
-
-static void hp100_stop_interface(struct device *dev)
+
+static void hp100_stop_interface( struct device *dev )
{
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- int ioaddr = dev->base_addr;
- u_int val;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u_int val;
#ifdef HP100_DEBUG_B
- printk("hp100: hp100_stop_interface %s\n", dev->name);
- hp100_outw(0x4221, TRACE);
-#endif
-
- if (lp->mode == 1)
- hp100_BM_shutdown(dev);
- else {
- /* Note: MMAP_DIS will be reenabled by start_interface */
- hp100_outw(HP100_INT_EN | HP100_RESET_LB |
- HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW);
- val = hp100_inw(OPTION_LSW);
-
- hp100_page(MAC_CTRL);
- hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);
-
- if (!(val & HP100_HW_RST))
- return; /* If reset, imm. return ... */
- /* ... else: busy wait until idle */
- for (val = 0; val < 6000; val++)
- if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) ==
- (HP100_TX_IDLE | HP100_RX_IDLE)) {
- hp100_page(PERFORMANCE);
- return;
- }
- printk("%s: hp100_stop_interface - timeout\n", dev->name);
- hp100_page(PERFORMANCE);
- }
+ printk("hp100: %s: hp100_stop_interface\n",dev->name);
+ hp100_outw( 0x4221, TRACE );
+#endif
+
+ if (lp->mode==1)
+ hp100_BM_shutdown( dev );
+ else
+ {
+ /* Note: MMAP_DIS will be reenabled by start_interface */
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB |
+ HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW );
+ val = hp100_inw( OPTION_LSW );
+
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+
+ if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */
+ /* ... else: busy wait until idle */
+ for ( val = 0; val < 6000; val++ )
+ if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+ (HP100_TX_IDLE | HP100_RX_IDLE) )
+ {
+ hp100_page(PERFORMANCE);
+ return;
+ }
+ printk( "hp100: %s: hp100_stop_interface - timeout\n", dev->name );
+ hp100_page(PERFORMANCE);
+ }
}
-
-static void hp100_load_eeprom(struct device *dev)
+
+static void hp100_load_eeprom( struct device *dev, u_short probe_ioaddr )
{
- int i;
- int ioaddr = dev->base_addr;
+ int i;
+ int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4222, TRACE);
+ hp100_outw( 0x4222, TRACE );
#endif
- hp100_page(EEPROM_CTRL);
- hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL);
- hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL);
- for (i = 0; i < 10000; i++)
- if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD))
- return;
- printk("%s: hp100_load_eeprom - timeout\n", dev->name);
+ hp100_page( EEPROM_CTRL );
+ hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
+ hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
+ for ( i = 0; i < 10000; i++ )
+ if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+ printk( "hp100: %s: hp100_load_eeprom - timeout\n", dev->name );
}
-
+
/* Sense connection status.
* return values: LAN_10 - Connected to 10Mbit/s network
* LAN_100 - Connected to 100Mbit/s network
* LAN_ERR - not connected or 100Mbit/s Hub down
*/
-static int hp100_sense_lan(struct device *dev)
+static int hp100_sense_lan( struct device *dev )
{
- int ioaddr = dev->base_addr;
- u_short val_VG, val_10;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
+ int ioaddr = dev->base_addr;
+ u_short val_VG, val_10;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4223, TRACE);
-#endif
-
- hp100_page(MAC_CTRL);
- /* Enable Auto Selection */
- /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */
- /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */
- /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */
- /* Now we have to wait a while... */
- /* for(i=0; i<5000; i++) */
- /* { */
- val_10 = hp100_inb(10_LAN_CFG_1);
- val_VG = hp100_inb(VG_LAN_CFG_1);
- /* } */
+ hp100_outw( 0x4223, TRACE );
+#endif
+
+ hp100_page( MAC_CTRL );
+ val_10 = hp100_inb( 10_LAN_CFG_1 );
+ val_VG = hp100_inb( VG_LAN_CFG_1 );
+ hp100_page( PERFORMANCE );
#ifdef HP100_DEBUG
- printk("hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10);
-#endif
- if (val_10 & HP100_LINK_BEAT_ST)
- return HP100_LAN_10;
- if ((lp->id->id == 0x02019F022) ||
- (lp->id->id == 0x01042103c) ||
- (lp->id->id == 0x01040103c)) {
- hp100_page(PERFORMANCE);
- return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */
- }
- /* for ( i = 0; i < 2500; i++ ) */
- /* { */
- val_VG = hp100_inb(VG_LAN_CFG_1);
- hp100_page(PERFORMANCE);
-
- if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */
- return HP100_LAN_100;
- /* } */
- return HP100_LAN_ERR;
+ printk( "hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", dev->name, val_VG, val_10 );
+#endif
+
+ if ( val_10 & HP100_LINK_BEAT_ST ) /* 10Mb connection is active */
+ return HP100_LAN_10;
+
+ if ( val_10 & HP100_AUI_ST ) /* have we BNC or AUI onboard? */
+ {
+ val_10 |= HP100_AUI_SEL | HP100_LOW_TH;
+ hp100_page( MAC_CTRL );
+ hp100_outb( val_10, 10_LAN_CFG_1 );
+ hp100_page( PERFORMANCE );
+ return HP100_LAN_10;
+ }
+
+ if ( (lp->id->id == 0x02019F022) ||
+ (lp->id->id == 0x01042103c) ||
+ (lp->id->id == 0x01040103c) )
+ return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */
+
+ if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */
+ return HP100_LAN_100;
+ return HP100_LAN_ERR;
}
-
-static int hp100_down_vg_link(struct device *dev)
+
+static int hp100_down_vg_link( struct device *dev )
{
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- int ioaddr = dev->base_addr;
- unsigned long time;
- long savelan, newlan;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned long time;
+ long savelan, newlan;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4224, TRACE);
- printk("hp100: down_vg_link\n");
+ hp100_outw( 0x4224, TRACE );
+ printk("hp100: %s: down_vg_link\n", dev->name);
#endif
- hp100_page(MAC_CTRL);
- time = jiffies + (HZ / 4);
- do {
- if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
- break;
- } while (time > jiffies);
+ hp100_page( MAC_CTRL );
+ time=jiffies+(HZ/4);
+ do{
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while (time>jiffies);
- if (jiffies >= time) /* no signal->no logout */
- return 0;
+ if ( jiffies >= time ) /* no signal->no logout */
+ return 0;
- /* Drop the VG Link by clearing the link up cmd and load addr. */
+ /* Drop the VG Link by clearing the link up cmd and load addr.*/
- hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1);
- hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1);
+ hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1);
+ hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1);
- /* Conditionally stall for >250ms on Link-Up Status (to go down) */
- time = jiffies + (HZ / 2);
- do {
- if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
- break;
- } while (time > jiffies);
+ /* Conditionally stall for >250ms on Link-Up Status (to go down) */
+ time=jiffies+(HZ/2);
+ do{
+ if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break;
+ } while(time>jiffies);
#ifdef HP100_DEBUG
- if (jiffies >= time)
- printk("hp100_down_vg_link: Link does not go down?\n");
-#endif
-
- /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
- /* logout under traffic (even though all the status bits are cleared), */
- /* do this workaround to get the Rev 1 MAC in its idle state */
- if (lp->chip == HP100_CHIPID_LASSEN) {
- /* Reset VG MAC to insure it leaves the logoff state even if */
- /* the Hub is still emitting tones */
- hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
- udelay(1500); /* wait for >1ms */
- hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */
- udelay(1500);
- }
- /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
- /* to get the VG mac to full reset. This is not req.d with later chips */
- /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
- /* selected again! This will be left to the connect hub function to */
- /* perform if desired. */
- if (lp->chip == HP100_CHIPID_LASSEN) {
- /* Have to write to 10 and 100VG control registers simultaneously */
- savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */
- newlan &= ~(HP100_VG_SEL << 16);
- newlan |= (HP100_DOT3_MAC) << 8;
- hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */
- hp100_outl(newlan, 10_LAN_CFG_1);
-
- /* Conditionally stall for 5sec on VG selected. */
- time = jiffies + (HZ * 5);
- do {
- if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST))
- break;
- } while (time > jiffies);
-
- hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
- hp100_outl(savelan, 10_LAN_CFG_1);
- }
- time = jiffies + (3 * HZ); /* Timeout 3s */
- do {
- if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0)
- break;
- } while (time > jiffies);
-
- if (time <= jiffies) {
+ if (jiffies>=time)
+ printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name);
+#endif
+
+ /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
+ /* logout under traffic (even though all the status bits are cleared), */
+ /* do this workaround to get the Rev 1 MAC in its idle state */
+ if ( lp->chip==HP100_CHIPID_LASSEN )
+ {
+ /* Reset VG MAC to insure it leaves the logoff state even if */
+ /* the Hub is still emitting tones */
+ hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
+ udelay(1500); /* wait for >1ms */
+ hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */
+ udelay(1500);
+ }
+
+ /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
+ /* to get the VG mac to full reset. This is not req.d with later chips */
+ /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
+ /* selected again! This will be left to the connect hub function to */
+ /* perform if desired. */
+ if (lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Have to write to 10 and 100VG control registers simultaneously */
+ savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */
+ newlan &= ~(HP100_VG_SEL<<16);
+ newlan |= (HP100_DOT3_MAC)<<8;
+ hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */
+ hp100_outl(newlan, 10_LAN_CFG_1);
+
+ /* Conditionally stall for 5sec on VG selected. */
+ time=jiffies+(HZ*5);
+ do{
+ if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break;
+ } while(time>jiffies);
+
+ hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
+ hp100_outl(savelan, 10_LAN_CFG_1);
+ }
+
+ time=jiffies+(3*HZ); /* Timeout 3s */
+ do {
+ if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break;
+ } while (time>jiffies);
+
+ if(time<=jiffies)
+ {
#ifdef HP100_DEBUG
- printk("hp100_down_vg_link: timeout\n");
-#endif
- return -EIO;
- }
- time = jiffies + (2 * HZ); /* This seems to take a while.... */
- do {
- } while (time > jiffies);
-
- return 0;
+ printk( "hp100: %s: down_vg_link: timeout\n", dev->name );
+#endif
+ return -EIO;
+ }
+
+ time=jiffies+(2*HZ); /* This seems to take a while.... */
+ do {} while (time>jiffies);
+
+ return 0;
}
-
-static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin)
+
+static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- u_short val = 0;
- unsigned long time;
- int startst;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ u_short val=0;
+ unsigned long time;
+ int startst;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4225, TRACE);
- printk("hp100: login_to_vg_hub\n");
-#endif
-
- /* Initiate a login sequence iff VG MAC is enabled and either Load Address
- * bit is zero or the force relogin flag is set (e.g. due to MAC address or
- * promiscuous mode change)
- */
- hp100_page(MAC_CTRL);
- startst = hp100_inb(VG_LAN_CFG_1);
- if ((force_relogin == TRUE) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) {
+ hp100_outw( 0x4225, TRACE );
+ printk("hp100: %s: login_to_vg_hub\n", dev->name);
+#endif
+
+ /* Initiate a login sequence iff VG MAC is enabled and either Load Address
+ * bit is zero or the force relogin flag is set (e.g. due to MAC address or
+ * promiscuous mode change)
+ */
+ hp100_page( MAC_CTRL );
+ startst=hp100_inb( VG_LAN_CFG_1 );
+ if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST))
+ {
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: Start training\n");
+ printk("hp100: %s: Start training\n", dev->name);
#endif
- /* Ensure VG Reset bit is 1 (i.e., do not reset) */
- hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1);
+ /* Ensure VG Reset bit is 1 (i.e., do not reset)*/
+ hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 );
- /* If Lassen AND auto-select-mode AND VG tones were sensed on */
- /* entry then temporarily put them into force 100Mbit mode */
- if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST))
- hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2);
-
- /* Drop the VG link by zeroing Link Up Command and Load Address */
- hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1);
+ /* If Lassen AND auto-select-mode AND VG tones were sensed on */
+ /* entry then temporarily put them into force 100Mbit mode */
+ if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) )
+ hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 );
+
+ /* Drop the VG link by zeroing Link Up Command and Load Address */
+ hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1);
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: Bring down the link\n");
-#endif
-
- /* Wait for link to drop */
- time = jiffies + (HZ / 10);
- do {
- if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
- break;
- } while (time > jiffies);
-
- /* Start an addressed training and optionally request promiscuous port */
- if ((dev->flags) & IFF_PROMISC) {
- hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2);
- if (lp->chip == HP100_CHIPID_LASSEN)
- hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST);
- } else {
- hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2);
- /* For ETR parts we need to reset the prom. bit in the training
- * register, otherwise promiscious mode won't be disabled.
- */
- if (lp->chip == HP100_CHIPID_LASSEN) {
- hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST);
- }
- }
-
- /* With ETR parts, frame format request bits can be set. */
- if (lp->chip == HP100_CHIPID_LASSEN)
- hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
-
- hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1);
+ printk("hp100: %s: Bring down the link\n", dev->name);
+#endif
- /* Note: Next wait could be omitted for Hood and earlier chips under */
- /* certain circumstances */
- /* TODO: check if hood/earlier and skip wait. */
+ /* Wait for link to drop */
+ time = jiffies + (HZ/10);
+ do {
+ if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break;
+ } while (time>jiffies);
- /* Wait for either short timeout for VG tones or long for login */
- /* Wait for the card hardware to signalise link cable status ok... */
- hp100_page(MAC_CTRL);
- time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */
- do {
- if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
- break;
- } while (jiffies < time);
+ /* Start an addressed training and optionally request promiscuous port */
+ if ( (dev->flags) & IFF_PROMISC )
+ {
+ hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ else
+ {
+ hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2);
+ /* For ETR parts we need to reset the prom. bit in the training
+ * register, otherwise promiscious mode won't be disabled.
+ */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST );
+ }
+ }
- if (jiffies >= time) {
+ /* With ETR parts, frame format request bits can be set. */
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
+
+ hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1);
+
+ /* Note: Next wait could be omitted for Hood and earlier chips under */
+ /* certain circumstances */
+ /* TODO: check if hood/earlier and skip wait. */
+
+ /* Wait for either short timeout for VG tones or long for login */
+ /* Wait for the card hardware to signalise link cable status ok... */
+ hp100_page( MAC_CTRL );
+ time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */
+ do {
+ if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
+ } while ( jiffies < time );
+
+ if ( jiffies >= time )
+ {
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: Link cable status not ok? Training aborted.\n");
-#endif
- } else {
+ printk( "hp100: %s: Link cable status not ok? Training aborted.\n", dev->name );
+#endif
+ }
+ else
+ {
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: HUB tones detected. Trying to train.\n");
+ printk( "hp100: %s: HUB tones detected. Trying to train.\n", dev->name);
#endif
- time = jiffies + (2 * HZ); /* again a timeout */
- do {
- val = hp100_inb(VG_LAN_CFG_1);
- if ((val & (HP100_LINK_UP_ST))) {
+ time = jiffies + ( 2*HZ ); /* again a timeout */
+ do {
+ val = hp100_inb( VG_LAN_CFG_1 );
+ if ( (val & ( HP100_LINK_UP_ST )) )
+ {
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: Passed training.\n");
+ printk( "hp100: %s: Passed training.\n", dev->name);
#endif
- break;
- }
- } while (time > jiffies);
- }
-
- /* If LINK_UP_ST is set, then we are logged into the hub. */
- if ((jiffies <= time) && (val & HP100_LINK_UP_ST)) {
+ break;
+ }
+ } while ( time > jiffies );
+ }
+
+ /* If LINK_UP_ST is set, then we are logged into the hub. */
+ if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) )
+ {
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: Successfully logged into the HUB.\n");
- if (lp->chip == HP100_CHIPID_LASSEN) {
- val = hp100_inw(TRAIN_ALLOW);
- printk("hp100: Card supports 100VG MAC Version \"%s\" ",
- (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre");
- printk("Driver will use MAC Version \"%s\"\n",
- (val & HP100_HUB_MACVER) ? "802.12" : "Pre");
- printk("hp100: Frame format is %s.\n", (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3");
- }
-#endif
- } else {
- /* If LINK_UP_ST is not set, login was not successful */
- printk("hp100/%s: Problem logging into the HUB.\n", dev->name);
- if (lp->chip == HP100_CHIPID_LASSEN) {
- /* Check allowed Register to find out why there is a problem. */
- val = hp100_inw(TRAIN_ALLOW); /* wont work on non-ETR card */
+ printk( "hp100: %s: Successfully logged into the HUB.\n", dev->name);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ val = hp100_inw(TRAIN_ALLOW);
+ printk( "hp100: %s: Card supports 100VG MAC Version \"%s\" ",
+ dev->name,(hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre");
+ printk( "Driver will use MAC Version \"%s\"\n",
+ ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" );
+ printk( "hp100: %s: Frame format is %s.\n",dev->name,(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3");
+ }
+#endif
+ }
+ else
+ {
+ /* If LINK_UP_ST is not set, login was not successful */
+ printk("hp100: %s: Problem logging into the HUB.\n",dev->name);
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Check allowed Register to find out why there is a problem. */
+ val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */
#ifdef HP100_DEBUG_TRAINING
- printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val);
-#endif
- if (val & HP100_MALLOW_ACCDENIED)
- printk("hp100: HUB access denied.\n");
- if (val & HP100_MALLOW_CONFIGURE)
- printk("hp100: MAC Configuration is incompatible with the Network.\n");
- if (val & HP100_MALLOW_DUPADDR)
- printk("hp100: Duplicate MAC Address on the Network.\n");
- }
- }
-
- /* If we have put the chip into forced 100 Mbit mode earlier, go back */
- /* to auto-select mode */
-
- if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) {
- hp100_page(MAC_CTRL);
- hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2);
- }
- val = hp100_inb(VG_LAN_CFG_1);
-
- /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
- hp100_page(PERFORMANCE);
- hp100_outw(HP100_MISC_ERROR, IRQ_STATUS);
-
- if (val & HP100_LINK_UP_ST)
- return (0); /* login was ok */
- else {
- printk("hp100: Training failed.\n");
- hp100_down_vg_link(dev);
- return -EIO;
- }
- }
- /* no forced relogin & already link there->no training. */
- return -EIO;
+ printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val);
+#endif
+ if ( val & HP100_MALLOW_ACCDENIED )
+ printk("hp100: %s: HUB access denied.\n", dev->name);
+ if ( val & HP100_MALLOW_CONFIGURE )
+ printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name);
+ if ( val & HP100_MALLOW_DUPADDR )
+ printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name);
+ }
+ }
+
+ /* If we have put the chip into forced 100 Mbit mode earlier, go back */
+ /* to auto-select mode */
+
+ if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) )
+ {
+ hp100_page( MAC_CTRL );
+ hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 );
+ }
+
+ val=hp100_inb(VG_LAN_CFG_1);
+
+ /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
+ hp100_page(PERFORMANCE);
+ hp100_outw( HP100_MISC_ERROR, IRQ_STATUS);
+
+ if (val&HP100_LINK_UP_ST)
+ return(0); /* login was ok */
+ else
+ {
+ printk("hp100: %s: Training failed.\n", dev->name);
+ hp100_down_vg_link( dev );
+ return -EIO;
+ }
+ }
+ /* no forced relogin & already link there->no training. */
+ return -EIO;
}
-
-static void hp100_cascade_reset(struct device *dev, u_short enable)
+
+static void hp100_cascade_reset( struct device *dev, u_short enable )
{
- int ioaddr = dev->base_addr;
- struct hp100_private *lp = (struct hp100_private *) dev->priv;
- int i;
+ int ioaddr = dev->base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev->priv;
+ int i;
#ifdef HP100_DEBUG_B
- hp100_outw(0x4226, TRACE);
- printk("hp100: cascade_reset\n");
-#endif
-
- if (enable == TRUE) {
- hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW);
- if (lp->chip == HP100_CHIPID_LASSEN) {
- /* Lassen requires a PCI transmit fifo reset */
- hp100_page(HW_MAP);
- hp100_andb(~HP100_PCI_RESET, PCICTRL2);
- hp100_orb(HP100_PCI_RESET, PCICTRL2);
- /* Wait for min. 300 ns */
- /* we cant use jiffies here, because it may be */
- /* that we have disabled the timer... */
- for (i = 0; i < 0xffff; i++);
- hp100_andb(~HP100_PCI_RESET, PCICTRL2);
- hp100_page(PERFORMANCE);
- }
- } else { /* bring out of reset */
- hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW);
- for (i = 0; i < 0xffff; i++);
- hp100_page(PERFORMANCE);
- }
+ hp100_outw( 0x4226, TRACE );
+ printk("hp100: %s: cascade_reset\n", dev->name);
+#endif
+
+ if (enable==TRUE)
+ {
+ hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW );
+ if(lp->chip==HP100_CHIPID_LASSEN)
+ {
+ /* Lassen requires a PCI transmit fifo reset */
+ hp100_page( HW_MAP );
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_orb( HP100_PCI_RESET, PCICTRL2 );
+ /* Wait for min. 300 ns */
+ /* we cant use jiffies here, because it may be */
+ /* that we have disabled the timer... */
+ for (i=0; i<0xffff; i++);
+ hp100_andb( ~HP100_PCI_RESET, PCICTRL2 );
+ hp100_page( PERFORMANCE );
+ }
+ }
+ else
+ { /* bring out of reset */
+ hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW);
+ for (i=0; i<0xffff; i++ );
+ hp100_page(PERFORMANCE);
+ }
}
-#ifdef HP100_DEBUG
-void hp100_RegisterDump(struct device *dev)
+#ifdef HP100_DEBUG
+void hp100_RegisterDump( struct device *dev )
{
- int ioaddr = dev->base_addr;
- int Page;
- int Register;
-
- /* Dump common registers */
- printk("hp100: Cascade Register Dump\n");
- printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID));
- printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING));
- printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW));
- printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW));
-
- /* Dump paged registers */
- for (Page = 0; Page < 8; Page++) {
- /* Dump registers */
- printk("page: 0x%.2x\n", Page);
- outw(Page, ioaddr + 0x02);
- for (Register = 0x8; Register < 0x22; Register += 2) {
- /* Display Register contents except data port */
- if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) {
- printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register));
- }
- }
+ int ioaddr=dev->base_addr;
+ int Page;
+ int Register;
+
+ /* Dump common registers */
+ printk("hp100: %s: Cascade Register Dump\n", dev->name);
+ printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID));
+ printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING));
+ printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW));
+ printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW));
+
+ /* Dump paged registers */
+ for (Page = 0; Page < 8; Page++)
+ {
+ /* Dump registers */
+ printk("page: 0x%.2x\n",Page);
+ outw( Page, ioaddr+0x02);
+ for (Register = 0x8; Register < 0x22; Register += 2)
+ {
+ /* Display Register contents except data port */
+ if (((Register != 0x10) && (Register != 0x12)) || (Page > 0))
+ {
+ printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register));
+ }
}
- hp100_page(PERFORMANCE);
+ }
+ hp100_page(PERFORMANCE);
}
#endif
-
+
/*
* module section
*/
-
+
#ifdef MODULE
/* Parameters set by insmod */
-int hp100_port[5] =
-{0, -1, -1, -1, -1};
+int hp100_port[5] = { 0, -1, -1, -1, -1 };
#ifdef LINUX_2_1
MODULE_PARM(hp100_port, "1-5i");
#endif
#ifdef LINUX_2_1
-char hp100_name[5][IFNAMSIZ] =
-{"", "", "", "", ""};
+char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
#else
-static char devname[5][IFNAMSIZ] =
-{"", "", "", "", ""};
-static char *hp100_name[5] =
-{devname[0], devname[1],
- devname[2], devname[3],
- devname[4]};
+static char devname[5][IFNAMSIZ] = { "", "", "", "", "" };
+static char *hp100_name[5] = { devname[0], devname[1],
+ devname[2], devname[3],
+ devname[4] };
#endif
/* List of devices */
-static struct device *hp100_devlist[5] =
-{NULL, NULL, NULL, NULL, NULL};
+static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL };
/*
* Note: if you have more than five 100vg cards in your pc, feel free to
@@ -2606,61 +3055,64 @@ static struct device *hp100_devlist[5] =
* option hp100 hp100_port=0x280 hp100_name=eth239
*/
-int init_module(void)
+int init_module( void )
{
- int i;
- int ret = 0;
-
- if (hp100_port == 0 && !EISA_bus && !pcibios_present())
- printk("HP100: You should not use auto-probing with insmod!\n");
-
- /* Loop on all possible base addresses */
- i = -1;
- while ((hp100_port[++i] != -1) && (i < 5)) {
- /* Create device and set basics args */
- hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL);
- memset(hp100_devlist[i], 0x00, sizeof(struct device));
- hp100_devlist[i]->name = hp100_name[i];
- hp100_devlist[i]->base_addr = hp100_port[i];
- hp100_devlist[i]->init = &hp100_probe;
-
- /* Try to create the device */
- if (register_netdev(hp100_devlist[i]) != 0) {
- /* DeAllocate everything */
- /* Note: if dev->priv is mallocated, there is no way to fail */
- kfree_s(hp100_devlist[i], sizeof(struct device));
- hp100_devlist[i] = (struct device *) NULL;
- ret = -EIO;
- }
- } /* Loop over all devices */
+ int i, cards;
+
+ if (hp100_port == 0 && !EISA_bus && !pcibios_present())
+ printk("hp100: You should not use auto-probing with insmod!\n");
+
+ /* Loop on all possible base addresses */
+ i = -1; cards = 0;
+ while((hp100_port[++i] != -1) && (i < 5))
+ {
+ /* Create device and set basics args */
+ hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL);
+ memset(hp100_devlist[i], 0x00, sizeof(struct device));
+ hp100_devlist[i]->name = hp100_name[i];
+ hp100_devlist[i]->base_addr = hp100_port[i];
+ hp100_devlist[i]->init = &hp100_probe;
+
+ /* Try to create the device */
+ if(register_netdev(hp100_devlist[i]) != 0)
+ {
+ /* DeAllocate everything */
+ /* Note: if dev->priv is mallocated, there is no way to fail */
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ }
+ else
+ cards++;
+ } /* Loop over all devices */
- return ret;
+ return cards > 0 ? 0 : -ENODEV;
}
-void cleanup_module(void)
+void cleanup_module( void )
{
- int i;
-
- /* TODO: Check if all skb's are released/freed. */
- for (i = 0; i < 5; i++)
- if (hp100_devlist[i] != (struct device *) NULL) {
- unregister_netdev(hp100_devlist[i]);
- release_region(hp100_devlist[i]->base_addr, HP100_REGION_SIZE);
- if (((struct hp100_private *) hp100_devlist[i]->priv)->mode == 1) /* busmaster */
- kfree_s(((struct hp100_private *) hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE + 0x0f);
- if (((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt)
- iounmap(((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt);
- kfree_s(hp100_devlist[i]->priv, sizeof(struct hp100_private));
- hp100_devlist[i]->priv = NULL;
- kfree_s(hp100_devlist[i], sizeof(struct device));
- hp100_devlist[i] = (struct device *) NULL;
- }
+ int i;
+
+ /* TODO: Check if all skb's are released/freed. */
+ for(i = 0; i < 5; i++)
+ if(hp100_devlist[i] != (struct device *) NULL)
+ {
+ unregister_netdev( hp100_devlist[i] );
+ release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE );
+ if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */
+ kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f);
+ if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt )
+ iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt );
+ kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) );
+ hp100_devlist[i]->priv = NULL;
+ kfree_s(hp100_devlist[i], sizeof(struct device));
+ hp100_devlist[i] = (struct device *) NULL;
+ }
}
-#endif /* MODULE */
-
+#endif /* MODULE */
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c"
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
index c1c62e6bb..436dd3700 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/hp100.h
@@ -1,7 +1,7 @@
/*
* hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
*
- * $Id: hp100.h,v 1.4 1997/05/26 21:09:19 davem Exp $
+ * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
*
* Authors: Jaroslav Kysela, <perex@pf.jcu.cz>
* Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c
index 141349576..16e52bd98 100644
--- a/drivers/net/ipddp.c
+++ b/drivers/net/ipddp.c
@@ -83,9 +83,6 @@ static unsigned int ipddp_debug = IPDDP_DEBUG;
/* Index to functions, as function prototypes. */
static int ipddp_xmit(struct sk_buff *skb, struct device *dev);
static struct net_device_stats *ipddp_get_stats(struct device *dev);
-static int ipddp_rebuild_header(struct sk_buff *skb);
-static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len);
static int ipddp_create(struct ipddp_route *new_rt);
static int ipddp_delete(struct ipddp_route *rt);
static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
@@ -119,10 +116,10 @@ int ipddp_init(struct device *dev)
/* Let the user now what mode we are in */
if(ipddp_mode == IPDDP_ENCAP)
- printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n",
+ printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n",
dev->name);
if(ipddp_mode == IPDDP_DECAP)
- printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n",
+ printk("%s: Appletalk-IP Decap. mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n",
dev->name);
/* Fill in the device structure with ethernet-generic values. */
@@ -140,8 +137,6 @@ int ipddp_init(struct device *dev)
dev->stop = ipddp_close;
dev->get_stats = ipddp_get_stats;
dev->do_ioctl = ipddp_ioctl;
- dev->hard_header = ipddp_hard_header; /* see ip_output.c */
- dev->rebuild_header = ipddp_rebuild_header;
dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
dev->mtu = 585;
@@ -158,24 +153,6 @@ int ipddp_init(struct device *dev)
}
/*
- * Transmit LLAP/ELAP frame using aarp_send_ddp.
- */
-static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
-{
- /* Retrieve the saved address hint */
- struct at_addr *at = (struct at_addr *)skb->data;
- skb_pull(skb,4);
-
- ((struct net_device_stats *) dev->priv)->tx_packets++;
- ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
-
- if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
* Get the current statistics. This may be called with the card open or closed.
*/
static struct net_device_stats *ipddp_get_stats(struct device *dev)
@@ -184,19 +161,15 @@ static struct net_device_stats *ipddp_get_stats(struct device *dev)
}
/*
- * Now the packet really wants to go out. On entry skb->data points to the
- * ddpehdr we reserved earlier. skb->h.raw will be the higher level header.
+ * Transmit LLAP/ELAP frame using aarp_send_ddp.
*/
-static int ipddp_rebuild_header(struct sk_buff *skb)
+static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
{
u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
struct ddpehdr *ddp;
- struct at_addr at;
struct ipddp_route *rt;
struct at_addr *our_addr;
- /* Wow! I'll eat my hat if this routine is really called. --ANK */
-
/*
* Find appropriate route to use, based only on IP number.
*/
@@ -205,25 +178,21 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
if(rt->ip == paddr)
break;
}
-
if(rt == NULL)
- {
- printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr));
- return -ENETUNREACH;
- }
+ return 0;
our_addr = atalk_find_dev_addr(rt->dev);
if(ipddp_mode == IPDDP_DECAP)
/*
* Pull off the excess room that should not be there.
- * This is the case for Localtalk, this may not hold
- * true for Ethertalk, etc.
+ * This is due to a hard-header problem. This is the
+ * quick fix for now though, till it breaks.
*/
- skb_pull(skb, 31-(sizeof(struct ddpehdr)+1));
+ skb_pull(skb, 35-(sizeof(struct ddpehdr)+1));
/* Create the Extended DDP header */
- ddp = (struct ddpehdr *) (skb->data+4);
+ ddp = (struct ddpehdr *)skb->data;
ddp->deh_len = skb->len;
ddp->deh_hops = 1;
ddp->deh_pad = 0;
@@ -231,7 +200,7 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
/*
* For Localtalk we need aarp_send_ddp to strip the
- * Ext DDP header and place a Shrt DDP header on it.
+ * long DDP header and place a shot DDP header on it.
*/
if(rt->dev->type == ARPHRD_LOCALTLK)
{
@@ -248,24 +217,16 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
ddp->deh_dport = 72;
ddp->deh_sport = 72;
- *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
- *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
+ *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
+ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
- /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */
- at = rt->at;
- memcpy(skb->data,(void *)&at,sizeof(at));
-
- skb->dev = rt->dev; /* set skb->dev to appropriate device */
skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
- return 0;
-}
+ ((struct net_device_stats *) dev->priv)->tx_packets++;
+ ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
-static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
-{
- /* Push down the header space and the type byte */
- skb_push(skb, sizeof(struct ddpehdr)+1+4);
+ if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/ipddp.h b/drivers/net/ipddp.h
index 31178934b..076373b81 100644
--- a/drivers/net/ipddp.h
+++ b/drivers/net/ipddp.h
@@ -10,7 +10,6 @@
#define SIOCADDIPDDPRT (SIOCDEVPRIVATE)
#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1)
#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2)
-#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3)
struct ipddp_route
{
diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c
index 9380f32f8..de70cd001 100644
--- a/drivers/net/ppp.c
+++ b/drivers/net/ppp.c
@@ -3,6 +3,7 @@
* Michael Callahan <callahan@maths.ox.ac.uk>
* Al Longyear <longyear@netcom.com>
* Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+ * Cyrus Durgin <cider@speakeasy.org> (changes for kmod)
*
* Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
* ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
@@ -50,7 +51,7 @@
/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
-#include <linux/config.h> /* for CONFIG_KERNELD */
+#include <linux/config.h> /* for CONFIG_KMOD */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -94,8 +95,8 @@ typedef struct sk_buff sk_buff;
#include <linux/if_pppvar.h>
#include <linux/ppp-comp.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#ifndef PPP_IPX
@@ -2190,14 +2191,14 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
restore_flags(flags);
cp = find_compressor (ccp_option[0]);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (cp == NULL) {
char modname[32];
sprintf(modname, "ppp-compress-%d", ccp_option[0]);
request_module(modname);
cp = find_compressor(ccp_option[0]);
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
if (cp == NULL)
goto out_no_comp;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index d036fabb3..6dbaec6d2 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -43,6 +43,7 @@ static const char *version =
#include <linux/init.h>
#include <asm/system.h>
#include <asm/bitops.h>
+#include <asm/delay.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/errno.h>
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index fe464965e..489f0a39e 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -181,12 +181,14 @@ sl_alloc_bufs(struct slip *sl, int mtu)
sl->xleft = 0;
rbuff = xchg(&sl->rbuff, rbuff);
xbuff = xchg(&sl->xbuff, xbuff);
-#ifdef CONFIG_SLIP_MODE_SLIP6
+#ifdef SL_INCLUDE_CSLIP
cbuff = xchg(&sl->cbuff, cbuff);
slcomp = xchg(&sl->slcomp, slcomp);
+#ifdef CONFIG_SLIP_MODE_SLIP6
sl->xdata = 0;
sl->xbits = 0;
#endif
+#endif
end_bh_atomic();
err = 0;
@@ -1134,7 +1136,7 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
it breaks my old poor gcc on alpha --ANK
*/
tmp = strlen(sl->dev->name) + 1;
- if (copy_to_user(arg, sl->dev->name, tmp) < 0)
+ if (copy_to_user(arg, sl->dev->name, tmp))
return -EFAULT;
return 0;
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index f4484e225..035c47a5c 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -636,7 +636,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
for (i = 0; i < 5; i++)
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__i386) /* This BIOS bug doesn't exist on Alphas. */
+#if defined(__i386__) /* This BIOS bug doesn't exist on Alphas. */
irq = last_irq;
#endif
}
@@ -1094,7 +1094,7 @@ tulip_open(struct device *dev)
outl(0x00200000 | 0xE000, ioaddr + CSR0);
#elif defined(__powerpc__)
outl(0x00200080 | 0x8000, ioaddr + CSR0);
-#elif defined(__i386)
+#elif defined(__i386__)
#if defined(MODULE)
/* When a module we don't have 'x86' to check. */
outl(0x00200000 | 0x4800, ioaddr + CSR0);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 2dc9c8a66..7956db9d1 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -9470,7 +9470,7 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
/*
* Try to fix up PCI config according to wished features.
*/
-#if defined(__i386) && !defined(MODULE)
+#if defined(__i386__) && !defined(MODULE)
if ((driver_setup.pci_fix_up & 1) &&
(chip->features & FE_CLSE) && cache_line_size == 0) {
#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 3c2f083bd..ebdcb560c 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -50,8 +50,8 @@ NULL, /* cur_cmd */ \
#include "ppa.h"
#include <linux/parport.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#ifndef PARPORT_MODULES
#define PARPORT_MODULES "parport_pc"
#endif
@@ -130,7 +130,7 @@ int ppa_detect(Scsi_Host_Template * host)
nhosts = 0;
try_again = 0;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!pb) {
request_module(PARPORT_MODULES);
pb = parport_enumerate();
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 4876ad297..90bb6e2d4 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -23,10 +23,13 @@
* Added request_module("scsi_hostadapter") for kerneld:
* (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
* Bjorn Ekwall <bj0rn@blox.se>
+ * (changed to kmod)
*
* Major improvements to the timeout, abort, and reset processing,
* as well as performance modifications for large queue depths by
* Leonard N. Zubkoff <lnz@dandelion.com>
+ *
+ * Converted cli() code to spinlocks, Ingo Molnar
*/
#include <linux/config.h>
@@ -57,8 +60,8 @@
#include "hosts.h"
#include "constants.h"
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#undef USE_STATIC_SCSI_MEMORY
@@ -350,8 +353,8 @@ scsi_make_blocked_list(void)
* (DB, 4 Feb 1995)
*/
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&io_request_lock, flags);
host_active = NULL;
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
@@ -383,7 +386,7 @@ scsi_make_blocked_list(void)
sh[index]->host_no);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
@@ -1134,21 +1137,21 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
SCpnt = found;
}
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
/* See if this request has already been queued by an interrupt routine
*/
if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
- restore_flags(flags);
+ __restore_flags(flags);
return NULL;
}
if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */
{
if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
sleep_on(&device->device_wait);
- restore_flags(flags);
+ __restore_flags(flags);
} else {
- restore_flags(flags);
+ __restore_flags(flags);
if (!wait) return NULL;
if (!SCwait) {
printk("Attempt to allocate device channel %d,"
@@ -1198,7 +1201,7 @@ Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
* to complete */
}
atomic_inc(&SCpnt->host->host_active);
- restore_flags(flags);
+ __restore_flags(flags);
SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
SCpnt->target,
atomic_read(&SCpnt->host->host_active)));
@@ -1295,8 +1298,7 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
host = SCpnt->host;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
/* Assign a unique nonzero serial_number. */
if (++serial_number == 0) serial_number = 1;
SCpnt->serial_number = serial_number;
@@ -1306,6 +1308,8 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
* we can avoid the drive not being ready.
*/
timeout = host->last_reset + MIN_RESET_DELAY;
+ spin_unlock(&io_request_lock);
+
if (jiffies < timeout) {
int ticks_remaining = timeout - jiffies;
/*
@@ -1317,11 +1321,11 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt)
* interrupt handler (assuming there is one irq-level per
* host).
*/
- sti();
+ __sti();
while (--ticks_remaining >= 0) udelay(1000000/HZ);
host->last_reset = jiffies - MIN_RESET_DELAY;
}
- restore_flags(flags);
+ __restore_flags(flags); /* this possibly puts us back into __cli() */
if( host->hostt->use_new_eh_code )
{
@@ -1452,21 +1456,20 @@ SCSI_LOG_MLQUEUE(4,
* ourselves.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
SCpnt->pid = scsi_pid++;
while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
}
if (host->block) host_active = host;
host->host_busy++;
device->device_busy++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
/*
* Our own function scsi_done (which marks the host as not busy, disables
@@ -1820,8 +1823,7 @@ void *scsi_malloc(unsigned int len)
if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
return NULL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
nbits = len >> 9;
mask = (1 << nbits) - 1;
@@ -1829,7 +1831,7 @@ void *scsi_malloc(unsigned int len)
for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
if ((dma_malloc_freelist[i] & (mask << j)) == 0){
dma_malloc_freelist[i] |= (mask << j);
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
scsi_dma_free_sectors -= nbits;
#ifdef DEBUG
SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
@@ -1838,7 +1840,7 @@ void *scsi_malloc(unsigned int len)
return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return NULL; /* Nope. No more */
}
@@ -1872,19 +1874,20 @@ int scsi_free(void *obj, unsigned int len)
if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
panic ("scsi_free:Bad memory alignment");
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
if((dma_malloc_freelist[page] &
(mask << sector)) != (mask<<sector)){
+ spin_unlock_irqrestore(&io_request_lock, flags);
#ifdef DEBUG
printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
obj, len, ret);
#endif
panic("scsi_free:Trying to free unused memory");
+ spin_lock_irqsave(&io_request_lock, flags);
}
scsi_dma_free_sectors += nbits;
dma_malloc_freelist[page] &= ~(mask << sector);
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return 0;
}
}
@@ -2548,8 +2551,7 @@ static void resize_dma_pool(void)
/* When we dick with the actual DMA list, we need to
* protect things
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
if (dma_malloc_freelist)
{
size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
@@ -2569,7 +2571,7 @@ static void resize_dma_pool(void)
dma_malloc_pages = new_dma_malloc_pages;
dma_sectors = new_dma_sectors;
scsi_need_isa_buffer = new_need_isa_buffer;
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
#ifdef DEBUG_INIT
printk("resize_dma_pool: dma free sectors = %d\n", scsi_dma_free_sectors);
@@ -2808,11 +2810,10 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
{
online_status = SDpnt->online;
SDpnt->online = FALSE;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
if(SCpnt->request.rq_status != RQ_INACTIVE)
{
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
printk("SCSI device not inactive - state=%d, id=%d\n",
SCpnt->request.rq_status, SCpnt->target);
for(SDpnt1 = shpnt->host_queue; SDpnt1;
@@ -2833,7 +2834,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
*/
SCpnt->state = SCSI_STATE_DISCONNECTING;
SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
}
}
@@ -3118,7 +3119,7 @@ int scsi_register_module(int module_type, void * ptr)
/* Load upper level device handler of some kind */
case MODULE_SCSI_DEV:
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (scsi_hosts == NULL)
request_module("scsi_hostadapter");
#endif
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f5e19c547..70adb0040 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -38,10 +37,6 @@
#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
-
#ifdef DEBUG
#define SENSE_TIMEOUT SCSI_TIMEOUT
#define ABORT_TIMEOUT SCSI_TIMEOUT
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
index 077b73063..daede4a56 100644
--- a/drivers/scsi/scsi_obsolete.c
+++ b/drivers/scsi/scsi_obsolete.c
@@ -20,10 +20,6 @@
* Native multichannel, wide scsi, /proc/scsi and hot plugging
* support added by Michael Neuffer <mike@i-connect.net>
*
- * Added request_module("scsi_hostadapter") for kerneld:
- * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
- * Bjorn Ekwall <bj0rn@blox.se>
- *
* Major improvements to the timeout, abort, and reset processing,
* as well as performance modifications for large queue depths by
* Leonard N. Zubkoff <lnz@dandelion.com>
@@ -47,7 +43,6 @@
* driver uses the new code this *ENTIRE* file will be nuked.
*/
-#include <linux/config.h> /* for CONFIG_KERNELD */
#define __NO_VERSION__
#include <linux/module.h>
@@ -70,10 +65,6 @@
#include "hosts.h"
#include "constants.h"
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
-
#undef USE_STATIC_SCSI_MEMORY
/*
diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
index b9e2a4feb..3c29353f9 100644
--- a/drivers/scsi/scsi_queue.c
+++ b/drivers/scsi/scsi_queue.c
@@ -10,7 +10,6 @@
* we attempt to remove commands from the queue and retry them.
*/
-#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -38,10 +37,6 @@
#include "hosts.h"
#include "constants.h"
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
-
/*
* TODO:
* 1) Prevent multiple traversals of list to look for commands to
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index c29194b70..5f0668eb6 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1598,15 +1598,14 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
target = DEVICE_NR(dev);
gdev = &GENDISK_STRUCT;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
if (DEVICE_BUSY || USAGE > maxusage) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
}
DEVICE_BUSY = 1;
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
max_p = gdev->max_p;
start = target << gdev->minor_shift;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index f8c899535..1b915e3ed 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -127,6 +127,19 @@
*
* Thanks to Roger Scott for driver debugging.
*
+ * 06/07/1997
+ *
+ * Added support for /proc file system (/proc/scsi/wd7000/[0...] files).
+ * Now, driver can handle hard disks with capacity >1GB.
+ *
+ * 01/15/1998
+ *
+ * Added support for BUS_ON and BUS_OFF parameters in config line.
+ * Miscellaneous cleanup.
+ *
+ * 03/01/1998
+ *
+ * WD7000 driver now work on kernels >= 2.1.x
*/
#ifdef MODULE
@@ -143,24 +156,29 @@
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
+#include <linux/version.h>
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
+#include <scsi/scsicam.h>
#define ANY2SCSI_INLINE /* undef this to use old macros */
-#undef DEBUG
+#undef WD7000_DEBUG /* general debug */
#include "wd7000.h"
+#include <linux/stat.h>
-#include<linux/stat.h>
-struct proc_dir_entry proc_scsi_wd7000 = {
- PROC_SCSI_7000FASST, 6, "wd7000",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
+struct proc_dir_entry proc_scsi_wd7000 =
+{
+ PROC_SCSI_7000FASST,
+ 6,
+ "wd7000",
+ S_IFDIR | S_IRUGO | S_IXUGO,
+ 2
};
@@ -186,52 +204,48 @@ struct proc_dir_entry proc_scsi_wd7000 = {
* WD7000-specific mailbox structure
*
*/
-typedef volatile struct mailbox{
- unchar status;
- unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */
+typedef volatile struct mailbox {
+ unchar status;
+ unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */
} Mailbox;
/*
* This structure should contain all per-adapter global data. I.e., any
* new global per-adapter data should put in here.
- *
*/
typedef struct adapter {
- struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */
- int iobase; /* This adapter's I/O base address */
- int irq; /* This adapter's IRQ level */
- int dma; /* This adapter's DMA channel */
- struct { /* This adapter's mailboxes */
- Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */
- Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */
- } mb;
- int next_ogmb; /* to reduce contention at mailboxes */
- unchar control; /* shadows CONTROL port value */
- unchar rev1, rev2; /* filled in by wd7000_revision */
+ struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */
+ int iobase; /* This adapter's I/O base address */
+ int irq; /* This adapter's IRQ level */
+ int dma; /* This adapter's DMA channel */
+ int int_counter; /* This adapter's interrupt counter */
+ int bus_on; /* This adapter's BUS_ON time */
+ int bus_off; /* This adapter's BUS_OFF time */
+ struct { /* This adapter's mailboxes */
+ Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */
+ Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */
+ } mb;
+ int next_ogmb; /* to reduce contention at mailboxes */
+ unchar control; /* shadows CONTROL port value */
+ unchar rev1, rev2; /* filled in by wd7000_revision */
} Adapter;
/*
- * The following is set up by wd7000_detect, and used thereafter by
- * wd7000_intr_handle to map the irq level to the corresponding Adapter.
- * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
- * changed to pick up the IRQ level correctly.
- */
-static Adapter *irq2host[NR_IRQS] = {NULL};
-
-/*
* (linear) base address for ROM BIOS
*/
-static const long wd7000_biosaddr[] = {
- 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
- 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
+static const long wd7000_biosaddr[] =
+{
+ 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
+ 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
};
#define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long))
-static const unsigned short wd7000_iobase[] = {
- 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
- 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
- 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
- 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
+static const unsigned short wd7000_iobase[] =
+{
+ 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
+ 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
+ 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
+ 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
};
#define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short))
@@ -240,24 +254,48 @@ static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
static const short wd7000_dma[] = { 5, 6, 7 };
#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short))
-
+
+/*
+ * possible irq range
+ */
+#define IRQ_MIN 3
+#define IRQ_MAX 15
+#define IRQS (IRQ_MAX - IRQ_MIN + 1)
+
+/*
+ * The following is set up by wd7000_detect, and used thereafter by
+ * wd7000_intr_handle to map the irq level to the corresponding Adapter.
+ * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
+ * changed to pick up the IRQ level correctly.
+ */
+static struct Scsi_Host *wd7000_host[IRQS];
+
+#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */
+#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */
+
/*
* Standard Adapter Configurations - used by wd7000_detect
*/
typedef struct {
- int irq; /* IRQ level */
- int dma; /* DMA channel */
- unsigned iobase; /* I/O base address */
+ short irq; /* IRQ level */
+ short dma; /* DMA channel */
+ unsigned iobase; /* I/O base address */
+ short bus_on; /* Time that WD7000 spends on the AT-bus when */
+ /* transferring data. BIOS default is 8000ns. */
+ short bus_off; /* Time that WD7000 spends OFF THE BUS after */
+ /* while it is transferring data. */
+ /* BIOS default is 1875ns */
} Config;
/*
* Add here your configuration...
*/
-static const Config configs[] = {
- { 15, 6, 0x350 }, /* defaults for single adapter */
- { 11, 5, 0x320 }, /* defaults for second adapter */
- { 7, 6, 0x350 }, /* My configuration (Zaga) */
- { -1, -1, 0x0 } /* Empty slot */
+static Config configs[] =
+{
+ { 15, 6, 0x350, BUS_ON, BUS_OFF }, /* defaults for single adapter */
+ { 11, 5, 0x320, BUS_ON, BUS_OFF }, /* defaults for second adapter */
+ { 7, 6, 0x350, BUS_ON, BUS_OFF }, /* My configuration (Zaga) */
+ { -1, -1, 0x0, BUS_ON, BUS_OFF } /* Empty slot */
};
#define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
@@ -267,13 +305,14 @@ static const Config configs[] = {
* added for the Future Domain version.
*/
typedef struct signature {
- const void *sig; /* String to look for */
- unsigned ofs; /* offset from BIOS base address */
- unsigned len; /* length of string */
+ const char *sig; /* String to look for */
+ unsigned long ofs; /* offset from BIOS base address */
+ unsigned len; /* length of string */
} Signature;
-static const Signature signatures[] = {
- { "SSTBIOS", 0x0000d, 7 } /* "SSTBIOS" @ offset 0x0000d */
+static const Signature signatures[] =
+{
+ {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */
};
#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
@@ -282,22 +321,23 @@ static const Signature signatures[] = {
* I/O Port Offsets and Bit Definitions
* 4 addresses are used. Those not defined here are reserved.
*/
-#define ASC_STAT 0 /* Status, Read */
-#define ASC_COMMAND 0 /* Command, Write */
+#define ASC_STAT 0 /* Status, Read */
+#define ASC_COMMAND 0 /* Command, Write */
#define ASC_INTR_STAT 1 /* Interrupt Status, Read */
-#define ASC_INTR_ACK 1 /* Acknowledge, Write */
-#define ASC_CONTROL 2 /* Control, Write */
+#define ASC_INTR_ACK 1 /* Acknowledge, Write */
+#define ASC_CONTROL 2 /* Control, Write */
/*
* ASC Status Port
*/
-#define INT_IM 0x80 /* Interrupt Image Flag */
-#define CMD_RDY 0x40 /* Command Port Ready */
-#define CMD_REJ 0x20 /* Command Port Byte Rejected */
-#define ASC_INIT 0x10 /* ASC Initialized Flag */
+#define INT_IM 0x80 /* Interrupt Image Flag */
+#define CMD_RDY 0x40 /* Command Port Ready */
+#define CMD_REJ 0x20 /* Command Port Byte Rejected */
+#define ASC_INIT 0x10 /* ASC Initialized Flag */
#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */
-/* COMMAND opcodes
+/*
+ * COMMAND opcodes
*
* Unfortunately, I have no idea how to properly use some of these commands,
* as the OEM manual does not make it clear. I have not been able to use
@@ -305,39 +345,38 @@ static const Signature signatures[] = {
* discernible effect whatsoever. I think they may be related to certain
* ICB commands, but again, the OEM manual doesn't make that clear.
*/
-#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */
-#define INITIALIZATION 1 /* initialization (10 bytes) */
-#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */
-#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */
-#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */
-#define SOFT_RESET 5 /* SCSI bus soft reset */
-#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */
-#define START_OGMB 0x80 /* start command in OGMB (n) */
+#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */
+#define INITIALIZATION 1 /* initialization (10 bytes) */
+#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */
+#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */
+#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */
+#define SOFT_RESET 5 /* SCSI bus soft reset */
+#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */
+#define START_OGMB 0x80 /* start command in OGMB (n) */
#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */
- /* where (n) = lower 6 bits */
-/* For INITIALIZATION:
+ /* where (n) = lower 6 bits */
+/*
+ * For INITIALIZATION:
*/
typedef struct initCmd {
- unchar op; /* command opcode (= 1) */
- unchar ID; /* Adapter's SCSI ID */
- unchar bus_on; /* Bus on time, x 125ns (see below) */
- unchar bus_off; /* Bus off time, "" "" */
- unchar rsvd; /* Reserved */
- unchar mailboxes[3]; /* Address of Mailboxes, MSB first */
- unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */
- unchar icmbs; /* Number of incoming MBs, "" "" */
+ unchar op; /* command opcode (= 1) */
+ unchar ID; /* Adapter's SCSI ID */
+ unchar bus_on; /* Bus on time, x 125ns (see below) */
+ unchar bus_off; /* Bus off time, "" "" */
+ unchar rsvd; /* Reserved */
+ unchar mailboxes[3]; /* Address of Mailboxes, MSB first */
+ unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */
+ unchar icmbs; /* Number of incoming MBs, "" "" */
} InitCmd;
-#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */
-#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */
-
-/* Interrupt Status Port - also returns diagnostic codes at ASC reset
+/*
+ * Interrupt Status Port - also returns diagnostic codes at ASC reset
*
* if msb is zero, the lower bits are diagnostic status
* Diagnostics:
- * 01 No diagnostic error occurred
- * 02 RAM failure
- * 03 FIFO R/W failed
+ * 01 No diagnostic error occurred
+ * 02 RAM failure
+ * 03 FIFO R/W failed
* 04 SBIC register read/write failed
* 05 Initialization D-FF failed
* 06 Host IRQ D-FF failed
@@ -346,19 +385,20 @@ typedef struct initCmd {
* 10NNNNNN outgoing mailbox NNNNNN is free
* 11NNNNNN incoming mailbox NNNNNN needs service
*/
-#define MB_INTR 0xC0 /* Mailbox Service possible/required */
-#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */
-#define MB_MASK 0x3f /* mask for mailbox number */
+#define MB_INTR 0xC0 /* Mailbox Service possible/required */
+#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */
+#define MB_MASK 0x3f /* mask for mailbox number */
-/* CONTROL port bits
+/*
+ * CONTROL port bits
*/
-#define INT_EN 0x08 /* Interrupt Enable */
-#define DMA_EN 0x04 /* DMA Enable */
-#define SCSI_RES 0x02 /* SCSI Reset */
-#define ASC_RES 0x01 /* ASC Reset */
+#define INT_EN 0x08 /* Interrupt Enable */
+#define DMA_EN 0x04 /* DMA Enable */
+#define SCSI_RES 0x02 /* SCSI Reset */
+#define ASC_RES 0x01 /* ASC Reset */
/*
- * Driver data structures:
+ * Driver data structures:
* - mb and scbs are required for interfacing with the host adapter.
* An SCB has extra fields not visible to the adapter; mb's
* _cannot_ do this, since the adapter assumes they are contiguous in
@@ -387,28 +427,28 @@ typedef struct initCmd {
*/
typedef struct sgb {
unchar len[3];
- unchar ptr[3]; /* Also SCSI-style - MSB first */
+ unchar ptr[3]; /* Also SCSI-style - MSB first */
} Sgb;
-typedef struct scb { /* Command Control Block 5.4.1 */
- unchar op; /* Command Control Block Operation Code */
- unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */
- /* Outbound data transfer, length is checked*/
- /* Inbound data transfer, length is checked */
- /* Logical Unit Number */
- unchar cdb[12]; /* SCSI Command Block */
- volatile unchar status; /* SCSI Return Status */
- volatile unchar vue; /* Vendor Unique Error Code */
- unchar maxlen[3]; /* Maximum Data Transfer Length */
- unchar dataptr[3]; /* SCSI Data Block Pointer */
- unchar linkptr[3]; /* Next Command Link Pointer */
- unchar direc; /* Transfer Direction */
- unchar reserved2[6]; /* SCSI Command Descriptor Block */
- /* end of hardware SCB */
- Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */
- Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */
- Adapter *host; /* host adapter */
- struct scb *next; /* for lists of scbs */
+typedef struct scb { /* Command Control Block 5.4.1 */
+ unchar op; /* Command Control Block Operation Code */
+ unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */
+ /* Outbound data transfer, length is checked */
+ /* Inbound data transfer, length is checked */
+ /* Logical Unit Number */
+ unchar cdb[12]; /* SCSI Command Block */
+ volatile unchar status; /* SCSI Return Status */
+ volatile unchar vue; /* Vendor Unique Error Code */
+ unchar maxlen[3]; /* Maximum Data Transfer Length */
+ unchar dataptr[3]; /* SCSI Data Block Pointer */
+ unchar linkptr[3]; /* Next Command Link Pointer */
+ unchar direc; /* Transfer Direction */
+ unchar reserved2[6]; /* SCSI Command Descriptor Block */
+ /* end of hardware SCB */
+ Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */
+ Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */
+ Adapter *host; /* host adapter */
+ struct scb *next; /* for lists of scbs */
} Scb;
/*
@@ -422,110 +462,110 @@ typedef struct scb { /* Command Control Block 5.4.1 */
* (notably, get/set unsolicited interrupt status) in my copy of the OEM
* manual, and others are ambiguous/hard to follow.
*/
-#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */
-#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */
-#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */
-#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */
-#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */
-#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */
-#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */
- /* 0x87 is reserved */
-#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */
-#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */
-#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */
-#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */
-#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */
-#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */
-#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */
-#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */
+#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */
+#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */
+#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */
+#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */
+#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */
+#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */
+#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */
+ /* 0x87 is reserved */
+#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */
+#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */
+#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */
+#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */
+#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */
+#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */
+#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */
+#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */
typedef struct icbRecvCmd {
- unchar op;
- unchar IDlun; /* Initiator SCSI ID/lun */
- unchar len[3]; /* command buffer length */
- unchar ptr[3]; /* command buffer address */
- unchar rsvd[7]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ unchar IDlun; /* Initiator SCSI ID/lun */
+ unchar len[3]; /* command buffer length */
+ unchar ptr[3]; /* command buffer address */
+ unchar rsvd[7]; /* reserved */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbRecvCmd;
typedef struct icbSendStat {
- unchar op;
- unchar IDlun; /* Target SCSI ID/lun */
- unchar stat; /* (outgoing) completion status byte 1 */
- unchar rsvd[12]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ unchar IDlun; /* Target SCSI ID/lun */
+ unchar stat; /* (outgoing) completion status byte 1 */
+ unchar rsvd[12]; /* reserved */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbSendStat;
typedef struct icbRevLvl {
- unchar op;
- volatile unchar primary; /* primary revision level (returned) */
- volatile unchar secondary; /* secondary revision level (returned) */
- unchar rsvd[12]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ volatile unchar primary; /* primary revision level (returned) */
+ volatile unchar secondary; /* secondary revision level (returned) */
+ unchar rsvd[12]; /* reserved */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbRevLvl;
-typedef struct icbUnsMask { /* I'm totally guessing here */
- unchar op;
- volatile unchar mask[14]; /* mask bits */
-#if 0
- unchar rsvd[12]; /* reserved */
+typedef struct icbUnsMask { /* I'm totally guessing here */
+ unchar op;
+ volatile unchar mask[14]; /* mask bits */
+#ifdef 0
+ unchar rsvd[12]; /* reserved */
#endif
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbUnsMask;
typedef struct icbDiag {
- unchar op;
- unchar type; /* diagnostics type code (0-3) */
- unchar len[3]; /* buffer length */
- unchar ptr[3]; /* buffer address */
- unchar rsvd[7]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ unchar type; /* diagnostics type code (0-3) */
+ unchar len[3]; /* buffer length */
+ unchar ptr[3]; /* buffer address */
+ unchar rsvd[7]; /* reserved */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbDiag;
-#define ICB_DIAG_POWERUP 0 /* Power-up diags only */
-#define ICB_DIAG_WALKING 1 /* walking 1's pattern */
-#define ICB_DIAG_DMA 2 /* DMA - system memory diags */
-#define ICB_DIAG_FULL 3 /* do both 1 & 2 */
+#define ICB_DIAG_POWERUP 0 /* Power-up diags only */
+#define ICB_DIAG_WALKING 1 /* walking 1's pattern */
+#define ICB_DIAG_DMA 2 /* DMA - system memory diags */
+#define ICB_DIAG_FULL 3 /* do both 1 & 2 */
typedef struct icbParms {
- unchar op;
- unchar rsvd1; /* reserved */
- unchar len[3]; /* parms buffer length */
- unchar ptr[3]; /* parms buffer address */
- unchar idx[2]; /* index (MSB-LSB) */
- unchar rsvd2[5]; /* reserved */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ unchar rsvd1; /* reserved */
+ unchar len[3]; /* parms buffer length */
+ unchar ptr[3]; /* parms buffer address */
+ unchar idx[2]; /* index (MSB-LSB) */
+ unchar rsvd2[5]; /* reserved */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbParms;
typedef struct icbAny {
- unchar op;
- unchar data[14]; /* format-specific data */
- volatile unchar vue; /* vendor-unique error code */
- volatile unchar status; /* returned (icmb) status */
- volatile unchar phase; /* used by interrupt handler */
+ unchar op;
+ unchar data[14]; /* format-specific data */
+ volatile unchar vue; /* vendor-unique error code */
+ volatile unchar status; /* returned (icmb) status */
+ volatile unchar phase; /* used by interrupt handler */
} IcbAny;
typedef union icb {
- unchar op; /* ICB opcode */
- IcbRecvCmd recv_cmd; /* format for receive command */
- IcbSendStat send_stat; /* format for send status */
- IcbRevLvl rev_lvl; /* format for get revision level */
- IcbDiag diag; /* format for execute diagnostics */
- IcbParms eparms; /* format for get/set exec parms */
- IcbAny icb; /* generic format */
- unchar data[18];
+ unchar op; /* ICB opcode */
+ IcbRecvCmd recv_cmd; /* format for receive command */
+ IcbSendStat send_stat; /* format for send status */
+ IcbRevLvl rev_lvl; /* format for get revision level */
+ IcbDiag diag; /* format for execute diagnostics */
+ IcbParms eparms; /* format for get/set exec parms */
+ IcbAny icb; /* generic format */
+ unchar data[18];
} Icb;
@@ -536,27 +576,34 @@ typedef union icb {
* structure is not part of the Adapter structure.
*/
static Scb scbs[MAX_SCBS];
-static Scb *scbfree = NULL; /* free list */
-static int freescbs = MAX_SCBS; /* free list counter */
-
-/*
- *
- */
-static short wd7000_setupIRQ[NUM_CONFIGS];
-static short wd7000_setupDMA[NUM_CONFIGS];
-static short wd7000_setupIO[NUM_CONFIGS];
-static short wd7000_card_num = 0;
+static Scb *scbfree = NULL; /* free list */
+static int freescbs = MAX_SCBS; /* free list counter */
/*
* END of data/declarations - code follows.
*/
+static void setup_error (char *mesg, int *ints)
+{
+ if (ints[0] == 3)
+ printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
+ ints[1], ints[2], ints[3], mesg);
+ else if (ints[0] == 4)
+ printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
+ ints[1], ints[2], ints[3], ints[4], mesg);
+ else
+ printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
+ ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+}
/*
* Note: You can now set these options from the kernel's "command line".
* The syntax is:
*
- * wd7000=IRQ,DMA,IO
+ * wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]
+ *
+ * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values
+ * are 8000ns for BUS_ON and 1875ns for BUS_OFF.
* eg:
* wd7000=7,6,0x350
*
@@ -565,82 +612,99 @@ static short wd7000_card_num = 0;
*/
void wd7000_setup (char *str, int *ints)
{
+ static short wd7000_card_num = 0;
short i, j;
if (wd7000_card_num >= NUM_CONFIGS) {
- printk ("wd7000_setup: Too many \"wd7000=\" configurations in "
- "command line!\n");
-
- return;
+ printk ("wd7000_setup: Too many \"wd7000=\" configurations in "
+ "command line!\n");
+ return;
}
- if (ints[0] != 3)
+ if ((ints[0] < 3) || (ints[0] > 5))
printk ("wd7000_setup: Error in command line! "
- "Usage: wd7000=IRQ,DMA,IO\n");
+ "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");
else {
for (i = 0; i < NUM_IRQS; i++)
if (ints[1] == wd7000_irq[i])
break;
if (i == NUM_IRQS) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "invalid IRQ.\n", ints[1], ints[2], ints[3]);
+ setup_error ("invalid IRQ.", ints);
return;
}
else
- wd7000_setupIRQ[wd7000_card_num] = ints[1];
+ configs[wd7000_card_num].irq = ints[1];
for (i = 0; i < NUM_DMAS; i++)
if (ints[2] == wd7000_dma[i])
break;
if (i == NUM_DMAS) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "invalid DMA channel.\n", ints[1], ints[2], ints[3]);
+ setup_error ("invalid DMA channel.", ints);
return;
}
else
- wd7000_setupDMA[wd7000_card_num] = ints[2];
+ configs[wd7000_card_num].dma = ints[2];
for (i = 0; i < NUM_IOPORTS; i++)
if (ints[3] == wd7000_iobase[i])
break;
if (i == NUM_IOPORTS) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "invalid I/O base address.\n", ints[1], ints[2], ints[3]);
+ setup_error ("invalid I/O base address.", ints);
return;
}
else
- wd7000_setupIO[wd7000_card_num] = ints[3];
+ configs[wd7000_card_num].iobase = ints[3];
+
+ if (ints[0] > 3) {
+ if ((ints[4] < 500) || (ints[4] > 31875)) {
+ setup_error ("BUS_ON value is out of range (500 to 31875 nanoseconds)!",
+ ints);
+ configs[wd7000_card_num].bus_on = BUS_ON;
+ }
+ else
+ configs[wd7000_card_num].bus_on = ints[4] / 125.0;
+ }
+ else
+ configs[wd7000_card_num].bus_on = BUS_ON;
+
+ if (ints[0] > 4) {
+ if ((ints[5] < 500) || (ints[5] > 31875)) {
+ setup_error ("BUS_OFF value is out of range (500 to 31875 nanoseconds)!",
+ ints);
+ configs[wd7000_card_num].bus_off = BUS_OFF;
+ }
+ else
+ configs[wd7000_card_num].bus_off = ints[5] / 125.0;
+ }
+ else
+ configs[wd7000_card_num].bus_off = BUS_OFF;
if (wd7000_card_num)
for (i = 0; i < (wd7000_card_num - 1); i++)
- for (j = i + 1; j < wd7000_card_num; j++)
- if (wd7000_setupIRQ[i] == wd7000_setupIRQ[j]) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "duplicated IRQ!\n",
- ints[1], ints[2], ints[3]);
- return;
- }
- else if (wd7000_setupDMA[i] == wd7000_setupDMA[j]) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "duplicated DMA channel!\n",
- ints[1], ints[2], ints[3]);
- return;
- }
- else if (wd7000_setupIO[i] == wd7000_setupIO[j]) {
- printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> "
- "duplicated I/O base address!\n",
- ints[1], ints[2], ints[3]);
- return;
- }
-
-#ifdef DEBUG
- printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x\n",
- wd7000_setupIRQ[wd7000_card_num],
- wd7000_setupDMA[wd7000_card_num],
- wd7000_setupIO[wd7000_card_num]);
+ for (j = i + 1; j < wd7000_card_num; j++)
+ if (configs[i].irq == configs[j].irq) {
+ setup_error ("duplicated IRQ!", ints);
+ return;
+ }
+ else if (configs[i].dma == configs[j].dma) {
+ setup_error ("duplicated DMA channel!", ints);
+ return;
+ }
+ else if (configs[i].iobase == configs[j].iobase) {
+ setup_error ("duplicated I/O base address!", ints);
+ return;
+ }
+
+#ifdef WD7000_DEBUG
+ printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
+ configs[wd7000_card_num].irq,
+ configs[wd7000_card_num].dma,
+ configs[wd7000_card_num].iobase,
+ configs[wd7000_card_num].bus_on * 125,
+ configs[wd7000_card_num].bus_off * 125);
#endif
wd7000_card_num++;
@@ -650,21 +714,20 @@ void wd7000_setup (char *str, int *ints)
#ifdef ANY2SCSI_INLINE
/*
- Since they're used a lot, I've redone the following from the macros
- formerly in wd7000.h, hopefully to speed them up by getting rid of
- all the shifting (it may not matter; GCC might have done as well anyway).
-
- xany2scsi and xscsi2int were not being used, and are no longer defined.
- (They were simply 4-byte versions of these routines).
-*/
-
-typedef union { /* let's cheat... */
- int i;
- unchar u[sizeof(int)]; /* the sizeof(int) makes it more portable */
+ * Since they're used a lot, I've redone the following from the macros
+ * formerly in wd7000.h, hopefully to speed them up by getting rid of
+ * all the shifting (it may not matter; GCC might have done as well anyway).
+ *
+ * xany2scsi and xscsi2int were not being used, and are no longer defined.
+ * (They were simply 4-byte versions of these routines).
+ */
+typedef union { /* let's cheat... */
+ int i;
+ unchar u[sizeof (int)]; /* the sizeof(int) makes it more portable */
} i_u;
-static inline void any2scsi( unchar *scsi, int any )
+static inline void any2scsi (unchar * scsi, int any)
{
*scsi++ = ((i_u) any).u[2];
*scsi++ = ((i_u) any).u[1];
@@ -672,49 +735,50 @@ static inline void any2scsi( unchar *scsi, int any )
}
-static inline int scsi2int( unchar *scsi )
+static inline int scsi2int (unchar * scsi)
{
i_u result;
- result.i = 0; /* clears unused bytes */
- *(result.u+2) = *scsi++;
- *(result.u+1) = *scsi++;
- *(result.u) = *scsi++;
- return result.i;
+ result.i = 0; /* clears unused bytes */
+ result.u[2] = *scsi++;
+ result.u[1] = *scsi++;
+ result.u[0] = *scsi++;
+
+ return (result.i);
}
#else
/*
- These are the old ones - I've just moved them here...
-*/
+ * These are the old ones - I've just moved them here...
+ */
#undef any2scsi
-#define any2scsi(up, p) \
-(up)[0] = (((unsigned long)(p)) >> 16); \
-(up)[1] = ((unsigned long)(p)) >> 8; \
-(up)[2] = ((unsigned long)(p));
+#define any2scsi(up, p) (up)[0] = (((unsigned long) (p)) >> 16); \
+ (up)[1] = ((unsigned long) (p)) >> 8; \
+ (up)[2] = ((unsigned long) (p));
#undef scsi2int
-#define scsi2int(up) ( (((unsigned long)*(up)) << 16) + \
- (((unsigned long)(up)[1]) << 8) + ((unsigned long)(up)[2]) )
+#define scsi2int(up) ( (((unsigned long) *(up)) << 16) + \
+ (((unsigned long) (up)[1]) << 8) + \
+ ((unsigned long) (up)[2]) )
#endif
-
-static inline void wd7000_enable_intr(Adapter *host)
+
+static inline void wd7000_enable_intr (Adapter *host)
{
host->control |= INT_EN;
- outb(host->control, host->iobase+ASC_CONTROL);
+ outb (host->control, host->iobase + ASC_CONTROL);
}
-static inline void wd7000_enable_dma(Adapter *host)
+static inline void wd7000_enable_dma (Adapter *host)
{
host->control |= DMA_EN;
- outb(host->control,host->iobase+ASC_CONTROL);
- set_dma_mode(host->dma, DMA_MODE_CASCADE);
- enable_dma(host->dma);
+ outb (host->control, host->iobase + ASC_CONTROL);
+ set_dma_mode (host->dma, DMA_MODE_CASCADE);
+ enable_dma (host->dma);
}
-#define WAITnexttimeout 200 /* 2 seconds */
+#define WAITnexttimeout 200 /* 2 seconds */
static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof)
{
@@ -722,7 +786,7 @@ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned
register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
while (jiffies <= WAITtimeout) {
- WAITbits = inb (port) & mask;
+ WAITbits = inb (port) & mask;
if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
return (0);
@@ -732,31 +796,32 @@ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned
}
-static inline void delay( unsigned how_long )
+static inline void delay (unsigned how_long)
{
- register unsigned long time = jiffies + how_long;
+ register unsigned long time = jiffies + how_long;
- while (jiffies < time);
+ while (jiffies < time);
}
-static inline int command_out(Adapter *host, unchar *cmd, int len)
+static inline int command_out (Adapter * host, unchar * cmd, int len)
{
- if (! WAIT (host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0)) {
- while (len--) {
- do {
- outb(*cmd, host->iobase+ASC_COMMAND);
- WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
- } while (inb(host->iobase+ASC_STAT) & CMD_REJ);
+ if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+ while (len--) {
+ do {
+ outb (*cmd, host->iobase + ASC_COMMAND);
+ WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
+ } while (inb (host->iobase + ASC_STAT) & CMD_REJ);
cmd++;
}
- return 1;
+ return (1);
}
- printk("wd7000 command_out: WAIT failed(%d)\n", len+1);
- return 0;
+ printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);
+
+ return (0);
}
@@ -770,7 +835,7 @@ static inline int command_out(Adapter *host, unchar *cmd, int len)
* the satisfiability of a request is not dependent on the size of the
* request.
*/
-static inline Scb *alloc_scbs(int needed)
+static inline Scb *alloc_scbs (int needed)
{
register Scb *scb, *p;
register unsigned long flags;
@@ -779,84 +844,89 @@ static inline Scb *alloc_scbs(int needed)
static int busy = 0;
int i;
- if (needed <= 0) return NULL; /* sanity check */
+ if (needed <= 0)
+ return (NULL); /* sanity check */
- save_flags(flags);
- cli();
- while (busy) { /* someone else is allocating */
- sti(); /* Yes this is really needed here */
- now = jiffies; while (jiffies == now) /* wait a jiffy */;
- cli();
+ save_flags (flags);
+ cli ();
+ while (busy) { /* someone else is allocating */
+ sti (); /* Yes this is really needed here */
+ for (now = jiffies; now == jiffies; ); /* wait a jiffy */
+ cli ();
}
- busy = 1; /* not busy now; it's our turn */
+ busy = 1; /* not busy now; it's our turn */
- while (freescbs < needed) {
+ while (freescbs < needed) {
timeout = jiffies + WAITnexttimeout;
do {
- sti(); /* Yes this is really needed here */
- now = jiffies;
- while (jiffies == now); /* wait a jiffy */
- cli();
- } while (freescbs < needed && jiffies <= timeout);
+ sti (); /* Yes this is really needed here */
+ for (now = jiffies; now == jiffies; ); /* wait a jiffy */
+ cli ();
+ } while (freescbs < needed && jiffies <= timeout);
/*
* If we get here with enough free Scbs, we can take them.
* Otherwise, we timed out and didn't get enough.
*/
- if (freescbs < needed) {
+ if (freescbs < needed) {
busy = 0;
- panic("wd7000: can't get enough free SCBs.\n");
- restore_flags(flags);
- return NULL;
+ panic ("wd7000: can't get enough free SCBs.\n");
+ restore_flags (flags);
+ return (NULL);
}
}
- scb = scbfree; freescbs -= needed;
- for (i = 0; i < needed; i++) { p = scbfree; scbfree = p->next; }
+ scb = scbfree;
+ freescbs -= needed;
+ for (i = 0; i < needed; i++) {
+ p = scbfree;
+ scbfree = p->next;
+ }
p->next = NULL;
-
- busy = 0; /* we're done */
+ busy = 0; /* we're done */
- restore_flags(flags);
+ restore_flags (flags);
- return scb;
+ return (scb);
}
-static inline void free_scb( Scb *scb )
+static inline void free_scb (Scb *scb)
{
register unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags (flags);
+ cli ();
- memset(scb, 0, sizeof(Scb));
- scb->next = scbfree; scbfree = scb;
+ memset (scb, 0, sizeof (Scb));
+ scb->next = scbfree;
+ scbfree = scb;
freescbs++;
- restore_flags(flags);
+ restore_flags (flags);
}
-static inline void init_scbs(void)
+static inline void init_scbs (void)
{
int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_flags (flags);
+ cli ();
scbfree = &(scbs[0]);
- memset(scbs, 0, sizeof(scbs));
- for (i = 0; i < MAX_SCBS-1; i++) {
- scbs[i].next = &(scbs[i+1]); scbs[i].SCpnt = NULL;
+ memset (scbs, 0, sizeof (scbs));
+ for (i = 0; i < MAX_SCBS - 1; i++) {
+ scbs[i].next = &(scbs[i + 1]);
+ scbs[i].SCpnt = NULL;
}
- scbs[MAX_SCBS-1].next = NULL;
- scbs[MAX_SCBS-1].SCpnt = NULL;
+ scbs[MAX_SCBS - 1].next = NULL;
+ scbs[MAX_SCBS - 1].SCpnt = NULL;
+
+ restore_flags (flags);
+}
- restore_flags(flags);
-}
-
-static int mail_out( Adapter *host, Scb *scbptr )
+static int mail_out (Adapter *host, Scb *scbptr)
/*
* Note: this can also be used for ICBs; just cast to the parm type.
*/
@@ -866,30 +936,35 @@ static int mail_out( Adapter *host, Scb *scbptr )
unchar start_ogmb;
Mailbox *ogmbs = host->mb.ogmb;
int *next_ogmb = &(host->next_ogmb);
-#ifdef DEBUG
- printk("wd7000 mail_out: 0x%06lx",(long) scbptr);
+
+#ifdef WD7000_DEBUG
+ printk ("wd7000_mail_out: 0x%06lx", (long) scbptr);
#endif
+
/* We first look for a free outgoing mailbox */
- save_flags(flags);
- cli();
+ save_flags (flags);
+ cli ();
ogmb = *next_ogmb;
for (i = 0; i < OGMB_CNT; i++) {
- if (ogmbs[ogmb].status == 0) {
-#ifdef DEBUG
- printk(" using OGMB 0x%x",ogmb);
+ if (ogmbs[ogmb].status == 0) {
+#ifdef WD7000_DEBUG
+ printk (" using OGMB 0x%x", ogmb);
#endif
ogmbs[ogmb].status = 1;
- any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
+ any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
- *next_ogmb = (ogmb+1) % OGMB_CNT;
+ *next_ogmb = (ogmb + 1) % OGMB_CNT;
break;
- } else
+ }
+ else
ogmb = (++ogmb) % OGMB_CNT;
}
- restore_flags(flags);
-#ifdef DEBUG
- printk(", scb is 0x%06lx",(long) scbptr);
+ restore_flags (flags);
+
+#ifdef WD7000_DEBUG
+ printk (", scb is 0x%06lx", (long) scbptr);
#endif
+
if (i >= OGMB_CNT) {
/*
* Alternatively, we might issue the "interrupt on free OGMB",
@@ -899,171 +974,182 @@ static int mail_out( Adapter *host, Scb *scbptr )
* that marks OGMB's free, waiting even with interrupts off
* should work, since they are freed very quickly in most cases.
*/
- #ifdef DEBUG
- printk(", no free OGMBs.\n");
+#ifdef WD7000_DEBUG
+ printk (", no free OGMBs.\n");
#endif
- return 0;
+ return (0);
}
- wd7000_enable_intr(host);
+ wd7000_enable_intr (host);
start_ogmb = START_OGMB | ogmb;
- command_out( host, &start_ogmb, 1 );
-#ifdef DEBUG
- printk(", awaiting interrupt.\n");
+ command_out (host, &start_ogmb, 1);
+
+#ifdef WD7000_DEBUG
+ printk (", awaiting interrupt.\n");
#endif
- return 1;
+
+ return (1);
}
-int make_code(unsigned hosterr, unsigned scsierr)
-{
-#ifdef DEBUG
+int make_code (unsigned hosterr, unsigned scsierr)
+{
+#ifdef WD7000_DEBUG
int in_error = hosterr;
#endif
- switch ((hosterr>>8)&0xff){
- case 0: /* Reserved */
- hosterr = DID_ERROR;
- break;
- case 1: /* Command Complete, no errors */
- hosterr = DID_OK;
- break;
- case 2: /* Command complete, error logged in scb status (scsierr) */
- hosterr = DID_OK;
- break;
- case 4: /* Command failed to complete - timeout */
- hosterr = DID_TIME_OUT;
- break;
- case 5: /* Command terminated; Bus reset by external device */
- hosterr = DID_RESET;
- break;
- case 6: /* Unexpected Command Received w/ host as target */
- hosterr = DID_BAD_TARGET;
- break;
+ switch ((hosterr >> 8) & 0xff) {
+ case 0: /* Reserved */
+ hosterr = DID_ERROR;
+ break;
+ case 1: /* Command Complete, no errors */
+ hosterr = DID_OK;
+ break;
+ case 2: /* Command complete, error logged in scb status (scsierr) */
+ hosterr = DID_OK;
+ break;
+ case 4: /* Command failed to complete - timeout */
+ hosterr = DID_TIME_OUT;
+ break;
+ case 5: /* Command terminated; Bus reset by external device */
+ hosterr = DID_RESET;
+ break;
+ case 6: /* Unexpected Command Received w/ host as target */
+ hosterr = DID_BAD_TARGET;
+ break;
case 80: /* Unexpected Reselection */
case 81: /* Unexpected Selection */
- hosterr = DID_BAD_INTR;
- break;
+ hosterr = DID_BAD_INTR;
+ break;
case 82: /* Abort Command Message */
- hosterr = DID_ABORT;
- break;
+ hosterr = DID_ABORT;
+ break;
case 83: /* SCSI Bus Software Reset */
case 84: /* SCSI Bus Hardware Reset */
- hosterr = DID_RESET;
- break;
+ hosterr = DID_RESET;
+ break;
default: /* Reserved */
- hosterr = DID_ERROR;
- break;
- }
-#ifdef DEBUG
- if (scsierr||hosterr)
- printk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
- scsierr,in_error,hosterr);
+ hosterr = DID_ERROR;
+ }
+#ifdef WD7000_DEBUG
+ if (scsierr || hosterr)
+ printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
+ scsierr, in_error, hosterr);
#endif
- return scsierr | (hosterr << 16);
+ return (scsierr | (hosterr << 16));
}
-static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
+static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
{
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
#endif
+
SCpnt->SCp.phase = 0;
}
-#define wd7000_intr_ack(host) outb(0,host->iobase+ASC_INTR_ACK)
+#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
-void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
+void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
{
register int flag, icmb, errstatus, icmb_status;
register int host_error, scsi_error;
- register Scb *scb; /* for SCSI commands */
- register IcbAny *icb; /* for host commands */
+ register Scb *scb; /* for SCSI commands */
+ register IcbAny *icb; /* for host commands */
register Scsi_Cmnd *SCpnt;
- Adapter *host = irq2host[irq]; /* This MUST be set!!! */
+ Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata; /* This MUST be set!!! */
Mailbox *icmbs = host->mb.icmb;
-#ifdef DEBUG
- printk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
+ host->int_counter++;
+
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
#endif
- flag = inb(host->iobase+ASC_INTR_STAT);
-#ifdef DEBUG
- printk("wd7000_intr_handle: intr stat = 0x%02x\n",flag);
+ flag = inb (host->iobase + ASC_INTR_STAT);
+
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
#endif
- if (!(inb(host->iobase+ASC_STAT) & INT_IM)) {
+ if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
/* NB: these are _very_ possible if IRQ 15 is being used, since
- it's the "garbage collector" on the 2nd 8259 PIC. Specifically,
- any interrupt signal into the 8259 which can't be identified
- comes out as 7 from the 8259, which is 15 to the host. Thus, it
- is a good thing the WD7000 has an interrupt status port, so we
- can sort these out. Otherwise, electrical noise and other such
- problems would be indistinguishable from valid interrupts...
- */
-#ifdef DEBUG
- printk("wd7000_intr_handle: phantom interrupt...\n");
+ * it's the "garbage collector" on the 2nd 8259 PIC. Specifically,
+ * any interrupt signal into the 8259 which can't be identified
+ * comes out as 7 from the 8259, which is 15 to the host. Thus, it
+ * is a good thing the WD7000 has an interrupt status port, so we
+ * can sort these out. Otherwise, electrical noise and other such
+ * problems would be indistinguishable from valid interrupts...
+ */
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: phantom interrupt...\n");
#endif
- wd7000_intr_ack(host);
- return;
+ wd7000_intr_ack (host);
+ return;
}
- if (flag & MB_INTR) {
+ if (flag & MB_INTR) {
/* The interrupt is for a mailbox */
if (!(flag & IMB_INTR)) {
-#ifdef DEBUG
- printk("wd7000_intr_handle: free outgoing mailbox\n");
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: free outgoing mailbox\n");
#endif
/*
* If sleep_on() and the "interrupt on free OGMB" command are
* used in mail_out(), wake_up() should correspondingly be called
* here. For now, we don't need to do anything special.
*/
- wd7000_intr_ack(host);
+ wd7000_intr_ack (host);
return;
- } else {
+ }
+ else {
/* The interrupt is for an incoming mailbox */
icmb = flag & MB_MASK;
icmb_status = icmbs[icmb].status;
- if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
-#ifdef DEBUG
- printk("wd7000_intr_handle: unsolicited interrupt 0x%02xh\n",
- icmb_status);
+ if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
+ icmb_status);
#endif
- wd7000_intr_ack(host);
+ wd7000_intr_ack (host);
return;
}
- scb = (struct scb *) scsi2int((unchar *)icmbs[icmb].scbptr);
+ /* Aaaargh! (Zaga) */
+ scb = (struct scb *) (scsi2int ((unchar *) icmbs[icmb].scbptr) | PAGE_OFFSET);
icmbs[icmb].status = 0;
- if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */
+ if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */
SCpnt = scb->SCpnt;
- if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
+ if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
host_error = scb->vue | (icmb_status << 8);
scsi_error = scb->status;
- errstatus = make_code(host_error,scsi_error);
+ errstatus = make_code (host_error, scsi_error);
SCpnt->result = errstatus;
- free_scb(scb);
+ free_scb (scb);
- SCpnt->scsi_done(SCpnt);
+ SCpnt->scsi_done (SCpnt);
}
- } else { /* an ICB is done */
+ }
+ else { /* an ICB is done */
icb = (IcbAny *) scb;
icb->status = icmb_status;
- icb->phase = 0;
+ icb->phase = 0;
}
- } /* incoming mailbox */
+ } /* incoming mailbox */
}
- wd7000_intr_ack(host);
- return;
+ wd7000_intr_ack (host);
+
+#ifdef WD7000_DEBUG
+ printk ("wd7000_intr_handle: return from interrupt handler\n");
+#endif
}
-int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
{
register Scb *scb;
register Sgb *sgb;
@@ -1076,94 +1162,105 @@ int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
SCpnt->scsi_done = done;
SCpnt->SCp.phase = 1;
- scb = alloc_scbs(1);
+ scb = alloc_scbs (1);
scb->idlun = idlun;
- memcpy(scb->cdb, cdb, cdblen);
+ memcpy (scb->cdb, cdb, cdblen);
scb->direc = 0x40; /* Disable direction check */
- scb->SCpnt = SCpnt; /* so we can find stuff later */
+ scb->SCpnt = SCpnt; /* so we can find stuff later */
SCpnt->host_scribble = (unchar *) scb;
scb->host = host;
- if (SCpnt->use_sg) {
+ if (SCpnt->use_sg) {
struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
unsigned i;
- if (SCpnt->host->sg_tablesize == SG_NONE) {
- panic("wd7000_queuecommand: scatter/gather not supported.\n");
+ if (SCpnt->host->sg_tablesize == SG_NONE) {
+ panic ("wd7000_queuecommand: scatter/gather not supported.\n");
}
-#ifdef DEBUG
- printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg);
+#ifdef WD7000_DEBUG
+ printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
#endif
sgb = scb->sgb;
- scb->op = 1;
- any2scsi(scb->dataptr, (int) sgb);
- any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) );
+ scb->op = 1;
+ any2scsi (scb->dataptr, (int) sgb);
+ any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb));
- for (i = 0; i < SCpnt->use_sg; i++) {
- any2scsi(sgb[i].ptr, (int) sg[i].address);
- any2scsi(sgb[i].len, sg[i].length);
+ for (i = 0; i < SCpnt->use_sg; i++) {
+ any2scsi (sgb[i].ptr, (int) sg[i].address);
+ any2scsi (sgb[i].len, sg[i].length);
}
- } else {
+ }
+ else {
scb->op = 0;
- any2scsi(scb->dataptr, (int) SCpnt->request_buffer);
- any2scsi(scb->maxlen, SCpnt->request_bufflen);
+ any2scsi (scb->dataptr, (int) SCpnt->request_buffer);
+ any2scsi (scb->maxlen, SCpnt->request_bufflen);
}
- while (!mail_out(host, scb)) /* keep trying */;
- return 1;
+ while (!mail_out (host, scb)); /* keep trying */
+
+ return (1);
}
-int wd7000_command(Scsi_Cmnd *SCpnt)
+int wd7000_command (Scsi_Cmnd *SCpnt)
{
- wd7000_queuecommand(SCpnt, wd7000_scsi_done);
+ wd7000_queuecommand (SCpnt, wd7000_scsi_done);
- while (SCpnt->SCp.phase > 0) barrier(); /* phase counts scbs down to 0 */
+ while (SCpnt->SCp.phase > 0)
+ barrier (); /* phase counts scbs down to 0 */
- return SCpnt->result;
+ return (SCpnt->result);
}
-int wd7000_diagnostics( Adapter *host, int code )
+int wd7000_diagnostics (Adapter *host, int code)
{
static IcbDiag icb = {ICB_OP_DIAGNOSTICS};
static unchar buf[256];
unsigned long timeout;
icb.type = code;
- any2scsi(icb.len, sizeof(buf));
- any2scsi(icb.ptr, (int) &buf);
+ any2scsi (icb.len, sizeof (buf));
+ any2scsi (icb.ptr, (int) &buf);
icb.phase = 1;
/*
* This routine is only called at init, so there should be OGMBs
* available. I'm assuming so here. If this is going to
* fail, I can just let the timeout catch the failure.
*/
- mail_out(host, (struct scb *) &icb);
- timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */
+ mail_out (host, (struct scb *) &icb);
+ timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */
while (icb.phase && jiffies < timeout)
- barrier(); /* wait for completion */
+ barrier (); /* wait for completion */
- if (icb.phase) {
- printk("wd7000_diagnostics: timed out.\n");
- return 0;
+ if (icb.phase) {
+ printk ("wd7000_diagnostics: timed out.\n");
+ return (0);
}
- if (make_code(icb.vue|(icb.status << 8),0)) {
- printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",
- icb.vue, icb.status);
- return 0;
+ if (make_code (icb.vue | (icb.status << 8), 0)) {
+ printk ("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",
+ icb.vue, icb.status);
+ return (0);
}
- return 1;
+ return (1);
}
-int wd7000_init( Adapter *host )
+int wd7000_init (Adapter *host)
{
- InitCmd init_cmd = {
- INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, {0,0,0}, OGMB_CNT, ICMB_CNT
+ InitCmd init_cmd =
+ {
+ INITIALIZATION,
+ 7,
+ host->bus_on,
+ host->bus_off,
+ 0,
+ { 0, 0, 0 },
+ OGMB_CNT,
+ ICMB_CNT
};
int diag;
@@ -1171,84 +1268,78 @@ int wd7000_init( Adapter *host )
* Reset the adapter - only. The SCSI bus was initialized at power-up,
* and we need to do this just so we control the mailboxes, etc.
*/
- outb(ASC_RES, host->iobase+ASC_CONTROL);
- delay(1); /* reset pulse: this is 10ms, only need 25us */
- outb(0,host->iobase+ASC_CONTROL);
- host->control = 0; /* this must always shadow ASC_CONTROL */
-
- if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
- printk ("wd7000_init: WAIT timed out.\n");
- return 0; /* 0 = not ok */
+ outb (ASC_RES, host->iobase + ASC_CONTROL);
+ delay (1); /* reset pulse: this is 10ms, only need 25us */
+ outb (0, host->iobase + ASC_CONTROL);
+ host->control = 0; /* this must always shadow ASC_CONTROL */
+
+ if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+ printk ("wd7000_init: WAIT timed out.\n");
+ return (0); /* 0 = not ok */
}
- if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) {
- printk("wd7000_init: ");
-
- switch (diag) {
- case 2:
- printk("RAM failure.\n");
- break;
- case 3:
- printk("FIFO R/W failed\n");
- break;
- case 4:
- printk("SBIC register R/W failed\n");
- break;
- case 5:
- printk("Initialization D-FF failed.\n");
- break;
- case 6:
- printk("Host IRQ D-FF failed.\n");
- break;
- case 7:
- printk("ROM checksum error.\n");
- break;
- default:
- printk("diagnostic code 0x%02Xh received.\n", diag);
+ if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {
+ printk ("wd7000_init: ");
+
+ switch (diag) {
+ case 2: printk ("RAM failure.\n");
+ break;
+ case 3: printk ("FIFO R/W failed\n");
+ break;
+ case 4: printk ("SBIC register R/W failed\n");
+ break;
+ case 5: printk ("Initialization D-FF failed.\n");
+ break;
+ case 6: printk ("Host IRQ D-FF failed.\n");
+ break;
+ case 7: printk ("ROM checksum error.\n");
+ break;
+ default: printk ("diagnostic code 0x%02Xh received.\n", diag);
}
- return 0;
+ return (0);
}
-
+
/* Clear mailboxes */
- memset(&(host->mb), 0, sizeof(host->mb));
+ memset (&(host->mb), 0, sizeof (host->mb));
/* Execute init command */
- any2scsi((unchar *) &(init_cmd.mailboxes), (int) &(host->mb));
- if (!command_out(host, (unchar *) &init_cmd, sizeof(init_cmd))) {
- printk("wd7000_init: adapter initialization failed.\n");
- return 0;
+ any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
+ if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {
+ printk ("wd7000_init: adapter initialization failed.\n");
+ return (0);
}
- if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
- printk ("wd7000_init: WAIT timed out.\n");
- return 0;
+ if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
+ printk ("wd7000_init: WAIT timed out.\n");
+ return (0);
}
- if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
- printk("wd7000_init: can't get IRQ %d.\n", host->irq);
- return 0;
+ if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
+ printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
+ return (0);
}
- if (request_dma(host->dma,"wd7000")) {
- printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
- free_irq(host->irq, NULL);
- return 0;
+ if (request_dma (host->dma, "wd7000")) {
+ printk ("wd7000_init: can't get DMA channel %d.\n", host->dma);
+ free_irq (host->irq, NULL);
+ return (0);
}
- wd7000_enable_dma(host);
- wd7000_enable_intr(host);
+ wd7000_enable_dma (host);
+ wd7000_enable_intr (host);
- if (!wd7000_diagnostics(host,ICB_DIAG_FULL)) {
- free_dma(host->dma);
- free_irq(host->irq, NULL);
- return 0;
+ if (!wd7000_diagnostics (host, ICB_DIAG_FULL)) {
+ free_dma (host->dma);
+ free_irq (host->irq, NULL);
+ return (0);
}
- return 1;
+ return (1);
}
-void wd7000_revision(Adapter *host)
+void wd7000_revision (Adapter *host)
{
- static IcbRevLvl icb = {ICB_OP_GET_REVISION};
+ static IcbRevLvl icb =
+ {ICB_OP_GET_REVISION};
icb.phase = 1;
/*
@@ -1257,14 +1348,160 @@ void wd7000_revision(Adapter *host)
* the only damage will be that the revision will show up as 0.0,
* which in turn means that scatter/gather will be disabled.
*/
- mail_out(host, (struct scb *) &icb);
+ mail_out (host, (struct scb *) &icb);
while (icb.phase)
- barrier(); /* wait for completion */
+ barrier (); /* wait for completion */
host->rev1 = icb.primary;
host->rev2 = icb.secondary;
}
+#undef SPRINTF
+#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
+
+int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host)
+{
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+#ifdef WD7000_DEBUG
+ printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
+#endif
+
+ /*
+ * Currently this is a no-op
+ */
+ printk ("Sorry, this function is currently out of order...\n");
+
+ restore_flags (flags);
+
+ return (length);
+}
+
+
+int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+ struct Scsi_Host *host = NULL;
+ Scsi_Device *scd;
+ Adapter *adapter;
+ unsigned long flags;
+ char *pos = buffer;
+ short i;
+
+#ifdef WD7000_DEBUG
+ Mailbox *ogmbs, *icmbs;
+ short count;
+#endif
+
+ /*
+ * Find the specified host board.
+ */
+ for (i = 0; i < IRQS; i++)
+ if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
+ host = wd7000_host[i];
+
+ break;
+ }
+
+ /*
+ * Host not found!
+ */
+ if (! host)
+ return (-ESRCH);
+
+ /*
+ * Has data been written to the file ?
+ */
+ if (inout)
+ return (wd7000_set_info (buffer, length, host));
+
+ adapter = (Adapter *) host->hostdata;
+
+ save_flags (flags);
+ cli ();
+
+ SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
+ SPRINTF (" IO base: 0x%x\n", adapter->iobase);
+ SPRINTF (" IRQ: %d\n", adapter->irq);
+ SPRINTF (" DMA channel: %d\n", adapter->dma);
+ SPRINTF (" Interrupts: %d\n", adapter->int_counter);
+ SPRINTF (" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
+ SPRINTF (" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
+
+#ifdef WD7000_DEBUG
+ ogmbs = adapter->mb.ogmb;
+ icmbs = adapter->mb.icmb;
+
+ SPRINTF ("\nControl port value: 0x%x\n", adapter->control);
+ SPRINTF ("Incoming mailbox:\n");
+ SPRINTF (" size: %d\n", ICMB_CNT);
+ SPRINTF (" queued messages: ");
+
+ for (i = count = 0; i < ICMB_CNT; i++)
+ if (icmbs[i].status) {
+ count++;
+ SPRINTF ("0x%x ", i);
+ }
+
+ SPRINTF (count ? "\n" : "none\n");
+
+ SPRINTF ("Outgoing mailbox:\n");
+ SPRINTF (" size: %d\n", OGMB_CNT);
+ SPRINTF (" next message: 0x%x\n", adapter->next_ogmb);
+ SPRINTF (" queued messages: ");
+
+ for (i = count = 0; i < OGMB_CNT; i++)
+ if (ogmbs[i].status) {
+ count++;
+ SPRINTF ("0x%x ", i);
+ }
+
+ SPRINTF (count ? "\n" : "none\n");
+#endif
+
+ /*
+ * Display driver information for each device attached to the board.
+ */
+ scd = host->host_queue;
+
+ SPRINTF ("\nAttached devices: %s\n", scd ? "" : "none");
+
+ for ( ; scd; scd = scd->next)
+ if (scd->host->host_no == hostno) {
+ SPRINTF (" [Channel: %02d, Id: %02d, Lun: %02d] ",
+ scd->channel, scd->id, scd->lun);
+ SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
+ scsi_device_types[(short) scd->type] : "Unknown device");
+
+ for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
+ SPRINTF ("%c", scd->vendor[i]);
+ SPRINTF (" ");
+
+ for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
+ SPRINTF ("%c", scd->model[i]);
+ SPRINTF ("\n");
+ }
+
+ SPRINTF ("\n");
+
+ restore_flags (flags);
+
+ /*
+ * Calculate start of next buffer, and return value.
+ */
+ *start = buffer + offset;
+
+ if ((pos - buffer) < offset)
+ return (0);
+ else if ((pos - buffer - offset) < length)
+ return (pos - buffer - offset);
+ else
+ return (length);
+}
+
+
/*
* Returns the number of adapters this driver is supporting.
*
@@ -1277,84 +1514,102 @@ void wd7000_revision(Adapter *host)
*/
int wd7000_detect (Scsi_Host_Template *tpnt)
{
- short present = 0, biosaddr_ptr, cfg_ptr, sig_ptr, i, pass;
+ short present = 0, biosaddr_ptr, sig_ptr, i, pass;
short biosptr[NUM_CONFIGS];
unsigned iobase;
Adapter *host = NULL;
struct Scsi_Host *sh;
- for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
+#ifdef WD7000_DEBUG
+ printk ("wd7000_detect: started\n");
+#endif
+
+ for (i = 0; i < IRQS; wd7000_host[i++] = NULL) ;
+ for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ;
tpnt->proc_dir = &proc_scsi_wd7000;
+ tpnt->proc_info = &wd7000_proc_info;
/*
* Set up SCB free list, which is shared by all adapters
*/
init_scbs ();
- for (pass = 0, cfg_ptr = 0; pass < NUM_CONFIGS; pass++) {
- for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
+ for (pass = 0; pass < NUM_CONFIGS; pass++) {
+ /*
+ * First, search for BIOS SIGNATURE...
+ */
+ for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
- for (i = 0; i < pass; i++)
- if (biosptr[i] == biosaddr_ptr)
- break;
-
- if ((i == pass) &&
- check_signature(wd7000_biosaddr[biosaddr_ptr] +
- signatures[sig_ptr].ofs,
- signatures[sig_ptr].sig,
- signatures[sig_ptr].len))
- goto bios_matched;
- }
+ for (i = 0; i < pass; i++)
+ if (biosptr[i] == biosaddr_ptr)
+ break;
-bios_matched:
+ if (i == pass) {
+#if (LINUX_VERSION_CODE < 0x020100)
+#else
+ void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] +
+ signatures[sig_ptr].ofs,
+ signatures[sig_ptr].len);
+#endif
+ short bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig,
+ signatures[sig_ptr].len);
+
+#if (LINUX_VERSION_CODE < 0x020100)
+#else
+ iounmap (biosaddr);
+#endif
-#ifdef DEBUG
+ if (! bios_match)
+ goto bios_matched;
+ }
+ }
+
+ bios_matched:
+ /*
+ * BIOS SIGNATURE has been found.
+ */
+#ifdef WD7000_DEBUG
printk ("wd7000_detect: pass %d\n", pass + 1);
- if (biosaddr_ptr == NUM_ADDRS)
+ if (biosaddr_ptr == NUM_ADDRS)
printk ("WD-7000 SST BIOS not detected...\n");
else
printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
- wd7000_biosaddr[biosaddr_ptr]);
+ wd7000_biosaddr[biosaddr_ptr]);
#endif
- if (wd7000_card_num)
- iobase = wd7000_setupIO[wd7000_card_num - 1];
- else {
- if (configs[cfg_ptr++].irq < 0)
- continue;
+ if (configs[pass].irq < 0)
+ continue;
- iobase = configs[cfg_ptr - 1].iobase;
- }
+ iobase = configs[pass].iobase;
-#ifdef DEBUG
- printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
+#ifdef WD7000_DEBUG
+ printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
#endif
- if (! check_region (iobase, 4)) {
+ if (!check_region (iobase, 4)) {
-#ifdef DEBUG
- printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
+#ifdef WD7000_DEBUG
+ printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
#endif
-
- /*
- * ASC reset...
- */
- outb (ASC_RES, iobase + ASC_CONTROL);
- delay (1);
- outb (0, iobase + ASC_CONTROL);
-
- if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
-#ifdef DEBUG
- {
- printk ("failed!\n");
- continue;
- }
- else
- printk ("ok!\n");
+ /*
+ * ASC reset...
+ */
+ outb (ASC_RES, iobase + ASC_CONTROL);
+ delay (1);
+ outb (0, iobase + ASC_CONTROL);
+
+ if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
+#ifdef WD7000_DEBUG
+ {
+ printk ("failed!\n");
+ continue;
+ }
+ else
+ printk ("ok!\n");
#else
- continue;
+ continue;
#endif
if (inb (iobase + ASC_INTR_STAT) == 1) {
@@ -1368,33 +1623,27 @@ bios_matched:
sh = scsi_register (tpnt, sizeof (Adapter));
host = (Adapter *) sh->hostdata;
-#ifdef DEBUG
- printk ("wd7000_detect: adapter allocated at 0x%x\n",
- (int) host);
+#ifdef WD7000_DEBUG
+ printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
#endif
memset (host, 0, sizeof (Adapter));
- if (wd7000_card_num) {
- host->irq = wd7000_setupIRQ[--wd7000_card_num];
- host->dma = wd7000_setupDMA[wd7000_card_num];
- }
- else {
- host->irq = configs[cfg_ptr - 1].irq;
- host->dma = configs[cfg_ptr - 1].dma;
- }
-
- host->sh = sh;
- host->iobase = iobase;
- irq2host[host->irq] = host;
+ host->irq = configs[pass].irq;
+ host->dma = configs[pass].dma;
+ host->iobase = iobase;
+ host->int_counter = 0;
+ host->bus_on = configs[pass].bus_on;
+ host->bus_off = configs[pass].bus_off;
+ host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
printk ("wd7000_detect: Trying init WD-7000 card at IO "
"0x%x, IRQ %d, DMA %d...\n",
host->iobase, host->irq, host->dma);
#endif
- if (! wd7000_init (host)) { /* Initialization failed */
+ if (!wd7000_init (host)) { /* Initialization failed */
scsi_unregister (sh);
continue;
@@ -1403,7 +1652,7 @@ bios_matched:
/*
* OK from here - we'll use this adapter/configuration.
*/
- wd7000_revision (host); /* important for scatter/gather */
+ wd7000_revision (host); /* important for scatter/gather */
/*
* Register our ports.
@@ -1411,34 +1660,34 @@ bios_matched:
request_region (host->iobase, 4, "wd7000");
/*
- * For boards before rev 6.0, scatter/gather
- * isn't supported.
+ * For boards before rev 6.0, scatter/gather isn't supported.
*/
if (host->rev1 < 6)
sh->sg_tablesize = SG_NONE;
- present++; /* count it */
+ present++; /* count it */
if (biosaddr_ptr != NUM_ADDRS)
biosptr[pass] = biosaddr_ptr;
printk ("Western Digital WD-7000 (rev %d.%d) ",
host->rev1, host->rev2);
- printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
+ printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
host->iobase, host->irq, host->dma);
+ printk (" BUS_ON time: %dns, BUS_OFF time: %dns\n",
+ host->bus_on * 125, host->bus_off * 125);
}
}
-#ifdef DEBUG
+#ifdef WD7000_DEBUG
else
- printk ("wd7000_detect: IO 0x%x region already allocated!\n",
- iobase);
+ printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
#endif
}
- if (! present)
- printk ("Failed initialization of WD-7000 SCSI card!\n");
+ if (!present)
+ printk ("Failed initialization of WD-7000 SCSI card!\n");
return (present);
}
@@ -1447,42 +1696,81 @@ bios_matched:
/*
* I have absolutely NO idea how to do an abort with the WD7000...
*/
-int wd7000_abort(Scsi_Cmnd * SCpnt)
+int wd7000_abort (Scsi_Cmnd *SCpnt)
{
Adapter *host = (Adapter *) SCpnt->host->hostdata;
- if (inb(host->iobase+ASC_STAT) & INT_IM) {
- printk("wd7000_abort: lost interrupt\n");
- wd7000_intr_handle(host->irq, NULL, NULL);
- return SCSI_ABORT_SUCCESS;
+ if (inb (host->iobase + ASC_STAT) & INT_IM) {
+ printk ("wd7000_abort: lost interrupt\n");
+ wd7000_intr_handle (host->irq, NULL, NULL);
+
+ return (SCSI_ABORT_SUCCESS);
}
- return SCSI_ABORT_SNOOZE;
+ return (SCSI_ABORT_SNOOZE);
}
/*
* I also have no idea how to do a reset...
*/
-int wd7000_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
+int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused)
{
- return SCSI_RESET_PUNT;
+ return (SCSI_RESET_PUNT);
}
/*
- * This was borrowed directly from aha1542.c, but my disks are organized
- * this way, so I think it will work OK. Someone who is ambitious can
- * borrow a newer or more complete version from another driver.
+ * This was borrowed directly from aha1542.c. (Zaga)
*/
-int wd7000_biosparam(Disk * disk, kdev_t dev, int* ip)
+int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
{
- int size = disk->capacity;
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = size >> 11;
-/* if (ip[2] >= 1024) ip[2] = 1024; */
- return 0;
+#ifdef WD7000_DEBUG
+ printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
+#endif
+
+ /*
+ * try default translation
+ */
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = disk->capacity / (64 * 32);
+
+ /*
+ * for disks >1GB do some guessing
+ */
+ if (ip[2] >= 1024) {
+ int info[3];
+
+ /*
+ * try to figure out the geometry from the partition table
+ */
+ if ((scsicam_bios_param (disk, dev, info) < 0) ||
+ !(((info[0] == 64) && (info[1] == 32)) ||
+ ((info[0] == 255) && (info[1] == 63)))) {
+ printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n"
+ " using extended translation.\n");
+
+ ip[0] = 255;
+ ip[1] = 63;
+ ip[2] = disk->capacity / (255 * 63);
+ }
+ else {
+ ip[0] = info[0];
+ ip[1] = info[1];
+ ip[2] = info[2];
+
+ if (info[0] == 255)
+ printk ("wd7000_biosparam: current partition table is using extended translation.\n");
+ }
+ }
+
+#ifdef WD7000_DEBUG
+ printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+ printk ("WARNING: check, if the bios geometry is correct.\n");
+#endif
+
+ return (0);
}
#ifdef MODULE
diff --git a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h
index 8835e5f50..73679c24a 100644
--- a/drivers/scsi/wd7000.h
+++ b/drivers/scsi/wd7000.h
@@ -8,17 +8,23 @@
* This file has been reduced to only the definitions needed for the
* WD7000 host structure.
*
+ * Revision by Miroslav Zagorac <zaga@fly.cc.fer.hr> Jun 1997.
*/
#include <linux/types.h>
#include <linux/kdev_t.h>
-int wd7000_detect(Scsi_Host_Template *);
-int wd7000_command(Scsi_Cmnd *);
-int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd7000_abort(Scsi_Cmnd *);
-int wd7000_reset(Scsi_Cmnd *, unsigned int);
-int wd7000_biosparam(Disk *, kdev_t, int *);
+extern struct proc_dir_entry proc_scsi_wd7000;
+
+
+int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host);
+int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+int wd7000_detect (Scsi_Host_Template *);
+int wd7000_command (Scsi_Cmnd *);
+int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd7000_abort (Scsi_Cmnd *);
+int wd7000_reset (Scsi_Cmnd *, unsigned int);
+int wd7000_biosparam (Disk *, kdev_t, int *);
#ifndef NULL
#define NULL 0L
@@ -38,18 +44,22 @@ int wd7000_biosparam(Disk *, kdev_t, int *);
#define WD7000_Q 16
#define WD7000_SG 16
-#define WD7000 { \
- name: "Western Digital WD-7000", \
- detect: wd7000_detect, \
- command: wd7000_command, \
- queuecommand: wd7000_queuecommand, \
- abort: wd7000_abort, \
- reset: wd7000_reset, \
- bios_param: wd7000_biosparam, \
- can_queue: WD7000_Q, \
- this_id: 7, \
- sg_tablesize: WD7000_SG, \
- cmd_per_lun: 1, \
- unchecked_isa_dma: 1, \
- use_clustering: ENABLE_CLUSTERING}
+#define WD7000 { \
+ proc_dir: &proc_scsi_wd7000, \
+ proc_info: wd7000_proc_info, \
+ name: "Western Digital WD-7000", \
+ detect: wd7000_detect, \
+ command: wd7000_command, \
+ queuecommand: wd7000_queuecommand, \
+ abort: wd7000_abort, \
+ reset: wd7000_reset, \
+ bios_param: wd7000_biosparam, \
+ can_queue: WD7000_Q, \
+ this_id: 7, \
+ sg_tablesize: WD7000_SG, \
+ cmd_per_lun: 1, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
+}
#endif
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index 7ef5f8dd4..d4678da82 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -6,6 +6,8 @@ fi
dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
if [ "$CONFIG_SB" = "y" ]; then
+ bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES
+ bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE
hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index e8ec0b12d..6b09e336b 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -117,22 +117,6 @@ else
endif
endif
-ifeq ($(CONFIG_MPU401),y)
-LX_OBJS += mpu401.o
-else
- ifeq ($(CONFIG_MPU401),m)
- MX_OBJS += mpu401.o
- else
- ifeq ($(CONFIG_MPU_EMU),y)
- LX_OBJS += mpu401.o
- else
- ifeq ($(CONFIG_MPU_EMU),m)
- MX_OBJS += mpu401.o
- endif
- endif
- endif
-endif
-
ifeq ($(CONFIG_UART401),y)
LX_OBJS += uart401.o
else
@@ -159,9 +143,31 @@ endif
ifeq ($(CONFIG_SSCAPE),y)
L_OBJS += sscape.o
+LX_OBJS += ad1848.o
+CONFIG_MPU401 = y
else
ifeq ($(CONFIG_SSCAPE),m)
M_OBJS += sscape.o
+ MX_OBJS += ad1848.o
+ ifneq ($(CONFIG_MPU401),y)
+ CONFIG_MPU401 = m
+ endif
+ endif
+endif
+
+ifeq ($(CONFIG_MPU401),y)
+LX_OBJS += mpu401.o
+else
+ ifeq ($(CONFIG_MPU401),m)
+ MX_OBJS += mpu401.o
+ else
+ ifeq ($(CONFIG_MPU_EMU),y)
+ LX_OBJS += mpu401.o
+ else
+ ifeq ($(CONFIG_MPU_EMU),m)
+ MX_OBJS += mpu401.o
+ endif
+ endif
endif
endif
@@ -265,7 +271,7 @@ CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE))
maui.o: maui_boot.h
maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex
- bin2hex maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
+ bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
@ ( \
echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \
echo 'FILES_BOOT_UP_TO_DATE += $@'; \
@@ -297,7 +303,7 @@ CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE))
trix.o: trix_boot.h
trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex
- hex2hex trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
+ hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
@ ( \
echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \
echo 'FILES_BOOT_UP_TO_DATE += $@'; \
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
index 6fdec35ec..d839ed208 100644
--- a/drivers/sound/ad1848.c
+++ b/drivers/sound/ad1848.c
@@ -23,6 +23,12 @@
*/
/*
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * general sleep/wakeup clean up.
+ * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free
+ * of irqs. Use dev_id.
+ *
+ * Status:
+ * Tested. Believed fully functional.
*/
#include <linux/config.h>
@@ -144,9 +150,9 @@ static void ad1848_tmr_reprogram(int dev);
static int ad_read(ad1848_info * devc, int reg)
{
- unsigned long flags;
- int x;
- int timeout = 900000;
+ unsigned long flags;
+ int x;
+ int timeout = 900000;
while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */
timeout--;
@@ -163,11 +169,10 @@ static int ad_read(ad1848_info * devc, int reg)
static void ad_write(ad1848_info * devc, int reg, int data)
{
- unsigned long flags;
- int timeout = 900000;
+ unsigned long flags;
+ int timeout = 900000;
- while (timeout > 0 &&
- inb(devc->base) == 0x80) /*Are we initializing */
+ while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */
timeout--;
save_flags(flags);
@@ -180,7 +185,7 @@ static void ad_write(ad1848_info * devc, int reg, int data)
static void wait_for_calibration(ad1848_info * devc)
{
- int timeout = 0;
+ int timeout = 0;
/*
* Wait until the auto calibration process has finished.
@@ -1751,7 +1756,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
else
devc->audio_flags |= DMA_DUPLEX;
}
-
+
+ portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);
+ if(portc==NULL)
+ return -1;
+
if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
dev_name,
&ad1848_audio_driver,
@@ -1762,12 +1771,11 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
dma_playback,
dma_capture)) < 0)
{
+ kfree(portc);
+ portc=NULL;
return -1;
}
- portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info)));
- sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info);
- if (sound_nblocks < 1024)
- sound_nblocks++;;
+
audio_devs[my_dev]->portc = portc;
memset((char *) portc, 0, sizeof(*portc));
@@ -1777,23 +1785,21 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
if (irq > 0)
{
- irq2dev[irq] = devc->dev_no = my_dev;
- if (snd_set_irq_handler(devc->irq, adintr,
- devc->name,
- NULL) < 0)
+ devc->dev_no = my_dev;
+ if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0)
{
- printk(KERN_WARNING "ad1848: IRQ in use\n");
+ printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n");
}
if (devc->model != MD_1848 && devc->model != MD_C930)
{
- int x;
- unsigned char tmp = ad_read(devc, 16);
+ int x;
+ unsigned char tmp = ad_read(devc, 16);
devc->timer_ticks = 0;
ad_write(devc, 21, 0x00); /* Timer MSB */
ad_write(devc, 20, 0x10); /* Timer LSB */
-
+#ifndef __SMP__
ad_write(devc, 16, tmp | 0x40); /* Enable timer */
for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
ad_write(devc, 16, tmp & ~0x40); /* Disable timer */
@@ -1805,6 +1811,9 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
DDB(printk("Interrupt test OK\n"));
devc->irq_ok = 1;
}
+#else
+ devc->irq_ok=1;
+#endif
}
else
devc->irq_ok = 1; /* Couldn't test. assume it's OK */
@@ -1840,7 +1849,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
void ad1848_control(int cmd, int arg)
{
- ad1848_info *devc;
+ ad1848_info *devc;
if (nr_ad1848_devs < 1)
return;
@@ -1850,7 +1859,7 @@ void ad1848_control(int cmd, int arg)
switch (cmd)
{
case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */
- if (devc->model != MD_1845)
+ if (devc->model != MD_1845)
return;
ad_enter_MCE(devc);
ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5));
@@ -1859,8 +1868,8 @@ void ad1848_control(int cmd, int arg)
case AD1848_MIXER_REROUTE:
{
- int o = (arg >> 8) & 0xff;
- int n = arg & 0xff;
+ int o = (arg >> 8) & 0xff;
+ int n = arg & 0xff;
if (n == SOUND_MIXER_NONE)
{ /* Just hide this control */
@@ -1906,12 +1915,14 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
if (devc != NULL)
{
+ if(audio_devs[dev]->portc!=NULL)
+ kfree(audio_devs[dev]->portc);
release_region(devc->base, 4);
if (!share_dma)
{
if (irq > 0)
- snd_release_irq(devc->irq);
+ free_irq(devc->irq, NULL);
sound_free_dma(audio_devs[dev]->dmap_out->dma);
@@ -1926,35 +1937,15 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
void adintr(int irq, void *dev_id, struct pt_regs *dummy)
{
- unsigned char status;
- ad1848_info *devc;
- int dev;
- int alt_stat = 0xff;
- unsigned char c930_stat = 0;
- int cnt = 0;
-
- if (irq < 0 || irq > 15)
- {
- dev = -1;
- }
- else
- dev = irq2dev[irq];
-
- if (dev < 0 || dev >= num_audiodevs)
- {
- for (irq = 0; irq < 17; irq++)
- if (irq2dev[irq] != -1)
- break;
-
- if (irq > 15)
- {
- /* printk("ad1848.c: Bogus interrupt %d\n", irq); */
- return;
- }
- dev = irq2dev[irq];
- devc = (ad1848_info *) audio_devs[dev]->devc;
- } else
- devc = (ad1848_info *) audio_devs[dev]->devc;
+ unsigned char status;
+ ad1848_info *devc;
+ int dev;
+ int alt_stat = 0xff;
+ unsigned char c930_stat = 0;
+ int cnt = 0;
+
+ dev = (int)dev_id;
+ devc = (ad1848_info *) audio_devs[dev]->devc;
interrupt_again: /* Jump back here if int status doesn't reset */
@@ -2542,12 +2533,12 @@ EXPORT_SYMBOL(unload_ms_sound);
#ifdef MODULE
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-MODULE_PARM(dma2, "i");
-MODULE_PARM(type, "i");
-MODULE_PARM(deskpro_xl, "i");
+MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */
+MODULE_PARM(irq, "i"); /* IRQ to use */
+MODULE_PARM(dma, "i"); /* First DMA channel */
+MODULE_PARM(dma2, "i"); /* Second DMA channel */
+MODULE_PARM(type, "i"); /* Card type */
+MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */
int io = -1;
int irq = -1;
diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c
index b27b1999a..9c9ccf095 100644
--- a/drivers/sound/audio.c
+++ b/drivers/sound/audio.c
@@ -21,7 +21,6 @@
#include <linux/config.h>
#include <linux/stddef.h>
-#include <linux/kerneld.h>
#include "sound_config.h"
diff --git a/drivers/sound/bin2hex.c b/drivers/sound/bin2hex.c
index 351dd24e0..fc49c99d9 100644
--- a/drivers/sound/bin2hex.c
+++ b/drivers/sound/bin2hex.c
@@ -2,12 +2,27 @@
int main( int argc, const char * argv [] )
{
- const char * varname = argv[1];
+ const char * varname;
int i = 0;
int c;
+ int id = 0;
+ if(argv[1] && strcmp(argv[1],"-i")==0)
+ {
+ argv++;
+ argc--;
+ id=1;
+ }
+
+ if(argc==1)
+ {
+ fprintf(stderr, "bin2hex: [-i] firmware\n");
+ exit(1);
+ }
+
+ varname = argv[1];
printf( "/* automatically generated by bin2hex */\n" );
- printf( "static unsigned char %s [] =\n{\n", varname );
+ printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":"");
while ( ( c = getchar( ) ) != EOF )
{
diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c
index c8732dfe4..fdb5b738c 100644
--- a/drivers/sound/cs4232.c
+++ b/drivers/sound/cs4232.c
@@ -12,7 +12,14 @@
* CS4232
* CS4236
* CS4236B
+ *
+ * Note: You will need a PnP config setup to initialise some CS4232 boards
+ * anyway.
+ *
+ * Changes
+ * Alan Cox Modularisation, Basic cleanups.
*/
+
/*
* Copyright (C) by Hannu Savolainen 1993-1997
*
@@ -20,6 +27,7 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
+
#include <linux/config.h>
#include <linux/module.h>
@@ -99,6 +107,8 @@ int probe_cs4232(struct address_info *hw_config)
* just one CS4232 compatible device can exist on the system. Also this
* method conflicts with possible PnP support in the OS. For this reason
* driver is just a temporary kludge.
+ *
+ * Also the Cirrus/Crystal method doesnt always work. Try ISAPnP first ;)
*/
/*
@@ -106,8 +116,8 @@ int probe_cs4232(struct address_info *hw_config)
* first time.
*/
- for (n = 0; n < 4; n++) {
-
+ for (n = 0; n < 4; n++)
+ {
/*
* Wake up the card by sending a 32 byte Crystal key to the key port.
*/
@@ -298,8 +308,7 @@ struct address_info cfg;
* loaded ready.
*/
-int
-init_module(void)
+int init_module(void)
{
if (io == -1 || irq == -1 || dma == -1 || dma2 == -1)
{
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 666d7765e..7f3957bfd 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -148,9 +148,6 @@ void sound_unload_drivers(void)
}
}
- for (i=0;i<num_audiodevs;i++)
- DMAbuf_deinit(i);
-
if (trace_init)
printk(KERN_DEBUG "Sound unload complete\n");
}
diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c
index 151e20449..db6a02d05 100644
--- a/drivers/sound/dmabuf.c
+++ b/drivers/sound/dmabuf.c
@@ -104,7 +104,7 @@ static int sound_alloc_dmap(struct dma_buffparms *dmap)
dmap->raw_buf_phys = virt_to_bus(start_addr);
for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++)
- set_bit(PG_reserved, &mem_map[i].flags);;
+ set_bit(PG_reserved, &mem_map[i].flags);
return 0;
}
@@ -115,8 +115,6 @@ static void sound_free_dmap(struct dma_buffparms *dmap)
if (dmap->raw_buf == NULL)
return;
- if (dmap->mapping_flags & DMA_MAP_MAPPED)
- return; /* Don't free mmapped buffer. Will use it next time */
for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);
start_addr = (unsigned long) dmap->raw_buf;
@@ -127,6 +125,8 @@ static void sound_free_dmap(struct dma_buffparms *dmap)
free_pages((unsigned long) dmap->raw_buf, sz);
dmap->raw_buf = NULL;
+ /* Remember the buffer is deleted so we dont Oops later */
+ dmap->fragment_size = 0;
}
@@ -206,6 +206,7 @@ static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
disable_dma(dmap->dma);
+ sound_free_dmap(dmap);
}
@@ -832,12 +833,12 @@ int DMAbuf_move_wrpointer(int dev, int l)
dmap->user_counter += l;
dmap->flags |= DMA_DIRTY;
- if (dmap->user_counter >= dmap->max_byte_counter) {
+ if (dmap->byte_counter >= dmap->max_byte_counter) {
/* Wrap the byte counters */
- long decr = dmap->user_counter;
- dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
- decr -= dmap->user_counter;
- dmap->byte_counter -= decr;
+ long decr = dmap->byte_counter;
+ dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
+ decr -= dmap->byte_counter;
+ dmap->user_counter -= decr;
}
end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size;
@@ -928,7 +929,7 @@ static void do_outputintr(int dev, int dummy)
dmap->byte_counter += dmap->bytes_in_use;
if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */
long decr = dmap->byte_counter;
- dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
+ dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
decr -= dmap->byte_counter;
dmap->user_counter -= decr;
}
@@ -952,7 +953,7 @@ static void do_outputintr(int dev, int dummy)
dmap->byte_counter += dmap->bytes_in_use;
if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */
long decr = dmap->byte_counter;
- dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use;
+ dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use);
decr -= dmap->byte_counter;
dmap->user_counter -= decr;
}
@@ -1211,18 +1212,4 @@ unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait)
return poll_input(file, dev, wait) | poll_output(file, dev, wait);
}
-void DMAbuf_deinit(int dev)
-{
- struct audio_operations *adev = audio_devs[dev];
- /* This routine is called when driver is being unloaded */
- if (!adev)
- return;
-#ifdef RUNTIME_DMA_ALLOC
- sound_free_dmap(adev->dmap_out);
-
- if (adev->flags & DMA_DUPLEX)
- sound_free_dmap(adev->dmap_in);
-#endif
-}
-
#endif
diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c
index 0f4f769eb..92e6dbab6 100644
--- a/drivers/sound/gus_card.c
+++ b/drivers/sound/gus_card.c
@@ -30,7 +30,7 @@ int gus_pnp_flag = 0;
void attach_gus_card(struct address_info *hw_config)
{
- snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp);
+ snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config);
gus_wave_init(hw_config);
@@ -101,7 +101,7 @@ void unload_gus(struct address_info *hw_config)
release_region(hw_config->io_base, 16);
release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */
- snd_release_irq(hw_config->irq);
+ snd_release_irq(hw_config->irq, hw_config);
sound_free_dma(hw_config->dma);
@@ -111,14 +111,15 @@ void unload_gus(struct address_info *hw_config)
void gusintr(int irq, void *dev_id, struct pt_regs *dummy)
{
- unsigned char src;
- extern int gus_timer_enabled;
+ unsigned char src;
+ extern int gus_timer_enabled;
+ struct address_info *hw_config=dev_id;
sti();
#ifdef CONFIG_GUSMAX
if (have_gus_max)
- adintr(irq, NULL, NULL);
+ adintr(irq, (void *)hw_config->slots[3], NULL);
#endif
while (1)
diff --git a/drivers/sound/hex2hex.c b/drivers/sound/hex2hex.c
index 19753bfc2..4b182625b 100644
--- a/drivers/sound/hex2hex.c
+++ b/drivers/sound/hex2hex.c
@@ -66,14 +66,27 @@ int loadhex(FILE *inf, unsigned char *buf)
int main( int argc, const char * argv [] )
{
- const char * varline = argv[1];
+ const char * varline;
int i,l;
+ int id=0;
+ if(argv[1] && strcmp(argv[1], "-i")==0)
+ {
+ argv++;
+ argc--;
+ id=1;
+ }
+ if(argv[1]==NULL)
+ {
+ fprintf(stderr,"hex2hex: [-i] filename\n");
+ exit(1);
+ }
+ varline = argv[1;
l = loadhex(stdin, buf);
printf("/*\n *\t Computer generated file. Do not edit.\n */\n");
printf("static int %s_len = %d;\n", varline, l);
- printf("static unsigned char %s[] = {\n", varline);
+ printf("static unsigned char %s[] %s = {\n", varline, id?"__initdata":"");
for (i=0;i<l;i++)
{
diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c
index 5cd620dbf..a7d37039c 100644
--- a/drivers/sound/maui.c
+++ b/drivers/sound/maui.c
@@ -9,7 +9,15 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * Alan Cox General clean up, use kernel IRQ
+ * system
+ *
+ * Status:
+ * Untested
*/
+
#include <linux/config.h>
#include <linux/module.h>
@@ -327,7 +335,7 @@ int probe_maui(struct address_info *hw_config)
maui_base = hw_config->io_base;
maui_osp = hw_config->osp;
- if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0)
+ if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
return 0;
/*
@@ -342,26 +350,26 @@ int probe_maui(struct address_info *hw_config)
maui_read() == -1 || maui_read() == -1)
if (!maui_init(hw_config->irq))
{
- snd_release_irq(hw_config->irq);
+ free_irq(hw_config->irq, NULL);
return 0;
}
}
if (!maui_write(0xCF)) /* Report hardware version */
{
printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- snd_release_irq(hw_config->irq);
+ free_irq(hw_config->irq, NULL);
return 0;
}
if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
{
printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- snd_release_irq(hw_config->irq);
+ free_irq(hw_config->irq, NULL);
return 0;
}
if (tmp1 == 0xff || tmp2 == 0xff)
{
- snd_release_irq(hw_config->irq);
- return 0;
+ free_irq(hw_config->irq, NULL);
+ return 0;
}
if (trace_init)
printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
@@ -439,7 +447,7 @@ void unload_maui(struct address_info *hw_config)
if (irq < 0)
irq = -irq;
if (irq > 0)
- snd_release_irq(irq);
+ free_irq(irq, NULL);
}
#ifdef MODULE
@@ -452,8 +460,7 @@ static int fw_load = 0;
struct address_info cfg;
/*
- * Install a CS4232 based card. Need to have ad1848 and mpu401
- * loaded ready.
+ * Install a Maui card. Needs mpu401 loaded already.
*/
int init_module(void)
diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c
index 0c024a454..09dea3a34 100644
--- a/drivers/sound/midibuf.c
+++ b/drivers/sound/midibuf.c
@@ -15,7 +15,6 @@
*/
#include <linux/config.h>
#include <linux/stddef.h>
-#include <linux/kerneld.h>
#define MIDIBUF_C
diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c
index 9ae597404..ce92010fc 100644
--- a/drivers/sound/mpu401.c
+++ b/drivers/sound/mpu401.c
@@ -9,10 +9,12 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ *
+ * Thomas Sailer ioctl code reworked (vmalloc/vfree removed)
+ * Alan Cox modularisation, use normal request_irq, use dev_id
*/
-/*
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- */
+
#include <linux/config.h>
#include <linux/module.h>
@@ -32,30 +34,30 @@ static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
#endif
struct mpu_config
- {
- int base; /*
+{
+ int base; /*
* I/O base
*/
- int irq;
- int opened; /*
- * Open mode
- */
- int devno;
- int synthno;
- int uart_mode;
- int initialized;
- int mode;
+ int irq;
+ int opened; /*
+ * Open mode
+ */
+ int devno;
+ int synthno;
+ int uart_mode;
+ int initialized;
+ int mode;
#define MODE_MIDI 1
#define MODE_SYNTH 2
- unsigned char version, revision;
- unsigned int capabilities;
+ unsigned char version, revision;
+ unsigned int capabilities;
#define MPU_CAP_INTLG 0x10000000
#define MPU_CAP_SYNC 0x00000010
#define MPU_CAP_FSK 0x00000020
#define MPU_CAP_CLS 0x00000040
#define MPU_CAP_SMPTE 0x00000080
#define MPU_CAP_2PORT 0x00000001
- int timer_flag;
+ int timer_flag;
#define MBUF_MAX 10
#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
@@ -75,28 +77,27 @@ struct mpu_config
#define COMDPORT(base) (base+1)
#define STATPORT(base) (base+1)
-static int
-mpu401_status(struct mpu_config *devc)
+static int mpu401_status(struct mpu_config *devc)
{
return inb(STATPORT(devc->base));
}
+
#define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL))
#define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY))
-static void
-write_command(struct mpu_config *devc, unsigned char cmd)
+
+static void write_command(struct mpu_config *devc, unsigned char cmd)
{
- outb((cmd), COMDPORT(devc->base));
+ outb(cmd, COMDPORT(devc->base));
}
-static int
-read_data(struct mpu_config *devc)
+
+static int read_data(struct mpu_config *devc)
{
return inb(DATAPORT(devc->base));
}
-static void
-write_data(struct mpu_config *devc, unsigned char byte)
+static void write_data(struct mpu_config *devc, unsigned char byte)
{
- outb((byte), DATAPORT(devc->base));
+ outb(byte, DATAPORT(devc->base));
}
#define OUTPUT_READY 0x40
@@ -107,22 +108,27 @@ write_data(struct mpu_config *devc, unsigned char byte)
static struct mpu_config dev_conf[MAX_MIDI_DEV] =
{
- {0}};
+ {0}
+};
-static int n_mpu_devs = 0;
-static volatile int irq2dev[17] =
-{-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1};
+static int n_mpu_devs = 0;
-static int reset_mpu401(struct mpu_config *devc);
-static void set_uart_mode(int dev, struct mpu_config *devc, int arg);
+static int reset_mpu401(struct mpu_config *devc);
+static void set_uart_mode(int dev, struct mpu_config *devc, int arg);
-static int mpu_timer_init(int midi_dev);
-static void mpu_timer_interrupt(void);
-static void timer_ext_event(struct mpu_config *devc, int event, int parm);
+static int mpu_timer_init(int midi_dev);
+static void mpu_timer_interrupt(void);
+static void timer_ext_event(struct mpu_config *devc, int event, int parm);
-static struct synth_info mpu_synth_info_proto =
-{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+static struct synth_info mpu_synth_info_proto = {
+ "MPU-401 MIDI interface",
+ 0,
+ SYNTH_TYPE_MIDI,
+ MIDI_TYPE_MPU401,
+ 0, 128,
+ 0, 128,
+ SYNTH_CAP_INPUT
+};
static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
@@ -158,10 +164,10 @@ static unsigned char len_tab[] = /* # of data bytes following a status
#else
#define STORE(cmd) \
{ \
- int len; \
- unsigned char obuf[8]; \
- cmd; \
- seq_input_event(obuf, len); \
+ int len; \
+ unsigned char obuf[8]; \
+ cmd; \
+ seq_input_event(obuf, len); \
}
#endif
@@ -169,242 +175,242 @@ static unsigned char len_tab[] = /* # of data bytes following a status
#define _seqbufptr 0
#define _SEQ_ADVBUF(x) len=x
-static int
-mpu_input_scanner(struct mpu_config *devc, unsigned char midic)
+static int mpu_input_scanner(struct mpu_config *devc, unsigned char midic)
{
switch (devc->m_state)
- {
- case ST_INIT:
- switch (midic)
- {
- case 0xf8:
- /* Timer overflow */
- break;
-
- case 0xfc:
- printk("<all end>");
- break;
-
- case 0xfd:
- if (devc->timer_flag)
- mpu_timer_interrupt();
- break;
-
- case 0xfe:
- return MPU_ACK;
- break;
-
- case 0xf0:
- case 0xf1:
- case 0xf2:
- case 0xf3:
- case 0xf4:
- case 0xf5:
- case 0xf6:
- case 0xf7:
- printk("<Trk data rq #%d>", midic & 0x0f);
- break;
-
- case 0xf9:
- printk("<conductor rq>");
- break;
-
- case 0xff:
- devc->m_state = ST_SYSMSG;
- break;
-
- default:
- if (midic <= 0xef)
- {
- /* printk( "mpu time: %d ", midic); */
- devc->m_state = ST_TIMED;
- } else
- printk("<MPU: Unknown event %02x> ", midic);
- }
- break;
-
- case ST_TIMED:
- {
- int msg = ((int) (midic & 0xf0) >> 4);
-
- devc->m_state = ST_DATABYTE;
-
- if (msg < 8) /* Data byte */
- {
- /* printk( "midi msg (running status) "); */
- msg = ((int) (devc->last_status & 0xf0) >> 4);
- msg -= 8;
- devc->m_left = len_tab[msg] - 1;
-
- devc->m_ptr = 2;
- devc->m_buf[0] = devc->last_status;
- devc->m_buf[1] = midic;
-
- if (devc->m_left <= 0)
- {
- devc->m_state = ST_INIT;
- do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- } else if (msg == 0xf) /* MPU MARK */
- {
- devc->m_state = ST_INIT;
-
- switch (midic)
- {
- case 0xf8:
- /* printk( "NOP "); */
- break;
-
- case 0xf9:
- /* printk( "meas end "); */
- break;
-
- case 0xfc:
- /* printk( "data end "); */
- break;
-
- default:
- printk("Unknown MPU mark %02x\n", midic);
- }
- } else
- {
- devc->last_status = midic;
- /* printk( "midi msg "); */
- msg -= 8;
- devc->m_left = len_tab[msg];
-
- devc->m_ptr = 1;
- devc->m_buf[0] = midic;
-
- if (devc->m_left <= 0)
- {
- devc->m_state = ST_INIT;
- do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- }
- }
- break;
-
- case ST_SYSMSG:
- switch (midic)
- {
- case 0xf0:
- printk("<SYX>");
- devc->m_state = ST_SYSEX;
- break;
-
- case 0xf1:
- devc->m_state = ST_MTC;
- break;
-
- case 0xf2:
- devc->m_state = ST_SONGPOS;
- devc->m_ptr = 0;
- break;
-
- case 0xf3:
- devc->m_state = ST_SONGSEL;
- break;
-
- case 0xf6:
- /* printk( "tune_request\n"); */
- devc->m_state = ST_INIT;
-
- /*
- * Real time messages
- */
- case 0xf8:
- /* midi clock */
- devc->m_state = ST_INIT;
- timer_ext_event(devc, TMR_CLOCK, 0);
- break;
-
- case 0xfA:
- devc->m_state = ST_INIT;
- timer_ext_event(devc, TMR_START, 0);
- break;
-
- case 0xFB:
- devc->m_state = ST_INIT;
- timer_ext_event(devc, TMR_CONTINUE, 0);
- break;
-
- case 0xFC:
- devc->m_state = ST_INIT;
- timer_ext_event(devc, TMR_STOP, 0);
- break;
-
- case 0xFE:
- /* active sensing */
- devc->m_state = ST_INIT;
- break;
-
- case 0xff:
- /* printk( "midi hard reset"); */
- devc->m_state = ST_INIT;
- break;
-
- default:
- printk("unknown MIDI sysmsg %0x\n", midic);
- devc->m_state = ST_INIT;
- }
- break;
-
- case ST_MTC:
- devc->m_state = ST_INIT;
- printk("MTC frame %x02\n", midic);
- break;
-
- case ST_SYSEX:
- if (midic == 0xf7)
- {
- printk("<EOX>");
- devc->m_state = ST_INIT;
- } else
- printk("%02x ", midic);
- break;
-
- case ST_SONGPOS:
- BUFTEST(devc);
- devc->m_buf[devc->m_ptr++] = midic;
- if (devc->m_ptr == 2)
- {
- devc->m_state = ST_INIT;
- devc->m_ptr = 0;
- timer_ext_event(devc, TMR_SPP,
- ((devc->m_buf[1] & 0x7f) << 7) |
- (devc->m_buf[0] & 0x7f));
- }
- break;
-
- case ST_DATABYTE:
- BUFTEST(devc);
- devc->m_buf[devc->m_ptr++] = midic;
- if ((--devc->m_left) <= 0)
- {
- devc->m_state = ST_INIT;
- do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- break;
-
- default:
- printk("Bad state %d ", devc->m_state);
- devc->m_state = ST_INIT;
- }
+ {
+ case ST_INIT:
+ switch (midic)
+ {
+ case 0xf8:
+ /* Timer overflow */
+ break;
+
+ case 0xfc:
+ printk("<all end>");
+ break;
+
+ case 0xfd:
+ if (devc->timer_flag)
+ mpu_timer_interrupt();
+ break;
+
+ case 0xfe:
+ return MPU_ACK;
+
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ printk("<Trk data rq #%d>", midic & 0x0f);
+ break;
+
+ case 0xf9:
+ printk("<conductor rq>");
+ break;
+
+ case 0xff:
+ devc->m_state = ST_SYSMSG;
+ break;
+
+ default:
+ if (midic <= 0xef)
+ {
+ /* printk( "mpu time: %d ", midic); */
+ devc->m_state = ST_TIMED;
+ }
+ else
+ printk("<MPU: Unknown event %02x> ", midic);
+ }
+ break;
+
+ case ST_TIMED:
+ {
+ int msg = ((int) (midic & 0xf0) >> 4);
+
+ devc->m_state = ST_DATABYTE;
+
+ if (msg < 8) /* Data byte */
+ {
+ /* printk( "midi msg (running status) "); */
+ msg = ((int) (devc->last_status & 0xf0) >> 4);
+ msg -= 8;
+ devc->m_left = len_tab[msg] - 1;
+
+ devc->m_ptr = 2;
+ devc->m_buf[0] = devc->last_status;
+ devc->m_buf[1] = midic;
+
+ if (devc->m_left <= 0)
+ {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ }
+ else if (msg == 0xf) /* MPU MARK */
+ {
+ devc->m_state = ST_INIT;
+
+ switch (midic)
+ {
+ case 0xf8:
+ /* printk( "NOP "); */
+ break;
+
+ case 0xf9:
+ /* printk( "meas end "); */
+ break;
+
+ case 0xfc:
+ /* printk( "data end "); */
+ break;
+
+ default:
+ printk("Unknown MPU mark %02x\n", midic);
+ }
+ }
+ else
+ {
+ devc->last_status = midic;
+ /* printk( "midi msg "); */
+ msg -= 8;
+ devc->m_left = len_tab[msg];
+
+ devc->m_ptr = 1;
+ devc->m_buf[0] = midic;
+
+ if (devc->m_left <= 0)
+ {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ }
+ }
+ break;
+
+ case ST_SYSMSG:
+ switch (midic)
+ {
+ case 0xf0:
+ printk("<SYX>");
+ devc->m_state = ST_SYSEX;
+ break;
+
+ case 0xf1:
+ devc->m_state = ST_MTC;
+ break;
+
+ case 0xf2:
+ devc->m_state = ST_SONGPOS;
+ devc->m_ptr = 0;
+ break;
+
+ case 0xf3:
+ devc->m_state = ST_SONGSEL;
+ break;
+
+ case 0xf6:
+ /* printk( "tune_request\n"); */
+ devc->m_state = ST_INIT;
+
+ /*
+ * Real time messages
+ */
+ case 0xf8:
+ /* midi clock */
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_CLOCK, 0);
+ break;
+
+ case 0xfA:
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_START, 0);
+ break;
+
+ case 0xFB:
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_CONTINUE, 0);
+ break;
+
+ case 0xFC:
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_STOP, 0);
+ break;
+
+ case 0xFE:
+ /* active sensing */
+ devc->m_state = ST_INIT;
+ break;
+
+ case 0xff:
+ /* printk( "midi hard reset"); */
+ devc->m_state = ST_INIT;
+ break;
+
+ default:
+ printk("unknown MIDI sysmsg %0x\n", midic);
+ devc->m_state = ST_INIT;
+ }
+ break;
+
+ case ST_MTC:
+ devc->m_state = ST_INIT;
+ printk("MTC frame %x02\n", midic);
+ break;
+
+ case ST_SYSEX:
+ if (midic == 0xf7)
+ {
+ printk("<EOX>");
+ devc->m_state = ST_INIT;
+ }
+ else
+ printk("%02x ", midic);
+ break;
+
+ case ST_SONGPOS:
+ BUFTEST(devc);
+ devc->m_buf[devc->m_ptr++] = midic;
+ if (devc->m_ptr == 2)
+ {
+ devc->m_state = ST_INIT;
+ devc->m_ptr = 0;
+ timer_ext_event(devc, TMR_SPP,
+ ((devc->m_buf[1] & 0x7f) << 7) |
+ (devc->m_buf[0] & 0x7f));
+ }
+ break;
+ case ST_DATABYTE:
+ BUFTEST(devc);
+ devc->m_buf[devc->m_ptr++] = midic;
+ if ((--devc->m_left) <= 0)
+ {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ break;
+
+ default:
+ printk("Bad state %d ", devc->m_state);
+ devc->m_state = ST_INIT;
+ }
return 1;
}
-static void
-mpu401_input_loop(struct mpu_config *devc)
+static void mpu401_input_loop(struct mpu_config *devc)
{
- unsigned long flags;
- int busy;
- int n;
+ unsigned long flags;
+ int busy;
+ int n;
save_flags(flags);
cli();
@@ -418,72 +424,45 @@ mpu401_input_loop(struct mpu_config *devc)
n = 50;
while (input_avail(devc) && n-- > 0)
- {
- unsigned char c = read_data(devc);
-
- if (devc->mode == MODE_SYNTH)
- {
- mpu_input_scanner(devc, c);
- } else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
- devc->inputintr(devc->devno, c);
- }
+ {
+ unsigned char c = read_data(devc);
+ if (devc->mode == MODE_SYNTH)
+ {
+ mpu_input_scanner(devc, c);
+ }
+ else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+ devc->inputintr(devc->devno, c);
+ }
devc->m_busy = 0;
}
-void
-mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+void mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
{
struct mpu_config *devc;
- int dev;
+ int dev = (int) dev_id;
sti();
-
-/*
- * FreeBSD (and some others) pass unit number to the interrupt handler.
- * In this case we have to scan the table for first handler.
- */
-
- if (irq < 1 || irq > 15)
- {
- dev = -1;
- } else
- dev = irq2dev[irq];
-
- if (dev == -1)
- {
- int origirq = irq;
-
- for (irq = 0; irq <= 16; irq++)
- if (irq2dev[irq] != -1)
- break;
- if (irq > 15)
- {
- printk("MPU-401: Bogus interrupt #%d?\n", origirq);
- return;
- }
- dev = irq2dev[irq];
- devc = &dev_conf[dev];
- } else
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
if (input_avail(devc))
+ {
if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
mpu401_input_loop(devc);
else
- {
- /* Dummy read (just to acknowledge the interrupt) */
- read_data(devc);
- }
+ {
+ /* Dummy read (just to acknowledge the interrupt) */
+ read_data(devc);
+ }
+ }
}
-static int
-mpu401_open(int dev, int mode,
+static int mpu401_open(int dev, int mode,
void (*input) (int dev, unsigned char data),
void (*output) (int dev)
)
{
- int err;
+ int err;
struct mpu_config *devc;
if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
@@ -492,36 +471,34 @@ mpu401_open(int dev, int mode,
devc = &dev_conf[dev];
if (devc->opened)
- {
- printk("MPU-401: Midi busy\n");
return -EBUSY;
- }
/*
- * Verify that the device is really running.
- * Some devices (such as Ensoniq SoundScape don't
- * work before the on board processor (OBP) is initialized
- * by downloading its microcode.
+ * Verify that the device is really running.
+ * Some devices (such as Ensoniq SoundScape don't
+ * work before the on board processor (OBP) is initialized
+ * by downloading its microcode.
*/
if (!devc->initialized)
- {
- if (mpu401_status(devc) == 0xff) /* Bus float */
- {
- printk("MPU-401: Device not initialized properly\n");
- return -EIO;
- }
- reset_mpu401(devc);
- }
- irq2dev[devc->irq] = dev;
+ {
+ if (mpu401_status(devc) == 0xff) /* Bus float */
+ {
+ printk(KERN_ERR "mpu401: Device not initialized properly\n");
+ return -EIO;
+ }
+ reset_mpu401(devc);
+ }
if (midi_devs[dev]->coproc)
+ {
if ((err = midi_devs[dev]->coproc->
open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)
- {
- printk("MPU-401: Can't access coprocessor device\n");
-
- return err;
- }
+ {
+ printk("MPU-401: Can't access coprocessor device\n");
+ return err;
+ }
+ }
+
set_uart_mode(dev, devc, 1);
devc->mode = MODE_MIDI;
devc->synthno = 0;
@@ -534,19 +511,16 @@ mpu401_open(int dev, int mode,
return 0;
}
-static void
-mpu401_close(int dev)
+static void mpu401_close(int dev)
{
struct mpu_config *devc;
devc = &dev_conf[dev];
-
if (devc->uart_mode)
reset_mpu401(devc); /*
* This disables the UART mode
*/
devc->mode = 0;
-
devc->inputintr = NULL;
if (midi_devs[dev]->coproc)
@@ -554,11 +528,10 @@ mpu401_close(int dev)
devc->opened = 0;
}
-static int
-mpu401_out(int dev, unsigned char midi_byte)
+static int mpu401_out(int dev, unsigned char midi_byte)
{
- int timeout;
- unsigned long flags;
+ int timeout;
+ unsigned long flags;
struct mpu_config *devc;
@@ -574,21 +547,20 @@ mpu401_out(int dev, unsigned char midi_byte)
save_flags(flags);
cli();
if (!output_ready(devc))
- {
- printk("MPU-401: Send data timeout\n");
- restore_flags(flags);
- return 0;
- }
+ {
+ printk(KERN_WARNING "mpu401: Send data timeout\n");
+ restore_flags(flags);
+ return 0;
+ }
write_data(devc, midi_byte);
restore_flags(flags);
return 1;
}
-static int
-mpu401_command(int dev, mpu_command_rec * cmd)
+static int mpu401_command(int dev, mpu_command_rec * cmd)
{
- int i, timeout, ok;
- int ret = 0;
+ int i, timeout, ok;
+ int ret = 0;
unsigned long flags;
struct mpu_config *devc;
@@ -597,10 +569,10 @@ mpu401_command(int dev, mpu_command_rec * cmd)
if (devc->uart_mode) /*
* Not possible in UART mode
*/
- {
- printk("MPU-401 commands not possible in the UART mode\n");
- return -EINVAL;
- }
+ {
+ printk(KERN_WARNING "mpu401: commands not possible in the UART mode\n");
+ return -EINVAL;
+ }
/*
* Test for input since pending input seems to block the output.
*/
@@ -613,83 +585,87 @@ mpu401_command(int dev, mpu_command_rec * cmd)
*/
timeout = 50000;
- retry:
+retry:
if (timeout-- <= 0)
- {
- printk("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
- return -EIO;
- }
+ {
+ printk(KERN_WARNING "mpu401: Command (0x%x) timeout\n", (int) cmd->cmd);
+ return -EIO;
+ }
save_flags(flags);
cli();
if (!output_ready(devc))
- {
+ {
restore_flags(flags);
goto retry;
- }
+ }
write_command(devc, cmd->cmd);
ok = 0;
for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ {
if (input_avail(devc))
- {
- if (devc->opened && devc->mode == MODE_SYNTH)
- {
- if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)
- ok = 1;
- } else
- { /* Device is not currently open. Use simpler method */
- if (read_data(devc) == MPU_ACK)
- ok = 1;
- }
- }
+ {
+ if (devc->opened && devc->mode == MODE_SYNTH)
+ {
+ if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)
+ ok = 1;
+ }
+ else
+ {
+ /* Device is not currently open. Use simpler method */
+ if (read_data(devc) == MPU_ACK)
+ ok = 1;
+ }
+ }
+ }
if (!ok)
- {
- restore_flags(flags);
- /* printk( "MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
- return -EIO;
- }
+ {
+ restore_flags(flags);
+ return -EIO;
+ }
if (cmd->nr_args)
+ {
for (i = 0; i < cmd->nr_args; i++)
- {
- for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
-
- if (!mpu401_out(dev, cmd->data[i]))
- {
- restore_flags(flags);
- printk("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
- return -EIO;
- }
- }
+ {
+ for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
+
+ if (!mpu401_out(dev, cmd->data[i]))
+ {
+ restore_flags(flags);
+ printk(KERN_WARNING "mpu401: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
+ return -EIO;
+ }
+ }
+ }
ret = 0;
cmd->data[0] = 0;
if (cmd->nr_returns)
+ {
for (i = 0; i < cmd->nr_returns; i++)
- {
- ok = 0;
- for (timeout = 5000; timeout > 0 && !ok; timeout--)
- if (input_avail(devc))
- {
- cmd->data[i] = read_data(devc);
- ok = 1;
- }
- if (!ok)
- {
- restore_flags(flags);
- /* printk( "MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */
- return -EIO;
- }
- }
+ {
+ ok = 0;
+ for (timeout = 5000; timeout > 0 && !ok; timeout--)
+ if (input_avail(devc))
+ {
+ cmd->data[i] = read_data(devc);
+ ok = 1;
+ }
+ if (!ok)
+ {
+ restore_flags(flags);
+ return -EIO;
+ }
+ }
+ }
restore_flags(flags);
-
return ret;
}
-static int
-mpu_cmd(int dev, int cmd, int data)
+static int mpu_cmd(int dev, int cmd, int data)
{
- int ret;
+ int ret;
static mpu_command_rec rec;
@@ -699,14 +675,11 @@ mpu_cmd(int dev, int cmd, int data)
rec.data[0] = data & 0xff;
if ((ret = mpu401_command(dev, &rec)) < 0)
- {
- return ret;
- }
+ return ret;
return (unsigned char) rec.data[0];
}
-static int
-mpu401_prefix_cmd(int dev, unsigned char status)
+static int mpu401_prefix_cmd(int dev, unsigned char status)
{
struct mpu_config *devc = &dev_conf[dev];
@@ -714,37 +687,29 @@ mpu401_prefix_cmd(int dev, unsigned char status)
return 1;
if (status < 0xf0)
- {
- if (mpu_cmd(dev, 0xD0, 0) < 0)
- {
- return 0;
- }
- return 1;
- }
+ {
+ if (mpu_cmd(dev, 0xD0, 0) < 0)
+ return 0;
+ return 1;
+ }
switch (status)
- {
- case 0xF0:
- if (mpu_cmd(dev, 0xDF, 0) < 0)
- {
- return 0;
- }
- return 1;
- break;
-
- default:
- return 0;
- }
+ {
+ case 0xF0:
+ if (mpu_cmd(dev, 0xDF, 0) < 0)
+ return 0;
+ return 1;
+ default:
+ return 0;
+ }
}
-static int
-mpu401_start_read(int dev)
+static int mpu401_start_read(int dev)
{
return 0;
}
-static int
-mpu401_end_read(int dev)
+static int mpu401_end_read(int dev)
{
return 0;
}
@@ -756,49 +721,47 @@ static int mpu401_ioctl(int dev, unsigned cmd, caddr_t arg)
int val, ret;
devc = &dev_conf[dev];
- switch (cmd) {
- case SNDCTL_MIDI_MPUMODE:
- if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
- printk("MPU-401: Intelligent mode not supported by the HW\n");
+ switch (cmd)
+ {
+ case SNDCTL_MIDI_MPUMODE:
+ if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
+ printk(KERN_WARNING "mpu401: Intelligent mode not supported by the HW\n");
+ return -EINVAL;
+ }
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ set_uart_mode(dev, devc, !val);
+ return 0;
+
+ case SNDCTL_MIDI_MPUCMD:
+ if (copy_from_user(&rec, arg, sizeof(rec)))
+ return -EFAULT;
+ if ((ret = mpu401_command(dev, &rec)) < 0)
+ return ret;
+ if (copy_to_user(arg, &rec, sizeof(rec)))
+ return -EFAULT;
+ return 0;
+
+ default:
return -EINVAL;
- }
- if (__get_user(val, (int *)arg))
- return -EFAULT;
- set_uart_mode(dev, devc, !val);
- return 0;
-
- case SNDCTL_MIDI_MPUCMD:
- if (__copy_from_user(&rec, arg, sizeof(rec)))
- return -EFAULT;
- if ((ret = mpu401_command(dev, &rec)) < 0)
- return ret;
- if (__copy_to_user(arg, &rec, sizeof(rec)))
- return -EFAULT;
- return 0;
-
- default:
- return -EINVAL;
}
}
-static void
-mpu401_kick(int dev)
+static void mpu401_kick(int dev)
{
}
-static int
-mpu401_buffer_status(int dev)
+static int mpu401_buffer_status(int dev)
{
return 0; /*
* No data in buffers
*/
}
-static int
-mpu_synth_ioctl(int dev,
+static int mpu_synth_ioctl(int dev,
unsigned int cmd, caddr_t arg)
{
- int midi_dev;
+ int midi_dev;
struct mpu_config *devc;
midi_dev = synth_devs[dev]->midi_dev;
@@ -809,88 +772,77 @@ mpu_synth_ioctl(int dev,
devc = &dev_conf[midi_dev];
switch (cmd)
- {
-
- case SNDCTL_SYNTH_INFO:
- memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info));
+ {
- return 0;
- break;
+ case SNDCTL_SYNTH_INFO:
+ memcpy((&((char *) arg)[0]), (char *) &mpu_synth_info[midi_dev], sizeof(struct synth_info));
+ return 0;
- case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
- break;
+ case SNDCTL_SYNTH_MEMAVL:
+ return 0x7fffffff;
- default:
- return -EINVAL;
- }
+ default:
+ return -EINVAL;
+ }
}
-static int
-mpu_synth_open(int dev, int mode)
+static int mpu_synth_open(int dev, int mode)
{
- int midi_dev, err;
+ int midi_dev, err;
struct mpu_config *devc;
midi_dev = synth_devs[dev]->midi_dev;
if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL)
- {
- return -ENXIO;
- }
+ return -ENXIO;
+
devc = &dev_conf[midi_dev];
/*
- * Verify that the device is really running.
- * Some devices (such as Ensoniq SoundScape don't
- * work before the on board processor (OBP) is initialized
- * by downloading its microcode.
+ * Verify that the device is really running.
+ * Some devices (such as Ensoniq SoundScape don't
+ * work before the on board processor (OBP) is initialized
+ * by downloading its microcode.
*/
if (!devc->initialized)
- {
- if (mpu401_status(devc) == 0xff) /* Bus float */
- {
- printk("MPU-401: Device not initialized properly\n");
- return -EIO;
- }
- reset_mpu401(devc);
- }
+ {
+ if (mpu401_status(devc) == 0xff) /* Bus float */
+ {
+ printk(KERN_ERR "mpu401: Device not initialized properly\n");
+ return -EIO;
+ }
+ reset_mpu401(devc);
+ }
if (devc->opened)
- {
- printk("MPU-401: Midi busy\n");
- return -EBUSY;
- }
+ return -EBUSY;
devc->mode = MODE_SYNTH;
devc->synthno = dev;
devc->inputintr = NULL;
- irq2dev[devc->irq] = midi_dev;
if (midi_devs[midi_dev]->coproc)
if ((err = midi_devs[midi_dev]->coproc->
open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0)
- {
- printk("MPU-401: Can't access coprocessor device\n");
-
- return err;
- }
+ {
+ printk(KERN_WARNING "mpu401: Can't access coprocessor device\n");
+ return err;
+ }
devc->opened = mode;
reset_mpu401(devc);
if (mode & OPEN_READ)
- {
- mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */
- mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
- mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */
- }
+ {
+ mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */
+ mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
+ mpu_cmd(midi_dev, 0x87, 0); /* Enable pitch & controller */
+ }
return 0;
}
-static void
-mpu_synth_close(int dev)
-{
- int midi_dev;
+static void mpu_synth_close(int dev)
+{
+ int midi_dev;
struct mpu_config *devc;
midi_dev = synth_devs[dev]->midi_dev;
@@ -958,55 +910,52 @@ static struct midi_operations mpu401_midi_proto =
static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
-static void
-mpu401_chk_version(int n, struct mpu_config *devc)
+static void mpu401_chk_version(int n, struct mpu_config *devc)
{
- int tmp;
- unsigned long flags;
+ int tmp;
+ unsigned long flags;
devc->version = devc->revision = 0;
save_flags(flags);
cli();
if ((tmp = mpu_cmd(n, 0xAC, 0)) < 0)
- {
- restore_flags(flags);
- return;
- }
+ {
+ restore_flags(flags);
+ return;
+ }
if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */
- {
- restore_flags(flags);
- return;
- }
+ {
+ restore_flags(flags);
+ return;
+ }
devc->version = tmp;
if ((tmp = mpu_cmd(n, 0xAD, 0)) < 0)
- {
- devc->version = 0;
- restore_flags(flags);
- return;
- }
+ {
+ devc->version = 0;
+ restore_flags(flags);
+ return;
+ }
devc->revision = tmp;
-
restore_flags(flags);
}
-void
-attach_mpu401(struct address_info *hw_config)
+void attach_mpu401(struct address_info *hw_config)
{
- unsigned long flags;
- char revision_char;
+ unsigned long flags;
+ char revision_char;
- int m;
+ int m;
struct mpu_config *devc;
hw_config->slots[1] = -1;
m = sound_alloc_mididev();
if (m == -1)
- {
- printk(KERN_WARNING "MPU-401: Too many midi devices detected\n");
- return;
- }
+ {
+ printk(KERN_WARNING "MPU-401: Too many midi devices detected\n");
+ return;
+ }
devc = &dev_conf[m];
devc->base = hw_config->io_base;
devc->osp = hw_config->osp;
@@ -1024,35 +973,36 @@ attach_mpu401(struct address_info *hw_config)
devc->irq = hw_config->irq;
if (devc->irq < 0)
- {
- devc->irq *= -1;
- devc->shared_irq = 1;
- }
- irq2dev[devc->irq] = m;
+ {
+ devc->irq *= -1;
+ devc->shared_irq = 1;
+ }
if (!hw_config->always_detect)
- {
- /* Verify the hardware again */
- if (!reset_mpu401(devc))
- {
- printk(KERN_WARNING "mpu401: Device didn't respond\n");
- sound_unload_mididev(m);
- return;
- }
- if (!devc->shared_irq)
- if (snd_set_irq_handler(devc->irq, mpuintr, "mpu401", devc->osp) < 0)
- {
- printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);
- sound_unload_mididev(m);
- return;
- }
- save_flags(flags);
- cli();
- mpu401_chk_version(m, devc);
- if (devc->version == 0)
- mpu401_chk_version(m, devc);
- restore_flags(flags);
- }
+ {
+ /* Verify the hardware again */
+ if (!reset_mpu401(devc))
+ {
+ printk(KERN_WARNING "mpu401: Device didn't respond\n");
+ sound_unload_mididev(m);
+ return;
+ }
+ if (!devc->shared_irq)
+ {
+ if (request_irq(devc->irq, mpuintr, 0, "mpu401", (void *)m) < 0)
+ {
+ printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);
+ sound_unload_mididev(m);
+ return;
+ }
+ }
+ save_flags(flags);
+ cli();
+ mpu401_chk_version(m, devc);
+ if (devc->version == 0)
+ mpu401_chk_version(m, devc);
+ restore_flags(flags);
+ }
request_region(hw_config->io_base, 2, "mpu401");
if (devc->version != 0)
@@ -1061,36 +1011,32 @@ attach_mpu401(struct address_info *hw_config)
devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */
- mpu401_synth_operations[m] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations)));
- sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations);
-
- if (sound_nblocks < 1024)
- sound_nblocks++;;
+ mpu401_synth_operations[m] = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
if (mpu401_synth_operations[m] == NULL)
- {
- sound_unload_mididev(m);
- printk(KERN_ERR "mpu401: Can't allocate memory\n");
- return;
- }
+ {
+ sound_unload_mididev(m);
+ printk(KERN_ERR "mpu401: Can't allocate memory\n");
+ return;
+ }
if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */
- {
- memcpy((char *) mpu401_synth_operations[m],
- (char *) &std_midi_synth,
+ {
+ memcpy((char *) mpu401_synth_operations[m],
+ (char *) &std_midi_synth,
sizeof(struct synth_operations));
- } else
- {
- memcpy((char *) mpu401_synth_operations[m],
- (char *) &mpu401_synth_proto,
+ }
+ else
+ {
+ memcpy((char *) mpu401_synth_operations[m],
+ (char *) &mpu401_synth_proto,
sizeof(struct synth_operations));
- }
+ }
memcpy((char *) &mpu401_midi_operations[m],
(char *) &mpu401_midi_proto,
sizeof(struct midi_operations));
- mpu401_midi_operations[m].converter =
- mpu401_synth_operations[m];
+ mpu401_midi_operations[m].converter = mpu401_synth_operations[m];
memcpy((char *) &mpu_synth_info[m],
(char *) &mpu_synth_info_proto,
@@ -1099,37 +1045,36 @@ attach_mpu401(struct address_info *hw_config)
n_mpu_devs++;
if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */
- {
- int ports = (devc->revision & 0x08) ? 32 : 16;
-
- devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
- MPU_CAP_CLS | MPU_CAP_2PORT;
-
- revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
- sprintf(mpu_synth_info[m].name,
- "MQX-%d%c MIDI Interface #%d",
- ports,
- revision_char,
- n_mpu_devs);
- } else
- {
-
- revision_char = devc->revision ? devc->revision + '@' : ' ';
- if ((int) devc->revision > ('Z' - '@'))
- revision_char = '+';
-
- devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
-
- if (hw_config->name)
- sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
- else
- sprintf(mpu_synth_info[m].name,
- "MPU-401 %d.%d%c Midi interface #%d",
- (int) (devc->version & 0xf0) >> 4,
- devc->version & 0x0f,
- revision_char,
- n_mpu_devs);
- }
+ {
+ int ports = (devc->revision & 0x08) ? 32 : 16;
+
+ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
+ MPU_CAP_CLS | MPU_CAP_2PORT;
+
+ revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
+ sprintf(mpu_synth_info[m].name, "MQX-%d%c MIDI Interface #%d",
+ ports,
+ revision_char,
+ n_mpu_devs);
+ }
+ else
+ {
+ revision_char = devc->revision ? devc->revision + '@' : ' ';
+ if ((int) devc->revision > ('Z' - '@'))
+ revision_char = '+';
+
+ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
+
+ if (hw_config->name)
+ sprintf(mpu_synth_info[m].name, "%s (MPU401)", hw_config->name);
+ else
+ sprintf(mpu_synth_info[m].name,
+ "MPU-401 %d.%d%c Midi interface #%d",
+ (int) (devc->version & 0xf0) >> 4,
+ devc->version & 0x0f,
+ revision_char,
+ n_mpu_devs);
+ }
strcpy(mpu401_midi_operations[m].info.name,
mpu_synth_info[m].name);
@@ -1137,24 +1082,21 @@ attach_mpu401(struct address_info *hw_config)
conf_printf(mpu_synth_info[m].name, hw_config);
mpu401_synth_operations[m]->midi_dev = devc->devno = m;
- mpu401_synth_operations[devc->devno]->info =
- &mpu_synth_info[devc->devno];
+ mpu401_synth_operations[devc->devno]->info = &mpu_synth_info[devc->devno];
if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */
hw_config->slots[2] = mpu_timer_init(m);
- irq2dev[devc->irq] = m;
midi_devs[m] = &mpu401_midi_operations[devc->devno];
hw_config->slots[1] = m;
sequencer_init();
}
-static int
-reset_mpu401(struct mpu_config *devc)
+static int reset_mpu401(struct mpu_config *devc)
{
- unsigned long flags;
- int ok, timeout, n;
- int timeout_limit;
+ unsigned long flags;
+ int ok, timeout, n;
+ int timeout_limit;
/*
* Send the RESET command. Try again if no success at the first time.
@@ -1167,30 +1109,30 @@ reset_mpu401(struct mpu_config *devc)
devc->initialized = 1;
for (n = 0; n < 2 && !ok; n++)
- {
- for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
+ {
+ for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
ok = output_ready(devc);
- write_command(devc, MPU_RESET); /*
+ write_command(devc, MPU_RESET); /*
* Send MPU-401 RESET Command
*/
- /*
- * Wait at least 25 msec. This method is not accurate so let's make the
- * loop bit longer. Cannot sleep since this is called during boot.
- */
+ /*
+ * Wait at least 25 msec. This method is not accurate so let's make the
+ * loop bit longer. Cannot sleep since this is called during boot.
+ */
- for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
- {
- save_flags(flags);
- cli();
- if (input_avail(devc))
- if (read_data(devc) == MPU_ACK)
- ok = 1;
- restore_flags(flags);
- }
+ for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
+ {
+ save_flags(flags);
+ cli();
+ if (input_avail(devc))
+ if (read_data(devc) == MPU_ACK)
+ ok = 1;
+ restore_flags(flags);
+ }
- }
+ }
devc->m_state = ST_INIT;
devc->m_ptr = 0;
@@ -1201,43 +1143,37 @@ reset_mpu401(struct mpu_config *devc)
return ok;
}
-static void
-set_uart_mode(int dev, struct mpu_config *devc, int arg)
+static void set_uart_mode(int dev, struct mpu_config *devc, int arg)
{
if (!arg && (devc->capabilities & MPU_CAP_INTLG))
- {
- return;
- }
+ return;
if ((devc->uart_mode == 0) == (arg == 0))
- {
- return; /* Already set */
- }
+ return; /* Already set */
reset_mpu401(devc); /* This exits the uart mode */
if (arg)
- {
- if (mpu_cmd(dev, UART_MODE_ON, 0) < 0)
- {
- printk("MPU%d: Can't enter UART mode\n", devc->devno);
- devc->uart_mode = 0;
- return;
- }
- }
+ {
+ if (mpu_cmd(dev, UART_MODE_ON, 0) < 0)
+ {
+ printk(KERN_ERR "mpu401: Can't enter UART mode\n");
+ devc->uart_mode = 0;
+ return;
+ }
+ }
devc->uart_mode = arg;
}
-int
-probe_mpu401(struct address_info *hw_config)
+int probe_mpu401(struct address_info *hw_config)
{
- int ok = 0;
+ int ok = 0;
struct mpu_config tmp_devc;
if (check_region(hw_config->io_base, 2))
- {
- printk("\n\nmpu401.c: I/O port %x already in use\n\n", hw_config->io_base);
- return 0;
- }
+ {
+ printk(KERN_ERR "mpu401: I/O port %x already in use\n\n", hw_config->io_base);
+ return 0;
+ }
tmp_devc.base = hw_config->io_base;
tmp_devc.irq = hw_config->irq;
tmp_devc.initialized = 0;
@@ -1248,27 +1184,32 @@ probe_mpu401(struct address_info *hw_config)
return 1;
if (inb(hw_config->io_base + 1) == 0xff)
- {
- DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));
- return 0; /* Just bus float? */
- }
+ {
+ DDB(printk("MPU401: Port %x looks dead.\n", hw_config->io_base));
+ return 0; /* Just bus float? */
+ }
ok = reset_mpu401(&tmp_devc);
if (!ok)
- {
- DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base));
- }
+ {
+ DDB(printk("MPU401: Reset failed on port %x\n", hw_config->io_base));
+ }
return ok;
}
-void
-unload_mpu401(struct address_info *hw_config)
+void unload_mpu401(struct address_info *hw_config)
{
+ void *p;
+ int n=hw_config->slots[1];
+
release_region(hw_config->io_base, 2);
if (hw_config->always_detect == 0 && hw_config->irq > 0)
- snd_release_irq(hw_config->irq);
- sound_unload_mididev(hw_config->slots[1]);
+ free_irq(hw_config->irq, (void *)n);
+ p=mpu401_synth_operations[n];
+ sound_unload_mididev(n);
sound_unload_timerdev(hw_config->slots[2]);
+ if(p)
+ kfree(p);
}
/*****************************************************
@@ -1285,23 +1226,20 @@ static volatile unsigned long curr_ticks, curr_clocks;
static unsigned long prev_event_time;
static int metronome_mode;
-static unsigned long
-clocks2ticks(unsigned long clocks)
+static unsigned long clocks2ticks(unsigned long clocks)
{
/*
- * The MPU-401 supports just a limited set of possible timebase values.
- * Since the applications require more choices, the driver has to
- * program the HW to do its best and to convert between the HW and
- * actual timebases.
+ * The MPU-401 supports just a limited set of possible timebase values.
+ * Since the applications require more choices, the driver has to
+ * program the HW to do its best and to convert between the HW and
+ * actual timebases.
*/
-
return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
}
-static void
-set_timebase(int midi_dev, int val)
+static void set_timebase(int midi_dev, int val)
{
- int hw_val;
+ int hw_val;
if (val < 48)
val = 48;
@@ -1314,19 +1252,18 @@ set_timebase(int midi_dev, int val)
hw_val = max_timebase;
if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0)
- {
- printk("MPU: Can't set HW timebase to %d\n", hw_val * 24);
- return;
- }
+ {
+ printk(KERN_WARNING "mpu401: Can't set HW timebase to %d\n", hw_val * 24);
+ return;
+ }
hw_timebase = hw_val * 24;
curr_timebase = val;
}
-static void
-tmr_reset(void)
+static void tmr_reset(void)
{
- unsigned long flags;
+ unsigned long flags;
save_flags(flags);
cli();
@@ -1336,8 +1273,7 @@ tmr_reset(void)
restore_flags(flags);
}
-static void
-set_timer_mode(int midi_dev)
+static void set_timer_mode(int midi_dev)
{
if (timer_mode & TMR_MODE_CLS)
mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */
@@ -1345,31 +1281,31 @@ set_timer_mode(int midi_dev)
mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */
if (timer_mode & TMR_INTERNAL)
- {
+ {
mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */
- } else
- {
- if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
- {
- mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */
- mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
- } else if (timer_mode & TMR_MODE_FSK)
- mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */
- }
+ }
+ else
+ {
+ if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
+ {
+ mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */
+ mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
+ }
+ else if (timer_mode & TMR_MODE_FSK)
+ mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */
+ }
}
-static void
-stop_metronome(int midi_dev)
+static void stop_metronome(int midi_dev)
{
mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */
}
-static void
-setup_metronome(int midi_dev)
+static void setup_metronome(int midi_dev)
{
- int numerator, denominator;
- int clks_per_click, num_32nds_per_beat;
- int beats_per_measure;
+ int numerator, denominator;
+ int clks_per_click, num_32nds_per_beat;
+ int beats_per_measure;
numerator = ((unsigned) metronome_mode >> 24) & 0xff;
denominator = ((unsigned) metronome_mode >> 16) & 0xff;
@@ -1380,15 +1316,14 @@ setup_metronome(int midi_dev)
if (!metronome_mode)
mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */
else
- {
- mpu_cmd(midi_dev, 0xE4, clks_per_click);
- mpu_cmd(midi_dev, 0xE6, beats_per_measure);
- mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */
- }
+ {
+ mpu_cmd(midi_dev, 0xE4, clks_per_click);
+ mpu_cmd(midi_dev, 0xE6, beats_per_measure);
+ mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without accents */
+ }
}
-static int
-mpu_start_timer(int midi_dev)
+static int mpu_start_timer(int midi_dev)
{
tmr_reset();
set_timer_mode(midi_dev);
@@ -1397,25 +1332,24 @@ mpu_start_timer(int midi_dev)
return TIMER_NOT_ARMED; /* Already running */
if (timer_mode & TMR_INTERNAL)
- {
- mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */
- tmr_running = 1;
- return TIMER_NOT_ARMED;
- } else
- {
- mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */
- mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */
- mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */
- mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */
- }
-
+ {
+ mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */
+ tmr_running = 1;
+ return TIMER_NOT_ARMED;
+ }
+ else
+ {
+ mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */
+ mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */
+ mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */
+ mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */
+ }
return TIMER_ARMED;
}
-static int
-mpu_timer_open(int dev, int mode)
+static int mpu_timer_open(int dev, int mode)
{
- int midi_dev = sound_timer_devs[dev]->devlink;
+ int midi_dev = sound_timer_devs[dev]->devlink;
if (timer_open)
return -EBUSY;
@@ -1435,10 +1369,9 @@ mpu_timer_open(int dev, int mode)
return 0;
}
-static void
-mpu_timer_close(int dev)
+static void mpu_timer_close(int dev)
{
- int midi_dev = sound_timer_devs[dev]->devlink;
+ int midi_dev = sound_timer_devs[dev]->devlink;
timer_open = tmr_running = 0;
mpu_cmd(midi_dev, 0x15, 0); /* Stop all */
@@ -1447,86 +1380,80 @@ mpu_timer_close(int dev)
stop_metronome(midi_dev);
}
-static int
-mpu_timer_event(int dev, unsigned char *event)
+static int mpu_timer_event(int dev, unsigned char *event)
{
- unsigned char command = event[1];
- unsigned long parm = *(unsigned int *) &event[4];
- int midi_dev = sound_timer_devs[dev]->devlink;
+ unsigned char command = event[1];
+ unsigned long parm = *(unsigned int *) &event[4];
+ int midi_dev = sound_timer_devs[dev]->devlink;
switch (command)
- {
- case TMR_WAIT_REL:
- parm += prev_event_time;
- case TMR_WAIT_ABS:
- if (parm > 0)
- {
- long time;
-
- if (parm <= curr_ticks) /* It's the time */
- return TIMER_NOT_ARMED;
-
- time = parm;
- next_event_time = prev_event_time = time;
-
- return TIMER_ARMED;
- }
- break;
-
- case TMR_START:
- if (tmr_running)
- break;
- return mpu_start_timer(midi_dev);
- break;
-
- case TMR_STOP:
- mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
- stop_metronome(midi_dev);
- tmr_running = 0;
- break;
-
- case TMR_CONTINUE:
- if (tmr_running)
- break;
- mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
- setup_metronome(midi_dev);
- tmr_running = 1;
- break;
-
- case TMR_TEMPO:
- if (parm)
- {
- if (parm < 8)
- parm = 8;
- if (parm > 250)
- parm = 250;
-
- if (mpu_cmd(midi_dev, 0xE0, parm) < 0)
- printk("MPU: Can't set tempo to %d\n", (int) parm);
- curr_tempo = parm;
- }
- break;
-
- case TMR_ECHO:
- seq_copy_to_input(event, 8);
- break;
-
- case TMR_TIMESIG:
- if (metronome_mode) /* Metronome enabled */
- {
- metronome_mode = parm;
- setup_metronome(midi_dev);
- }
- break;
-
- default:;
- }
+ {
+ case TMR_WAIT_REL:
+ parm += prev_event_time;
+ case TMR_WAIT_ABS:
+ if (parm > 0)
+ {
+ long time;
+
+ if (parm <= curr_ticks) /* It's the time */
+ return TIMER_NOT_ARMED;
+ time = parm;
+ next_event_time = prev_event_time = time;
+
+ return TIMER_ARMED;
+ }
+ break;
+
+ case TMR_START:
+ if (tmr_running)
+ break;
+ return mpu_start_timer(midi_dev);
+
+ case TMR_STOP:
+ mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
+ stop_metronome(midi_dev);
+ tmr_running = 0;
+ break;
+ case TMR_CONTINUE:
+ if (tmr_running)
+ break;
+ mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
+ setup_metronome(midi_dev);
+ tmr_running = 1;
+ break;
+
+ case TMR_TEMPO:
+ if (parm)
+ {
+ if (parm < 8)
+ parm = 8;
+ if (parm > 250)
+ parm = 250;
+ if (mpu_cmd(midi_dev, 0xE0, parm) < 0)
+ printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) parm);
+ curr_tempo = parm;
+ }
+ break;
+
+ case TMR_ECHO:
+ seq_copy_to_input(event, 8);
+ break;
+
+ case TMR_TIMESIG:
+ if (metronome_mode) /* Metronome enabled */
+ {
+ metronome_mode = parm;
+ setup_metronome(midi_dev);
+ }
+ break;
+
+ default:
+ }
return TIMER_NOT_ARMED;
}
-static unsigned long
-mpu_timer_get_time(int dev)
+static unsigned long mpu_timer_get_time(int dev)
{
if (!timer_open)
return 0;
@@ -1534,128 +1461,115 @@ mpu_timer_get_time(int dev)
return curr_ticks;
}
-static int
-mpu_timer_ioctl(int dev,
- unsigned int command, caddr_t arg)
+static int mpu_timer_ioctl(int dev, unsigned int command, caddr_t arg)
{
- int midi_dev = sound_timer_devs[dev]->devlink;
+ int midi_dev = sound_timer_devs[dev]->devlink;
switch (command)
- {
- case SNDCTL_TMR_SOURCE:
- {
- int parm;
-
- parm = *(int *) arg;
- parm &= timer_caps;
-
- if (parm != 0)
- {
- timer_mode = parm;
-
- if (timer_mode & TMR_MODE_CLS)
- mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */
- else if (timer_mode & TMR_MODE_SMPTE)
- mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */
- }
- return (*(int *) arg = timer_mode);
- }
- break;
-
- case SNDCTL_TMR_START:
- mpu_start_timer(midi_dev);
- return 0;
- break;
-
- case SNDCTL_TMR_STOP:
- tmr_running = 0;
- mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
- stop_metronome(midi_dev);
- return 0;
- break;
-
- case SNDCTL_TMR_CONTINUE:
- if (tmr_running)
- return 0;
- tmr_running = 1;
- mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
- return 0;
- break;
-
- case SNDCTL_TMR_TIMEBASE:
- {
- int val;
-
- val = *(int *) arg;
- if (val)
- set_timebase(midi_dev, val);
-
- return (*(int *) arg = curr_timebase);
- }
- break;
-
- case SNDCTL_TMR_TEMPO:
- {
- int val;
- int ret;
-
- val = *(int *) arg;
-
- if (val)
- {
- if (val < 8)
- val = 8;
- if (val > 250)
- val = 250;
- if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0)
- {
- printk("MPU: Can't set tempo to %d\n", (int) val);
- return ret;
- }
- curr_tempo = val;
- }
- return (*(int *) arg = curr_tempo);
- }
- break;
-
- case SNDCTL_SEQ_CTRLRATE:
- {
- int val;
-
- val = *(int *) arg;
- if (val != 0) /* Can't change */
- return -EINVAL;
-
- return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
- }
- break;
-
- case SNDCTL_SEQ_GETTIME:
- return (*(int *) arg = curr_ticks);
- break;
-
- case SNDCTL_TMR_METRONOME:
- metronome_mode = *(int *) arg;
- setup_metronome(midi_dev);
- return 0;
- break;
-
- default:;
- }
+ {
+ case SNDCTL_TMR_SOURCE:
+ {
+ int parm;
+
+ parm = *(int *) arg;
+ parm &= timer_caps;
+ if (parm != 0)
+ {
+ timer_mode = parm;
+
+ if (timer_mode & TMR_MODE_CLS)
+ mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */
+ else if (timer_mode & TMR_MODE_SMPTE)
+ mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */
+ }
+ return (*(int *) arg = timer_mode);
+ }
+ break;
+
+ case SNDCTL_TMR_START:
+ mpu_start_timer(midi_dev);
+ return 0;
+
+ case SNDCTL_TMR_STOP:
+ tmr_running = 0;
+ mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
+ stop_metronome(midi_dev);
+ return 0;
+
+ case SNDCTL_TMR_CONTINUE:
+ if (tmr_running)
+ return 0;
+ tmr_running = 1;
+ mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
+ return 0;
+
+ case SNDCTL_TMR_TIMEBASE:
+ {
+ int val;
+
+ val = *(int *) arg;
+ if (val)
+ set_timebase(midi_dev, val);
+ return (*(int *) arg = curr_timebase);
+ }
+ break;
+
+ case SNDCTL_TMR_TEMPO:
+ {
+ int val;
+ int ret;
+
+ val = *(int *) arg;
+
+ if (val)
+ {
+ if (val < 8)
+ val = 8;
+ if (val > 250)
+ val = 250;
+ if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0)
+ {
+ printk(KERN_WARNING "mpu401: Can't set tempo to %d\n", (int) val);
+ return ret;
+ }
+ curr_tempo = val;
+ }
+ return (*(int *) arg = curr_tempo);
+ }
+ break;
+
+ case SNDCTL_SEQ_CTRLRATE:
+ {
+ int val;
+
+ val = *(int *) arg;
+ if (val != 0) /* Can't change */
+ return -EINVAL;
+ return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
+ }
+ break;
+
+ case SNDCTL_SEQ_GETTIME:
+ return (*(int *) arg = curr_ticks);
+
+ case SNDCTL_TMR_METRONOME:
+ metronome_mode = *(int *) arg;
+ setup_metronome(midi_dev);
+ return 0;
+
+ default:
+ }
return -EINVAL;
}
-static void
-mpu_timer_arm(int dev, long time)
+static void mpu_timer_arm(int dev, long time)
{
if (time < 0)
time = curr_ticks + 1;
else if (time <= curr_ticks) /* It's the time */
return;
-
next_event_time = prev_event_time = time;
-
return;
}
@@ -1672,10 +1586,8 @@ static struct sound_timer_operations mpu_timer =
mpu_timer_arm
};
-static void
-mpu_timer_interrupt(void)
+static void mpu_timer_interrupt(void)
{
-
if (!timer_open)
return;
@@ -1686,10 +1598,10 @@ mpu_timer_interrupt(void)
curr_ticks = clocks2ticks(curr_clocks);
if (curr_ticks >= next_event_time)
- {
- next_event_time = (unsigned long) -1;
- sequencer_timer(0);
- }
+ {
+ next_event_time = (unsigned long) -1;
+ sequencer_timer(0);
+ }
}
static void timer_ext_event(struct mpu_config *devc, int event, int parm)
@@ -1706,8 +1618,9 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm)
break;
case TMR_START:
- printk("Ext MIDI start\n");
+ printk("Ext MIDI start\n");
if (!tmr_running)
+ {
if (timer_mode & TMR_EXTERNAL)
{
tmr_running = 1;
@@ -1715,6 +1628,7 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm)
next_event_time = 0;
STORE(SEQ_START_TIMER());
}
+ }
break;
case TMR_STOP:
diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c
index 36734c2e7..cd768801f 100644
--- a/drivers/sound/opl3.c
+++ b/drivers/sound/opl3.c
@@ -2,25 +2,30 @@
* sound/opl3.c
*
* A low level driver for Yamaha YM3812 and OPL-3 -chips
- */
-/*
+ *
+*
* Copyright (C) by Hannu Savolainen 1993-1997
*
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ *
+ * Changes
+ * Thomas Sailer ioctl code reworked (vmalloc/vfree removed)
+ * Alan Cox modularisation, fixed sound_mem allocs.
+ *
+ * Status
+ * Believed to work. Badly needs rewriting a bit to support multiple
+ * OPL3 devices.
*/
-/*
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- */
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
/*
* Major improvements to the FM handling 30AUG92 by Rob Hooft,
- */
-/*
* hooft@chem.ruu.nl
*/
@@ -109,32 +114,32 @@ static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg)
struct sbi_instrument ins;
switch (cmd) {
- case SNDCTL_FM_LOAD_INSTR:
- printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
- if (__copy_from_user(&ins, arg, sizeof(ins)))
- return -EFAULT;
- if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
- printk("FM Error: Invalid instrument number %d\n", ins.channel);
- return -EINVAL;
- }
- return store_instr(ins.channel, &ins);
+ case SNDCTL_FM_LOAD_INSTR:
+ printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
+ if (copy_from_user(&ins, arg, sizeof(ins)))
+ return -EFAULT;
+ if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
+ printk(KERN_WARNING "FM Error: Invalid instrument number %d\n", ins.channel);
+ return -EINVAL;
+ }
+ return store_instr(ins.channel, &ins);
- case SNDCTL_SYNTH_INFO:
- devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
- if (__copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)))
- return -EFAULT;
- return 0;
+ case SNDCTL_SYNTH_INFO:
+ devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
+ if (copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)))
+ return -EFAULT;
+ return 0;
- case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
+ case SNDCTL_SYNTH_MEMAVL:
+ return 0x7fffffff;
- case SNDCTL_FM_4OP_ENABLE:
- if (devc->model == 2)
- enter_4op_mode();
- return 0;
+ case SNDCTL_FM_4OP_ENABLE:
+ if (devc->model == 2)
+ enter_4op_mode();
+ return 0;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
}
@@ -151,8 +156,8 @@ int opl3_detect(int ioaddr, int *osp)
* Note2! The chip is initialized if detected.
*/
- unsigned char stat1, signature;
- int i;
+ unsigned char stat1, signature;
+ int i;
if (devc != NULL)
{
@@ -160,10 +165,7 @@ int opl3_detect(int ioaddr, int *osp)
return 0;
}
- devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(*devc)));
- sound_mem_sizes[sound_nblocks] = sizeof(*devc);
- if (sound_nblocks < 1024)
- sound_nblocks++;;
+ devc = (struct opl_devinfo *)kmalloc(sizeof(*devc), GFP_KERNEL);
if (devc == NULL)
{
@@ -333,7 +335,7 @@ static char fm_volume_table[128] =
static void calc_vol(unsigned char *regbyte, int volume, int main_vol)
{
- int level = (~*regbyte & 0x3f);
+ int level = (~*regbyte & 0x3f);
if (main_vol > 127)
main_vol = 127;
@@ -814,7 +816,8 @@ static int opl3_load_patch(int dev, int format, const char *addr,
return -EINVAL;
}
- copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs);
+ if(copy_from_user(&((char *) &ins)[offs], &(addr)[offs], sizeof(ins) - offs))
+ return -EFAULT;
if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
{
@@ -1199,6 +1202,7 @@ void cleanup_module(void)
{
if (devc)
{
+ kfree(devc);
devc = NULL;
sound_unload_synthdev(me);
}
diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c
index 656034d54..bf95b84d5 100644
--- a/drivers/sound/pas2_card.c
+++ b/drivers/sound/pas2_card.c
@@ -164,7 +164,7 @@ static int config_pas_hw(struct address_info *hw_config)
}
else
{
- if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0)
+ if (request_irq(pas_irq, pasintr, "PAS16", 0, NULL) < 0)
ok = 0;
}
}
@@ -355,7 +355,7 @@ void
unload_pas(struct address_info *hw_config)
{
sound_free_dma(hw_config->dma);
- snd_release_irq(hw_config->irq);
+ free_irq(hw_config->irq, NULL);
}
#ifdef MODULE
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c
index 9d62dd485..7a0a2e66e 100644
--- a/drivers/sound/pss.c
+++ b/drivers/sound/pss.c
@@ -11,7 +11,8 @@
* for more info.
*/
/*
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer ioctl code reworked (vmalloc/vfree removed)
+ * Alan Cox modularisation, clean up.
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -62,12 +63,12 @@ static int pss_synthLen = 0;
#endif
typedef struct pss_confdata
- {
- int base;
- int irq;
- int dma;
- int *osp;
- }
+{
+ int base;
+ int irq;
+ int dma;
+ int *osp;
+}
pss_confdata;
@@ -77,12 +78,11 @@ static pss_confdata *devc = &pss_data;
static int pss_initialized = 0;
static int nonstandard_microcode = 0;
-static void
-pss_write(int data)
+static void pss_write(int data)
{
- int i, limit;
+ int i, limit;
- limit = jiffies + 10; /* The timeout is 0.1 seconds */
+ limit = jiffies + HZ/10; /* The timeout is 0.1 seconds */
/*
* Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
@@ -92,21 +92,20 @@ pss_write(int data)
*/
for (i = 0; i < 5000000 && jiffies < limit; i++)
- {
- if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
- {
- outw(devc->base + PSS_DATA, data);
- return;
- }
- }
- printk("PSS: DSP Command (%04x) Timeout.\n", data);
+ {
+ if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
+ {
+ outw(devc->base + PSS_DATA, data);
+ return;
+ }
+ }
+ printk(KERN_ERR "PSS: DSP Command (%04x) Timeout.\n", data);
}
-int
-probe_pss(struct address_info *hw_config)
+int probe_pss(struct address_info *hw_config)
{
- unsigned short id;
- int irq, dma;
+ unsigned short id;
+ int irq, dma;
devc->base = hw_config->io_base;
irq = devc->irq = hw_config->irq;
@@ -129,8 +128,7 @@ probe_pss(struct address_info *hw_config)
return 1;
}
-static int
-set_irq(pss_confdata * devc, int dev, int irq)
+static int set_irq(pss_confdata * devc, int dev, int irq)
{
static unsigned short irq_bits[16] =
{
@@ -148,16 +146,15 @@ set_irq(pss_confdata * devc, int dev, int irq)
tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */
if ((bits = irq_bits[irq]) == 0 && irq != 0)
- {
- printk("PSS: Invalid IRQ %d\n", irq);
- return 0;
- }
+ {
+ printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq);
+ return 0;
+ }
outw(tmp | bits, REG(dev));
return 1;
}
-static int
-set_io_base(pss_confdata * devc, int dev, int base)
+static int set_io_base(pss_confdata * devc, int dev, int base)
{
unsigned short tmp = inw(REG(dev)) & 0x003f;
unsigned short bits = (base & 0x0ffc) << 4;
@@ -167,8 +164,7 @@ set_io_base(pss_confdata * devc, int dev, int base)
return 1;
}
-static int
-set_dma(pss_confdata * devc, int dev, int dma)
+static int set_dma(pss_confdata * devc, int dev, int dma)
{
static unsigned short dma_bits[8] =
{
@@ -184,150 +180,139 @@ set_dma(pss_confdata * devc, int dev, int dma)
tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */
if ((bits = dma_bits[dma]) == 0 && dma != 4)
- {
- printk("PSS: Invalid DMA %d\n", dma);
+ {
+ printk(KERN_ERR "PSS: Invalid DMA %d\n", dma);
return 0;
- }
+ }
outw(tmp | bits, REG(dev));
return 1;
}
-static int
-pss_reset_dsp(pss_confdata * devc)
+static int pss_reset_dsp(pss_confdata * devc)
{
- unsigned long i, limit = jiffies + 10;
+ unsigned long i, limit = jiffies + HZ/10;
outw(0x2000, REG(PSS_CONTROL));
-
- for (i = 0; i < 32768 && jiffies < limit; i++)
+ for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
inw(REG(PSS_CONTROL));
-
outw(0x0000, REG(PSS_CONTROL));
-
return 1;
}
-static int
-pss_put_dspword(pss_confdata * devc, unsigned short word)
+static int pss_put_dspword(pss_confdata * devc, unsigned short word)
{
- int i, val;
+ int i, val;
for (i = 0; i < 327680; i++)
- {
- val = inw(REG(PSS_STATUS));
- if (val & PSS_WRITE_EMPTY)
- {
- outw(word, REG(PSS_DATA));
- return 1;
- }
- }
+ {
+ val = inw(REG(PSS_STATUS));
+ if (val & PSS_WRITE_EMPTY)
+ {
+ outw(word, REG(PSS_DATA));
+ return 1;
+ }
+ }
return 0;
}
-static int
-pss_get_dspword(pss_confdata * devc, unsigned short *word)
+static int pss_get_dspword(pss_confdata * devc, unsigned short *word)
{
- int i, val;
+ int i, val;
for (i = 0; i < 327680; i++)
- {
- val = inw(REG(PSS_STATUS));
- if (val & PSS_READ_FULL)
- {
- *word = inw(REG(PSS_DATA));
- return 1;
- }
- }
-
+ {
+ val = inw(REG(PSS_STATUS));
+ if (val & PSS_READ_FULL)
+ {
+ *word = inw(REG(PSS_DATA));
+ return 1;
+ }
+ }
return 0;
}
-static int
-pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags)
+static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags)
{
- int i, limit, val, count;
+ int i, limit, val, count;
if (flags & CPF_FIRST)
- {
+ {
/*_____ Warn DSP software that a boot is coming */
- outw(0x00fe, REG(PSS_DATA));
-
- limit = jiffies + 10;
+ outw(0x00fe, REG(PSS_DATA));
- for (i = 0; i < 32768 && jiffies < limit; i++)
- if (inw(REG(PSS_DATA)) == 0x5500)
- break;
-
- outw(*block++, REG(PSS_DATA));
+ limit = jiffies + HZ/10;
+ for (i = 0; i < 32768 && jiffies < limit; i++)
+ if (inw(REG(PSS_DATA)) == 0x5500)
+ break;
- pss_reset_dsp(devc);
- }
+ outw(*block++, REG(PSS_DATA));
+ pss_reset_dsp(devc);
+ }
count = 1;
while (1)
- {
- int j;
+ {
+ int j;
- for (j = 0; j < 327670; j++)
- {
+ for (j = 0; j < 327670; j++)
+ {
/*_____ Wait for BG to appear */
- if (inw(REG(PSS_STATUS)) & PSS_FLAG3)
- break;
- }
-
- if (j == 327670)
- {
- /* It's ok we timed out when the file was empty */
- if (count >= size && flags & CPF_LAST)
- break;
- else
- {
- printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
- return 0;
- }
- }
+ if (inw(REG(PSS_STATUS)) & PSS_FLAG3)
+ break;
+ }
+
+ if (j == 327670)
+ {
+ /* It's ok we timed out when the file was empty */
+ if (count >= size && flags & CPF_LAST)
+ break;
+ else
+ {
+ printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
+ return 0;
+ }
+ }
/*_____ Send the next byte */
- outw(*block++, REG(PSS_DATA));
- count++;
- }
+ outw(*block++, REG(PSS_DATA));
+ count++;
+ }
if (flags & CPF_LAST)
- {
+ {
/*_____ Why */
- outw(0, REG(PSS_DATA));
-
- limit = jiffies + 10;
- for (i = 0; i < 32768 && jiffies < limit; i++)
- val = inw(REG(PSS_STATUS));
-
- limit = jiffies + 10;
- for (i = 0; i < 32768 && jiffies < limit; i++)
- {
- val = inw(REG(PSS_STATUS));
- if (val & 0x4000)
- break;
- }
-
- /* now read the version */
- for (i = 0; i < 32000; i++)
- {
- val = inw(REG(PSS_STATUS));
- if (val & PSS_READ_FULL)
- break;
- }
- if (i == 32000)
- return 0;
-
- val = inw(REG(PSS_DATA));
- /* printk( "<PSS: microcode version %d.%d loaded>", val/16, val % 16); */
- }
+ outw(0, REG(PSS_DATA));
+
+ limit = jiffies + HZ/10;
+ for (i = 0; i < 32768 && (limit - jiffies >= 0); i++)
+ val = inw(REG(PSS_STATUS));
+
+ limit = jiffies + HZ/10;
+ for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)
+ {
+ val = inw(REG(PSS_STATUS));
+ if (val & 0x4000)
+ break;
+ }
+
+ /* now read the version */
+ for (i = 0; i < 32000; i++)
+ {
+ val = inw(REG(PSS_STATUS));
+ if (val & PSS_READ_FULL)
+ break;
+ }
+ if (i == 32000)
+ return 0;
+
+ val = inw(REG(PSS_DATA));
+ /* printk( "<PSS: microcode version %d.%d loaded>", val/16, val % 16); */
+ }
return 1;
}
-void
-attach_pss(struct address_info *hw_config)
+void attach_pss(struct address_info *hw_config)
{
unsigned short id;
- char tmp[100];
+ char tmp[100];
devc->base = hw_config->io_base;
devc->irq = hw_config->irq;
@@ -350,20 +335,20 @@ attach_pss(struct address_info *hw_config)
#if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES
if (sound_alloc_dma(hw_config->dma, "PSS"))
- {
- printk("pss.c: Can't allocate DMA channel\n");
- return;
- }
+ {
+ printk("pss.c: Can't allocate DMA channel.\n");
+ return;
+ }
if (!set_irq(devc, CONF_PSS, devc->irq))
- {
- printk("PSS: IRQ error\n");
- return;
- }
+ {
+ printk("PSS: IRQ allocation error.\n");
+ return;
+ }
if (!set_dma(devc, CONF_PSS, devc->dma))
- {
- printk("PSS: DRQ error\n");
- return;
- }
+ {
+ printk(KERN_ERR "PSS: DMA allocation error\n");
+ return;
+ }
#endif
pss_initialized = 1;
@@ -371,8 +356,7 @@ attach_pss(struct address_info *hw_config)
conf_printf(tmp, hw_config);
}
-static void
-pss_init_speaker(void)
+static void pss_init_speaker(void)
{
/* Don't ask what are these commands. I really don't know */
pss_write(0x0010);
@@ -387,53 +371,52 @@ pss_init_speaker(void)
pss_write(0x0800 | 0x00ce); /* Stereo switch? */
}
-int
-probe_pss_mpu(struct address_info *hw_config)
+int probe_pss_mpu(struct address_info *hw_config)
{
- int timeout;
+ int timeout;
if (!pss_initialized)
return 0;
if (check_region(hw_config->io_base, 2))
- {
- printk("PSS: MPU I/O port conflict\n");
- return 0;
- }
+ {
+ printk("PSS: MPU I/O port conflict\n");
+ return 0;
+ }
if (!set_io_base(devc, CONF_MIDI, hw_config->io_base))
- {
- printk("PSS: MIDI base error.\n");
+ {
+ printk("PSS: MIDI base could not be set.\n");
return 0;
- }
+ }
if (!set_irq(devc, CONF_MIDI, hw_config->irq))
- {
- printk("PSS: MIDI IRQ error.\n");
+ {
+ printk("PSS: MIDI IRQ allocation error.\n");
return 0;
- }
+ }
if (!pss_synthLen)
- {
- printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n");
- return 0;
- }
+ {
+ printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n");
+ return 0;
+ }
if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
- {
- printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
- return 0;
- }
+ {
+ printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+ return 0;
+ }
pss_init_speaker();
-/*
- * Finally wait until the DSP algorithm has initialized itself and
- * deactivates receive interrupt.
- */
+ /*
+ * Finally wait until the DSP algorithm has initialized itself and
+ * deactivates receive interrupt.
+ */
for (timeout = 900000; timeout > 0; timeout--)
- {
- if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */
- inb(hw_config->io_base); /* Discard it */
- else
- break; /* No more input */
- }
+ {
+ if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */
+ inb(hw_config->io_base); /* Discard it */
+ else
+ break; /* No more input */
+ }
#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
return probe_mpu401(hw_config);
@@ -442,62 +425,56 @@ probe_pss_mpu(struct address_info *hw_config)
#endif
}
-static int
-pss_coproc_open(void *dev_info, int sub_device)
+static int pss_coproc_open(void *dev_info, int sub_device)
{
switch (sub_device)
- {
- case COPR_MIDI:
-
- if (pss_synthLen == 0)
- {
- printk("PSS: MIDI synth microcode not available.\n");
- return -EIO;
- }
- if (nonstandard_microcode)
- if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
- {
- printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
- return -EIO;
- }
- nonstandard_microcode = 0;
- break;
-
- default:;
- }
+ {
+ case COPR_MIDI:
+ if (pss_synthLen == 0)
+ {
+ printk(KERN_ERR "PSS: MIDI synth microcode not available.\n");
+ return -EIO;
+ }
+ if (nonstandard_microcode)
+ if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
+ {
+ printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+ return -EIO;
+ }
+ nonstandard_microcode = 0;
+ break;
+
+ default:
+ }
return 0;
}
-static void
-pss_coproc_close(void *dev_info, int sub_device)
+static void pss_coproc_close(void *dev_info, int sub_device)
{
return;
}
-static void
-pss_coproc_reset(void *dev_info)
+static void pss_coproc_reset(void *dev_info)
{
if (pss_synthLen)
if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
- {
- printk("PSS: Unable to load MIDI synth microcode to DSP.\n");
- }
+ {
+ printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n");
+ }
nonstandard_microcode = 0;
}
-static int
-download_boot_block(void *dev_info, copr_buffer * buf)
+static int download_boot_block(void *dev_info, copr_buffer * buf)
{
if (buf->len <= 0 || buf->len > sizeof(buf->data))
return -EINVAL;
if (!pss_download_boot(devc, buf->data, buf->len, buf->flags))
- {
- printk("PSS: Unable to load microcode block to DSP.\n");
- return -EIO;
- }
+ {
+ printk(KERN_ERR "PSS: Unable to load microcode block to DSP.\n");
+ return -EIO;
+ }
nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */
-
return 0;
}
@@ -512,169 +489,170 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l
int i, err;
/* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */
- switch (cmd) {
- case SNDCTL_COPR_RESET:
- pss_coproc_reset(dev_info);
- return 0;
+ switch (cmd)
+ {
+ case SNDCTL_COPR_RESET:
+ pss_coproc_reset(dev_info);
+ return 0;
- case SNDCTL_COPR_LOAD:
- buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
- if (buf == NULL)
- return -ENOSPC;
- if (__copy_from_user(buf, arg, sizeof(copr_buffer))) {
+ case SNDCTL_COPR_LOAD:
+ buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+ if (buf == NULL)
+ return -ENOSPC;
+ if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
+ vfree(buf);
+ return -EFAULT;
+ }
+ err = download_boot_block(dev_info, buf);
vfree(buf);
- return -EFAULT;
- }
- err = download_boot_block(dev_info, buf);
- vfree(buf);
- return err;
+ return err;
- case SNDCTL_COPR_SENDMSG:
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
- if (mbuf == NULL)
- return -ENOSPC;
- if (__copy_from_user(mbuf, arg, sizeof(copr_msg))) {
- vfree(mbuf);
- return -EFAULT;
- }
- data = (unsigned short *)(mbuf->data);
- save_flags(flags);
- cli();
- for (i = 0; i < mbuf->len; i++) {
- if (!pss_put_dspword(devc, *data++)) {
- restore_flags(flags);
- mbuf->len = i; /* feed back number of WORDs sent */
- err = __copy_to_user(arg, mbuf, sizeof(copr_msg));
+ case SNDCTL_COPR_SENDMSG:
+ mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ if (mbuf == NULL)
+ return -ENOSPC;
+ if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
vfree(mbuf);
- return err ? -EFAULT : -EIO;
+ return -EFAULT;
}
- }
- restore_flags(flags);
- vfree(mbuf);
- return 0;
-
- case SNDCTL_COPR_RCVMSG:
- err = 0;
- mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
- if (mbuf == NULL)
- return -ENOSPC;
- data = (unsigned short *)mbuf->data;
- save_flags(flags);
- cli();
- for (i = 0; i < mbuf->len; i++) {
- mbuf->len = i; /* feed back number of WORDs read */
- if (!pss_get_dspword(devc, data++)) {
- if (i == 0)
- err = -EIO;
- break;
+ data = (unsigned short *)(mbuf->data);
+ save_flags(flags);
+ cli();
+ for (i = 0; i < mbuf->len; i++) {
+ if (!pss_put_dspword(devc, *data++)) {
+ restore_flags(flags);
+ mbuf->len = i; /* feed back number of WORDs sent */
+ err = copy_to_user(arg, mbuf, sizeof(copr_msg));
+ vfree(mbuf);
+ return err ? -EFAULT : -EIO;
+ }
}
- }
- restore_flags(flags);
- if (__copy_to_user(arg, mbuf, sizeof(copr_msg)))
- err = -EFAULT;
- vfree(mbuf);
- return err;
-
- case SNDCTL_COPR_RDATA:
- if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
- return -EFAULT;
- save_flags(flags);
- cli();
- if (!pss_put_dspword(devc, 0x00d0)) {
- restore_flags(flags);
- return -EIO;
- }
- if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
restore_flags(flags);
- return -EIO;
- }
- if (!pss_get_dspword(devc, &tmp)) {
+ vfree(mbuf);
+ return 0;
+
+ case SNDCTL_COPR_RCVMSG:
+ err = 0;
+ mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+ if (mbuf == NULL)
+ return -ENOSPC;
+ data = (unsigned short *)mbuf->data;
+ save_flags(flags);
+ cli();
+ for (i = 0; i < mbuf->len; i++) {
+ mbuf->len = i; /* feed back number of WORDs read */
+ if (!pss_get_dspword(devc, data++)) {
+ if (i == 0)
+ err = -EIO;
+ break;
+ }
+ }
restore_flags(flags);
- return -EIO;
- }
- dbuf.parm1 = tmp;
- restore_flags(flags);
- if (__copy_to_user(arg, &dbuf, sizeof(dbuf)))
- return -EFAULT;
- return 0;
+ if (copy_to_user(arg, mbuf, sizeof(copr_msg)))
+ err = -EFAULT;
+ vfree(mbuf);
+ return err;
- case SNDCTL_COPR_WDATA:
- if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
- return -EFAULT;
- save_flags(flags);
- cli();
- if (!pss_put_dspword(devc, 0x00d1)) {
- restore_flags(flags);
- return -EIO;
- }
- if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) {
- restore_flags(flags);
- return -EIO;
- }
- tmp = (unsigned int)dbuf.parm2 & 0xffff;
- if (!pss_put_dspword(devc, tmp)) {
+ case SNDCTL_COPR_RDATA:
+ if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+ return -EFAULT;
+ save_flags(flags);
+ cli();
+ if (!pss_put_dspword(devc, 0x00d0)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_get_dspword(devc, &tmp)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ dbuf.parm1 = tmp;
restore_flags(flags);
- return -EIO;
- }
- restore_flags(flags);
- return 0;
+ if (copy_to_user(arg, &dbuf, sizeof(dbuf)))
+ return -EFAULT;
+ return 0;
- case SNDCTL_COPR_WCODE:
- if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
- return -EFAULT;
- save_flags(flags);
- cli();
- if (!pss_put_dspword(devc, 0x00d3)) {
- restore_flags(flags);
- return -EIO;
- }
- if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
- restore_flags(flags);
- return -EIO;
- }
- tmp = (unsigned int)dbuf.parm2 & 0x00ff;
- if (!pss_put_dspword(devc, tmp)) {
- restore_flags(flags);
- return -EIO;
- }
- tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff;
- if (!pss_put_dspword(devc, tmp)) {
+ case SNDCTL_COPR_WDATA:
+ if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+ return -EFAULT;
+ save_flags(flags);
+ cli();
+ if (!pss_put_dspword(devc, 0x00d1)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ tmp = (unsigned int)dbuf.parm2 & 0xffff;
+ if (!pss_put_dspword(devc, tmp)) {
+ restore_flags(flags);
+ return -EIO;
+ }
restore_flags(flags);
- return -EIO;
- }
- restore_flags(flags);
- return 0;
+ return 0;
- case SNDCTL_COPR_RCODE:
- if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
- return -EFAULT;
- save_flags(flags);
- cli();
- if (!pss_put_dspword(devc, 0x00d2)) {
- restore_flags(flags);
- return -EIO;
- }
- if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
- restore_flags(flags);
- return -EIO;
- }
- if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */
+ case SNDCTL_COPR_WCODE:
+ if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+ return -EFAULT;
+ save_flags(flags);
+ cli();
+ if (!pss_put_dspword(devc, 0x00d3)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ tmp = (unsigned int)dbuf.parm2 & 0x00ff;
+ if (!pss_put_dspword(devc, tmp)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff;
+ if (!pss_put_dspword(devc, tmp)) {
+ restore_flags(flags);
+ return -EIO;
+ }
restore_flags(flags);
- return -EIO;
- }
- dbuf.parm1 = tmp << 8;
- if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */
+ return 0;
+
+ case SNDCTL_COPR_RCODE:
+ if (copy_from_user(&dbuf, arg, sizeof(dbuf)))
+ return -EFAULT;
+ save_flags(flags);
+ cli();
+ if (!pss_put_dspword(devc, 0x00d2)) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */
+ restore_flags(flags);
+ return -EIO;
+ }
+ dbuf.parm1 = tmp << 8;
+ if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */
+ restore_flags(flags);
+ return -EIO;
+ }
+ dbuf.parm1 |= tmp & 0x00ff;
restore_flags(flags);
- return -EIO;
- }
- dbuf.parm1 |= tmp & 0x00ff;
- restore_flags(flags);
- if (__copy_to_user(arg, &dbuf, sizeof(dbuf)))
- return -EFAULT;
- return 0;
+ if (copy_to_user(arg, &dbuf, sizeof(dbuf)))
+ return -EFAULT;
+ return 0;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
return -EINVAL;
}
@@ -689,52 +667,47 @@ static coproc_operations pss_coproc_operations =
&pss_data
};
-void
-attach_pss_mpu(struct address_info *hw_config)
+void attach_pss_mpu(struct address_info *hw_config)
{
#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
- {
- attach_mpu401(hw_config); /* Slot 1 */
-
- if (hw_config->slots[1] != -1) /* The MPU driver installed itself */
- midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
- }
+ attach_mpu401(hw_config); /* Slot 1 */
+ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */
+ midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
#endif
}
-int
-probe_pss_mss(struct address_info *hw_config)
+int probe_pss_mss(struct address_info *hw_config)
{
- volatile int timeout;
+ volatile int timeout;
if (!pss_initialized)
return 0;
if (check_region(hw_config->io_base, 8))
- {
- printk("PSS: WSS I/O port conflict\n");
+ {
+ printk(KERN_ERR "PSS: WSS I/O port conflicts.\n");
return 0;
- }
+ }
if (!set_io_base(devc, CONF_WSS, hw_config->io_base))
- {
- printk("PSS: WSS base error.\n");
- return 0;
- }
+ {
+ printk("PSS: WSS base not settable.\n");
+ return 0;
+ }
if (!set_irq(devc, CONF_WSS, hw_config->irq))
- {
- printk("PSS: WSS IRQ error.\n");
- return 0;
- }
+ {
+ printk("PSS: WSS IRQ allocation error.\n");
+ return 0;
+ }
if (!set_dma(devc, CONF_WSS, hw_config->dma))
- {
- printk("PSS: WSS DRQ error\n");
- return 0;
- }
+ {
+ printk(KERN_ERR "PSS: WSS DMA allocation error\n");
+ return 0;
+ }
/*
- * For some reason the card returns 0xff in the WSS status register
- * immediately after boot. Probably MIDI+SB emulation algorithm
- * downloaded to the ADSP2115 spends some time initializing the card.
- * Let's try to wait until it finishes this task.
+ * For some reason the card returns 0xff in the WSS status register
+ * immediately after boot. Probably MIDI+SB emulation algorithm
+ * downloaded to the ADSP2115 spends some time initializing the card.
+ * Let's try to wait until it finishes this task.
*/
for (timeout = 0;
timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04;
@@ -748,8 +721,7 @@ probe_pss_mss(struct address_info *hw_config)
return probe_ms_sound(hw_config);
}
-void
-attach_pss_mss(struct address_info *hw_config)
+void attach_pss_mss(struct address_info *hw_config)
{
attach_ms_sound(hw_config); /* Slot 0 */
@@ -757,34 +729,31 @@ attach_pss_mss(struct address_info *hw_config)
audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations;
}
-void
-unload_pss(struct address_info *hw_config)
+void unload_pss(struct address_info *hw_config)
{
}
-void
-unload_pss_mpu(struct address_info *hw_config)
+void unload_pss_mpu(struct address_info *hw_config)
{
#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
unload_mpu401(hw_config);
#endif
}
-void
-unload_pss_mss(struct address_info *hw_config)
+void unload_pss_mss(struct address_info *hw_config)
{
unload_ms_sound(hw_config);
}
#ifdef MODULE
-int pss_io = 0x220;
+int pss_io = -1;
-int mss_io = 0x530;
-int mss_irq = 11;
-int mss_dma = 1;
+int mss_io = -1;
+int mss_irq = -1;
+int mss_dma = -1;
-int mpu_io = 0x330;
+int mpu_io = -1;
int mpu_irq = -1;
struct address_info cfgpss = { 0 /* pss_io */, 0, -1, -1 };
@@ -798,22 +767,20 @@ MODULE_PARM(mss_dma, "i");
MODULE_PARM(mpu_io, "i");
MODULE_PARM(mpu_irq, "i");
-static int fw_load = 0;
-static int pssmpu = 0, pssmss = 0;
+static int fw_load = 0;
+static int pssmpu = 0, pssmss = 0;
/*
* Load a PSS sound card module
*/
-int
-init_module(void)
+int init_module(void)
{
-#if 0
- if (pss_io == -1 || irq == -1 || dma == -1) {
- printk("pss: dma, irq and io must be set.\n");
- return -EINVAL;
+ if (pss_io == -1 || mss_io == -1 || mss_irq == -1 || mss_dma == -1) {
+ printk(KERN_INFO "pss: mss_io, mss_dma, mss_irq and pss_io must be set.\n");
+ return -EINVAL;
}
-#endif
+
cfgpss.io_base = pss_io;
cfgmss.io_base = mss_io;
@@ -823,7 +790,8 @@ init_module(void)
cfgmpu.io_base = mpu_io;
cfgmpu.irq = mpu_irq;
- if (!pss_synth) {
+ if (!pss_synth)
+ {
fw_load = 1;
pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth);
}
@@ -845,8 +813,7 @@ init_module(void)
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
if (fw_load && pss_synth)
kfree(pss_synth);
diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c
index 9a0fe3c79..bf3a8dbef 100644
--- a/drivers/sound/sb_audio.c
+++ b/drivers/sound/sb_audio.c
@@ -1151,14 +1151,14 @@ void sb_audio_init(sb_devc * devc, char *name)
}
if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- name,
- driver,
- sizeof(struct audio_driver),
- audio_flags,
- format_mask,
- devc,
- devc->dma8,
- devc->dma8)) < 0)
+ name,
+ driver,
+ sizeof(struct audio_driver),
+ audio_flags,
+ format_mask,
+ devc,
+ devc->dma8,
+ devc->dma8)) < 0)
{
printk(KERN_ERR "sb: unable to install audio.\n");
return;
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index fddf74b79..941422c3f 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -69,6 +69,7 @@ int trix = 0; /* Set trix=1 to load this as support for trix */
int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */
int sm_games = 0; /* Mixer - see sb_mixer.c */
int acer = 0; /* Do acer notebook init */
+int mwave_bug = 0; /* Using the dreadful mwave sb emulation */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
@@ -80,10 +81,11 @@ MODULE_PARM(mad16, "i");
MODULE_PARM(trix, "i");
MODULE_PARM(pas2, "i");
MODULE_PARM(sm_games, "i");
+MODULE_PARM(mwave_bug, "i");
-static int sbmpu = 0;
+static int sbmpu = 0;
-void *smw_free = NULL;
+void *smw_free = NULL;
int init_module(void)
{
@@ -119,8 +121,7 @@ int init_module(void)
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
if (smw_free)
kfree(smw_free);
@@ -133,19 +134,20 @@ cleanup_module(void)
#else
-#ifdef SM_GAMES
+#ifdef CONFIG_SM_GAMES
int sm_games = 1;
-
#else
int sm_games = 0;
-
#endif
-#ifdef SB_ACER
+#ifdef CONFIG_SB_ACER
int acer = 1;
-
#else
int acer = 0;
-
+#endif
+#ifdef CONFIG_SB_MWAVE
+int mwave_bug = 1;
+#else
+int mwave_bug = 0;
#endif
#endif
#endif
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 0f3e1e6aa..fcdcfcf2c 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -28,7 +28,6 @@
static sb_devc *detected_devc = NULL; /* For communication from probe to init */
static sb_devc *last_devc = NULL; /* For MPU401 initialization */
-static sb_devc *irq2devc[16] = {NULL};
static unsigned char jazz_irq_bits[] = {
0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6
};
@@ -123,15 +122,9 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy)
int status;
unsigned char src = 0xff;
- sb_devc *devc = irq2devc[irq];
+ sb_devc *devc = dev_id;
- if (devc == NULL || devc->irq != irq)
- {
- DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq));
- return;
- }
devc->irq_ok = 1;
-
if (devc->model == MDL_SB16)
{
src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */
@@ -710,6 +703,7 @@ void sb_dsp_init(struct address_info *hw_config)
sb_devc *devc;
char name[100];
extern int sb_be_quiet;
+ extern int mwave_bug;
/*
* Check if we had detected a SB device earlier
@@ -743,21 +737,19 @@ void sb_dsp_init(struct address_info *hw_config)
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0)
{ /* IRQ setup */
- if (snd_set_irq_handler(hw_config->irq, sbintr, "soundblaster", devc->osp) < 0)
+ if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0)
{
printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq);
sound_unload_audiodev(devc->dev);
return;
}
- irq2devc[hw_config->irq] = devc;
devc->irq_ok = 0;
if (devc->major == 4)
if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */
{
- snd_release_irq(devc->irq);
+ free_irq(devc->irq, devc);
sound_unload_audiodev(devc->dev);
- irq2devc[hw_config->irq] = NULL;
return;
}
if ((devc->type == 0 || devc->type == MDL_ESS) &&
@@ -777,7 +769,7 @@ void sb_dsp_init(struct address_info *hw_config)
/* Skip IRQ detection if SMP (doesn't work) */
devc->irq_ok = 1;
#else
- if (devc->major == 4 && devc->minor <= 11) /* Won't work */
+ if ((devc->major == 4 && devc->minor <= 11 ) || mwave_bug ) /* Won't work */
devc->irq_ok = 1;
else
{
@@ -883,6 +875,7 @@ void sb_dsp_init(struct address_info *hw_config)
}
}
hw_config->card_subtype = devc->model;
+ hw_config->slots[0]=devc->dev;
last_devc = devc; /* For SB MPU detection */
if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0)
@@ -915,15 +908,8 @@ void sb_dsp_disable_recording(int io_base)
void sb_dsp_unload(struct address_info *hw_config)
{
sb_devc *devc;
- int irq = hw_config->irq;
- if (irq < 0)
- irq *= -1;
-
- if (irq > 2 && irq < 16)
- devc = irq2devc[irq];
- else
- devc = NULL;
+ devc = audio_devs[hw_config->slots[0]]->devc;
if (devc && devc->base == hw_config->io_base)
{
@@ -937,12 +923,12 @@ void sb_dsp_unload(struct address_info *hw_config)
}
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0)
{
- snd_release_irq(devc->irq);
- irq2devc[devc->irq] = NULL;
+ free_irq(devc->irq, devc);
sound_unload_mixerdev(devc->my_mixerdev);
sound_unload_mididev(devc->my_mididev);
sound_unload_audiodev(devc->my_dev);
}
+ kfree(devc);
}
else
release_region(hw_config->io_base, 16);
diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h
index aed677c89..416737f65 100644
--- a/drivers/sound/sound_calls.h
+++ b/drivers/sound/sound_calls.h
@@ -11,7 +11,6 @@ int DMAbuf_start_output(int dev, int buff_no, int l);
int DMAbuf_move_wrpointer(int dev, int l);
/* int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); */
void DMAbuf_init(int dev, int dma1, int dma2);
-void DMAbuf_deinit(int dev);
int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
int DMAbuf_open_dma (int dev);
void DMAbuf_close_dma (int dev);
@@ -84,8 +83,9 @@ void MIDIbuf_init(void);
/* From soundcard.c */
void request_sound_timer (int count);
void sound_stop_timer(void);
-int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp);
-void snd_release_irq(int vect);
+/* These two are about to die.. */
+int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp, void *dev_id);
+void snd_release_irq(int vect, void *ptr);
void sound_dma_malloc(int dev);
void sound_dma_free(int dev);
void conf_printf(char *name, struct address_info *hw_config);
diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c
index 8a519e7e2..986668316 100644
--- a/drivers/sound/sound_timer.c
+++ b/drivers/sound/sound_timer.c
@@ -47,6 +47,14 @@ void reprogram_timer(void)
{
unsigned long usecs_per_tick;
+ /*
+ * The user is changing the timer rate before setting a timer
+ * slap, bad bad not allowed.
+ */
+
+ if(!tmr)
+ return;
+
usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
/*
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index e23e5486e..fe3622a73 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -26,7 +26,7 @@
#include <linux/fcntl.h>
#include <linux/ctype.h>
#include <linux/stddef.h>
-#include <linux/kerneld.h>
+#include <linux/kmod.h>
#ifdef __KERNEL__
#include <asm/io.h>
#include <asm/segment.h>
@@ -439,7 +439,7 @@ static int sound_open(struct inode *inode, struct file *file)
case SND_DEV_CTL:
dev >>= 4;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
char modname[20];
sprintf(modname, "mixer%d", dev);
@@ -555,14 +555,14 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg)
{
if (mixdev < 0 || mixdev >= MAX_MIXER_DEV)
return -ENXIO;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
/* Try to load the mixer... */
if (mixer_devs[mixdev] == NULL) {
char modname[20];
sprintf(modname, "mixer%d", mixdev);
request_module(modname);
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
if (mixdev >= num_mixers || !mixer_devs[mixdev])
return -ENXIO;
if (cmd == SOUND_MIXER_INFO)
@@ -801,7 +801,7 @@ free_all_irqs(void)
if (irqs & (1ul << i))
{
printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i);
- snd_release_irq(i);
+ snd_release_irq(i, NULL);
}
}
irqs = 0;
@@ -895,14 +895,14 @@ void cleanup_module(void)
}
#endif
-int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp)
+int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp, void *dev_id)
{
- int retcode;
- unsigned long flags;
+ int retcode;
+ unsigned long flags;
save_flags(flags);
cli();
- retcode = request_irq(interrupt_level, iproc, 0, name, NULL);
+ retcode = request_irq(interrupt_level, iproc, 0, name, dev_id);
if (retcode < 0)
{
@@ -915,13 +915,13 @@ int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct
return retcode;
}
-void snd_release_irq(int vect)
+void snd_release_irq(int vect, void *dev_id)
{
if (!(irqs & (1ul << vect)))
return;
irqs &= ~(1ul << vect);
- free_irq(vect, NULL);
+ free_irq(vect, dev_id);
}
int sound_alloc_dma(int chn, char *deviceID)
diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c
index 7293e9047..2e7ed2a27 100644
--- a/drivers/sound/uart401.c
+++ b/drivers/sound/uart401.c
@@ -9,7 +9,15 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * Alan Cox Reformatted, removed sound_mem usage, use normal Linux
+ * interrupt allocation.
+ *
+ * Status:
+ * Untested
*/
+
#include <linux/config.h>
#include <linux/module.h>
@@ -19,45 +27,43 @@
#if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE)
typedef struct uart401_devc
- {
- int base;
- int irq;
- int *osp;
- void (*midi_input_intr) (int dev, unsigned char data);
- int opened, disabled;
- volatile unsigned char input_byte;
- int my_dev;
- int share_irq;
- }
+{
+ int base;
+ int irq;
+ int *osp;
+ void (*midi_input_intr) (int dev, unsigned char data);
+ int opened, disabled;
+ volatile unsigned char input_byte;
+ int my_dev;
+ int share_irq;
+}
uart401_devc;
static uart401_devc *detected_devc = NULL;
-static uart401_devc *irq2devc[16] =
-{NULL};
#define DATAPORT (devc->base)
#define COMDPORT (devc->base+1)
#define STATPORT (devc->base+1)
-static int
-uart401_status(uart401_devc * devc)
+static int uart401_status(uart401_devc * devc)
{
return inb(STATPORT);
}
+
#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY))
-static void
-uart401_cmd(uart401_devc * devc, unsigned char cmd)
+
+static void uart401_cmd(uart401_devc * devc, unsigned char cmd)
{
outb((cmd), COMDPORT);
}
-static int
-uart401_read(uart401_devc * devc)
+
+static int uart401_read(uart401_devc * devc)
{
return inb(DATAPORT);
}
-static void
-uart401_write(uart401_devc * devc, unsigned char byte)
+
+static void uart401_write(uart401_devc * devc, unsigned char byte)
{
outb((byte), DATAPORT);
}
@@ -71,30 +77,26 @@ uart401_write(uart401_devc * devc, unsigned char byte)
static int reset_uart401(uart401_devc * devc);
static void enter_uart_mode(uart401_devc * devc);
-static void
-uart401_input_loop(uart401_devc * devc)
+static void uart401_input_loop(uart401_devc * devc)
{
while (input_avail(devc))
- {
- unsigned char c = uart401_read(devc);
-
- if (c == MPU_ACK)
- devc->input_byte = c;
- else if (devc->opened & OPEN_READ && devc->midi_input_intr)
- devc->midi_input_intr(devc->my_dev, c);
- }
+ {
+ unsigned char c = uart401_read(devc);
+
+ if (c == MPU_ACK)
+ devc->input_byte = c;
+ else if (devc->opened & OPEN_READ && devc->midi_input_intr)
+ devc->midi_input_intr(devc->my_dev, c);
+ }
}
-void
-uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
+void uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
{
- uart401_devc *devc;
+ uart401_devc *devc = dev_id;
if (irq < 1 || irq > 15)
return;
- devc = irq2devc[irq];
-
if (devc == NULL)
return;
@@ -108,12 +110,12 @@ uart401_open(int dev, int mode,
void (*output) (int dev)
)
{
- uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+ uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
if (devc->opened)
- {
- return -EBUSY;
- }
+ {
+ return -EBUSY;
+ }
while (input_avail(devc))
uart401_read(devc);
@@ -125,21 +127,19 @@ uart401_open(int dev, int mode,
return 0;
}
-static void
-uart401_close(int dev)
+static void uart401_close(int dev)
{
- uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+ uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
reset_uart401(devc);
devc->opened = 0;
}
-static int
-uart401_out(int dev, unsigned char midi_byte)
+static int uart401_out(int dev, unsigned char midi_byte)
{
- int timeout;
- unsigned long flags;
- uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+ int timeout;
+ unsigned long flags;
+ uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
if (devc->disabled)
return 1;
@@ -163,36 +163,32 @@ uart401_out(int dev, unsigned char midi_byte)
for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
if (!output_ready(devc))
- {
- printk("MPU-401: Timeout - Device not responding\n");
+ {
+ printk(KERN_WARNING "uart401: Timeout - Device not responding\n");
devc->disabled = 1;
reset_uart401(devc);
enter_uart_mode(devc);
return 1;
- }
+ }
uart401_write(devc, midi_byte);
return 1;
}
-static int
-uart401_start_read(int dev)
+static int uart401_start_read(int dev)
{
return 0;
}
-static int
-uart401_end_read(int dev)
+static int uart401_end_read(int dev)
{
return 0;
}
-static void
-uart401_kick(int dev)
+static void uart401_kick(int dev)
{
}
-static int
-uart401_buffer_status(int dev)
+static int uart401_buffer_status(int dev)
{
return 0;
}
@@ -203,7 +199,9 @@ uart401_buffer_status(int dev)
static struct midi_operations uart401_operations =
{
- {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401},
+ {
+ "MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401
+ },
&std_midi_synth,
{0},
uart401_open,
@@ -218,11 +216,10 @@ static struct midi_operations uart401_operations =
NULL
};
-static void
-enter_uart_mode(uart401_devc * devc)
+static void enter_uart_mode(uart401_devc * devc)
{
- int ok, timeout;
- unsigned long flags;
+ int ok, timeout;
+ unsigned long flags;
save_flags(flags);
cli();
@@ -242,11 +239,10 @@ enter_uart_mode(uart401_devc * devc)
restore_flags(flags);
}
-void
-attach_uart401(struct address_info *hw_config)
+void attach_uart401(struct address_info *hw_config)
{
- uart401_devc *devc;
- char *name = "MPU-401 (UART) MIDI";
+ uart401_devc *devc;
+ char *name = "MPU-401 (UART) MIDI";
if (hw_config->name)
name = hw_config->name;
@@ -255,80 +251,75 @@ attach_uart401(struct address_info *hw_config)
return;
- devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(uart401_devc)));
- sound_mem_sizes[sound_nblocks] = sizeof(uart401_devc);
- if (sound_nblocks < 1024)
- sound_nblocks++;;
+ devc = (uart401_devc *) kmalloc(sizeof(uart401_devc), GFP_KERNEL);
if (devc == NULL)
- {
- printk(KERN_WARNING "uart401: Can't allocate memory\n");
- return;
- }
+ {
+ printk(KERN_WARNING "uart401: Can't allocate memory\n");
+ return;
+ }
memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc));
detected_devc = NULL;
devc->irq = hw_config->irq;
if (devc->irq < 0)
- {
- devc->share_irq = 1;
- devc->irq *= -1;
- } else
+ {
+ devc->share_irq = 1;
+ devc->irq *= -1;
+ }
+ else
devc->share_irq = 0;
if (devc->irq < 1 || devc->irq > 15)
+ {
+ kfree(devc);
return;
+ }
if (!devc->share_irq)
- if (snd_set_irq_handler(devc->irq, uart401intr, "MPU-401 UART", devc->osp) < 0)
- {
- printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
- devc->share_irq = 1;
- }
- irq2devc[devc->irq] = devc;
+ {
+ if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0)
+ {
+ printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq);
+ devc->share_irq = 1;
+ }
+ }
devc->my_dev = sound_alloc_mididev();
request_region(hw_config->io_base, 4, "MPU-401 UART");
enter_uart_mode(devc);
if (devc->my_dev == -1)
- {
- printk(KERN_INFO "uart401: Too many midi devices detected\n");
- return;
- }
+ {
+ printk(KERN_INFO "uart401: Too many midi devices detected\n");
+ kfree(devc);
+ return;
+ }
conf_printf(name, hw_config);
std_midi_synth.midi_dev = devc->my_dev;
-
-
- midi_devs[devc->my_dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations)));
- sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations);
-
- if (sound_nblocks < 1024)
- sound_nblocks++;;
+ midi_devs[devc->my_dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
if (midi_devs[devc->my_dev] == NULL)
- {
- printk("uart401: Failed to allocate memory\n");
- sound_unload_mididev(devc->my_dev);
- return;
- }
+ {
+ printk(KERN_ERR "uart401: Failed to allocate memory\n");
+ sound_unload_mididev(devc->my_dev);
+ kfree(devc);
+ devc=NULL;
+ return;
+ }
memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations,
sizeof(struct midi_operations));
midi_devs[devc->my_dev]->devc = devc;
-
-
- midi_devs[devc->my_dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations)));
- sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations);
-
- if (sound_nblocks < 1024)
- sound_nblocks++;
-
+ midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
if (midi_devs[devc->my_dev]->converter == NULL)
- {
- printk(KERN_WARNING "uart401: Failed to allocate memory\n");
- sound_unload_mididev(devc->my_dev);
- return;
- }
+ {
+ printk(KERN_WARNING "uart401: Failed to allocate memory\n");
+ sound_unload_mididev(devc->my_dev);
+ kfree(midi_devs[devc->my_dev]);
+ kfree(devc);
+ devc=NULL;
+ return;
+ }
memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth,
sizeof(struct synth_operations));
@@ -339,10 +330,9 @@ attach_uart401(struct address_info *hw_config)
devc->opened = 0;
}
-static int
-reset_uart401(uart401_devc * devc)
+static int reset_uart401(uart401_devc * devc)
{
- int ok, timeout, n;
+ int ok, timeout, n;
/*
* Send the RESET command. Try again if no success at the first time.
@@ -351,31 +341,33 @@ reset_uart401(uart401_devc * devc)
ok = 0;
for (n = 0; n < 2 && !ok; n++)
- {
- for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
-
- devc->input_byte = 0;
- uart401_cmd(devc, MPU_RESET);
-
- /*
- * Wait at least 25 msec. This method is not accurate so let's make the
- * loop bit longer. Cannot sleep since this is called during boot.
- */
-
- for (timeout = 50000; timeout > 0 && !ok; timeout--)
- if (devc->input_byte == MPU_ACK) /* Interrupt */
- ok = 1;
- else if (input_avail(devc))
- if (uart401_read(devc) == MPU_ACK)
- ok = 1;
-
- }
+ {
+ for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--);
+ devc->input_byte = 0;
+ uart401_cmd(devc, MPU_RESET);
+ /*
+ * Wait at least 25 msec. This method is not accurate so let's make the
+ * loop bit longer. Cannot sleep since this is called during boot.
+ */
+
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ {
+ if (devc->input_byte == MPU_ACK) /* Interrupt */
+ ok = 1;
+ else if (input_avail(devc))
+ {
+ if (uart401_read(devc) == MPU_ACK)
+ ok = 1;
+ }
+ }
+ }
if (ok)
- {
- DEB(printk("Reset UART401 OK\n"));
- } else
+ {
+ DEB(printk("Reset UART401 OK\n"));
+ }
+ else
DDB(printk("Reset UART401 failed - No hardware detected.\n"));
if (ok)
@@ -386,14 +378,12 @@ reset_uart401(uart401_devc * devc)
return ok;
}
-int
-probe_uart401(struct address_info *hw_config)
+int probe_uart401(struct address_info *hw_config)
{
- int ok = 0;
- unsigned long flags;
-
+ int ok = 0;
+ unsigned long flags;
static uart401_devc hw_info;
- uart401_devc *devc = &hw_info;
+ uart401_devc *devc = &hw_info;
DDB(printk("Entered probe_uart401()\n"));
@@ -422,21 +412,10 @@ probe_uart401(struct address_info *hw_config)
return ok;
}
-void
-unload_uart401(struct address_info *hw_config)
+void unload_uart401(struct address_info *hw_config)
{
- uart401_devc *devc;
-
- int irq = hw_config->irq;
-
- if (irq < 0)
- {
- irq *= -1;
- }
- if (irq < 1 || irq > 15)
- return;
-
- devc = irq2devc[irq];
+ uart401_devc *devc;
+ devc = midi_devs[hw_config->slots[4]]->devc;
if (devc == NULL)
return;
@@ -444,47 +423,47 @@ unload_uart401(struct address_info *hw_config)
release_region(hw_config->io_base, 4);
if (!devc->share_irq)
- snd_release_irq(devc->irq);
-
+ free_irq(devc->irq, devc);
+ sound_unload_mididev(hw_config->slots[4]);
if (devc)
+ {
+ kfree(midi_devs[devc->my_dev]->converter);
+ kfree(midi_devs[devc->my_dev]);
+ kfree(devc);
devc = NULL;
- sound_unload_mididev(hw_config->slots[4]);
+ }
}
#ifdef MODULE
-int io = -1;
-int irq = -1;
+int io = -1;
+int irq = -1;
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
struct address_info hw;
-int
-init_module(void)
+int init_module(void)
{
/* Can be loaded either for module use or to provide functions
to others */
if (io != -1 && irq != -1)
- {
- printk("MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
- hw.irq = irq;
- hw.io_base = io;
- if (probe_uart401(&hw) == 0)
- return -ENODEV;
- attach_uart401(&hw);
- }
+ {
+ printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997");
+ hw.irq = irq;
+ hw.io_base = io;
+ if (probe_uart401(&hw) == 0)
+ return -ENODEV;
+ attach_uart401(&hw);
+ }
SOUND_LOCK;
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
if (io != -1 && irq != -1)
- {
- unload_uart401(&hw);
- }
+ unload_uart401(&hw);
/* FREE SYMTAB */
SOUND_LOCK_END;
}
diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c
index 932be1846..b26e75a89 100644
--- a/drivers/sound/uart6850.c
+++ b/drivers/sound/uart6850.c
@@ -10,6 +10,11 @@
* Extended by Alan Cox for Red Hat Software. Now a loadable MIDI driver.
* 28/4/97 - (C) Copyright Alan Cox. Released under the GPL version 2.
*
+ * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now
+ * uses native linux resources
+ *
+ * Status: Testing required
+ *
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -297,7 +302,7 @@ int probe_uart6850(struct address_info *hw_config)
uart6850_base = hw_config->io_base;
uart6850_irq = hw_config->irq;
- if (snd_set_irq_handler(uart6850_irq, m6850intr, "MIDI6850", uart6850_osp) < 0)
+ if (request_irq(uart6850_irq, m6850intr, 0, "MIDI6850", NULL) < 0)
return 0;
ok = reset_uart6850();
@@ -307,7 +312,7 @@ int probe_uart6850(struct address_info *hw_config)
void unload_uart6850(struct address_info *hw_config)
{
- snd_release_irq(hw_config->irq);
+ free_irq(hw_config->irq, NULL);
sound_unload_mididev(hw_config->slots[4]);
}
diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c
index 12c221a68..4820d5f36 100644
--- a/drivers/sound/v_midi.c
+++ b/drivers/sound/v_midi.c
@@ -2,15 +2,22 @@
* sound/v_midi.c
*
* The low level driver for the Sound Blaster DS chips.
- */
-/*
+ *
+ *
* Copyright (C) by Hannu Savolainen 1993-1996
*
* USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
* ??
+ *
+ * Changes
+ * Alan Cox Modularisation, changed memory allocations
+ *
+ * Status
+ * Untested
*/
+
#include <linux/config.h>
#include <linux/module.h>
diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c
index 1341d3196..872d77928 100644
--- a/drivers/video/fbcon.c
+++ b/drivers/video/fbcon.c
@@ -74,8 +74,8 @@
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/init.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <asm/irq.h>
@@ -196,7 +196,7 @@ static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
static struct display_switch *probe_list(struct display_switch *dispsw,
struct display *disp);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
static void request_driver(struct display *disp, int is_accel);
#endif
static struct display_switch *fbcon_get_driver(struct display *disp);
@@ -1368,7 +1368,7 @@ static struct display_switch *probe_list(struct display_switch *dispsw,
}
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
static void request_driver(struct display *disp, int is_accel)
{
char modname[30];
@@ -1400,7 +1400,7 @@ static void request_driver(struct display *disp, int is_accel)
len += sprintf(modname+len, "-%d", disp->var.accel);
request_module(modname);
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
static struct display_switch *fbcon_get_driver(struct display *disp)
@@ -1410,7 +1410,7 @@ static struct display_switch *fbcon_get_driver(struct display *disp)
if (disp->var.accel != FB_ACCEL_NONE) {
/* First try an accelerated driver */
dispsw = probe_list(accel_drivers, disp);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!dispsw) {
request_driver(disp, 1);
dispsw = probe_list(accel_drivers, disp);
@@ -1422,7 +1422,7 @@ static struct display_switch *fbcon_get_driver(struct display *disp)
/* Then try an unaccelerated driver */
dispsw = probe_list(drivers, disp);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!dispsw) {
request_driver(disp, 0);
dispsw = probe_list(drivers, disp);
diff --git a/fs/buffer.c b/fs/buffer.c
index 7e45b223e..ec844de9f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -731,7 +731,8 @@ static void refill_freelist(int size)
/* We are going to try to locate this much memory. */
needed = bdf_prm.b_un.nrefill * size;
- while ((nr_free_pages > min_free_pages*2) &&
+ while ((nr_free_pages > freepages.min*2) &&
+ BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
grow_buffers(GFP_BUFFER, size)) {
obtained += PAGE_SIZE;
if (obtained >= needed)
@@ -815,7 +816,8 @@ repeat:
* are _any_ free buffers.
*/
while (obtained < (needed >> 1) &&
- nr_free_pages > min_free_pages + 5 &&
+ nr_free_pages > freepages.min + 5 &&
+ BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
grow_buffers(GFP_BUFFER, size))
obtained += PAGE_SIZE;
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
index 0a4140745..1f2d0a94c 100644
--- a/fs/coda/Makefile
+++ b/fs/coda/Makefile
@@ -3,7 +3,7 @@
#
O_TARGET := coda.o
-O_OBJS := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\
+O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\
symlink.o pioctl.o sysctl.o
M_OBJS := $(O_TARGET)
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 7673bfbdd..cdf586507 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -24,16 +24,22 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
-/* Keep various stats */
-struct cfsnc_statistics cfsnc_stat;
+static void coda_ccinsert(struct coda_cache *el, struct super_block *sb);
+static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii);
+static void coda_ccremove(struct coda_cache *el);
+static void coda_cnremove(struct coda_cache *el);
+static void coda_cache_create(struct inode *inode, int mask);
+static struct coda_cache * coda_cache_find(struct inode *inode);
-/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */
+/* Keep various stats */
+struct cfsnc_statistics cfsnc_stat;
-void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
+/* insert a acl-cache entry in sb list */
+static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
{
struct coda_sb_info *sbi = coda_sbp(sb);
-ENTRY;
+ ENTRY;
if ( !sbi || !el) {
printk("coda_ccinsert: NULL sbi or el!\n");
return ;
@@ -42,17 +48,19 @@ ENTRY;
list_add(&el->cc_cclist, &sbi->sbi_cchead);
}
-void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp)
+/* insert a acl-cache entry in the inode list */
+static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
{
-ENTRY;
- if ( !cnp || !el) {
- printk("coda_cninsert: NULL cnp or el!\n");
+ ENTRY;
+ if ( !cii || !el) {
+ printk("coda_cninsert: NULL cii or el!\n");
return ;
}
- list_add(&el->cc_cnlist, &cnp->c_cnhead);
+ list_add(&el->cc_cnlist, &cii->c_cnhead);
}
-void coda_ccremove(struct coda_cache *el)
+/* remove a cache entry from the superblock list */
+static void coda_ccremove(struct coda_cache *el)
{
ENTRY;
if (el->cc_cclist.next && el->cc_cclist.prev)
@@ -61,7 +69,8 @@ void coda_ccremove(struct coda_cache *el)
printk("coda_cnremove: trying to remove 0 entry!");
}
-void coda_cnremove(struct coda_cache *el)
+/* remove a cache entry from the inode's list */
+static void coda_cnremove(struct coda_cache *el)
{
ENTRY;
if (el->cc_cnlist.next && el->cc_cnlist.prev)
@@ -70,10 +79,10 @@ void coda_cnremove(struct coda_cache *el)
printk("coda_cnremove: trying to remove 0 entry!");
}
-
-void coda_cache_create(struct inode *inode, int mask)
+/* create a new cache entry and enlist it */
+static void coda_cache_create(struct inode *inode, int mask)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct super_block *sb = inode->i_sb;
struct coda_cache *cc = NULL;
ENTRY;
@@ -85,17 +94,19 @@ void coda_cache_create(struct inode *inode, int mask)
}
coda_load_creds(&cc->cc_cred);
cc->cc_mask = mask;
- coda_cninsert(cc, cnp);
+ coda_cninsert(cc, cii);
coda_ccinsert(cc, sb);
}
-struct coda_cache * coda_cache_find(struct inode *inode)
+/* see if there is a match for the current
+ credentials already */
+static struct coda_cache * coda_cache_find(struct inode *inode)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct list_head *lh, *le;
struct coda_cache *cc = NULL;
- le = lh = &cnp->c_cnhead;
+ le = lh = &cii->c_cnhead;
while( (le = le->next ) != lh ) {
/* compare name and creds */
cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -107,6 +118,7 @@ struct coda_cache * coda_cache_find(struct inode *inode)
return NULL;
}
+/* create or extend an acl cache hit */
void coda_cache_enter(struct inode *inode, int mask)
{
struct coda_cache *cc;
@@ -120,17 +132,21 @@ void coda_cache_enter(struct inode *inode, int mask)
}
}
-void coda_cache_clear_cnp(struct coda_inode_info *cnp)
+/* remove all cached acl matches from an inode */
+void coda_cache_clear_inode(struct inode *inode)
{
struct list_head *lh, *le;
+ struct coda_inode_info *cii;
struct coda_cache *cc;
+ ENTRY;
- if ( !cnp ) {
- printk("coda_cache_cnp_clear: NULL cnode\n");
+ if ( !inode ) {
+ CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n");
return;
}
+ cii = ITOC(inode);
- lh = le = &cnp->c_cnhead;
+ lh = le = &cii->c_cnhead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cnlist);
coda_cnremove(cc);
@@ -139,6 +155,7 @@ void coda_cache_clear_cnp(struct coda_inode_info *cnp)
}
}
+/* remove all acl caches */
void coda_cache_clear_all(struct super_block *sb)
{
struct list_head *lh, *le;
@@ -150,6 +167,9 @@ void coda_cache_clear_all(struct super_block *sb)
return;
}
+ if ( list_empty(&sbi->sbi_cchead) )
+ return;
+
lh = le = &sbi->sbi_cchead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -159,6 +179,7 @@ void coda_cache_clear_all(struct super_block *sb)
}
}
+/* remove all acl caches for a principal */
void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
{
struct list_head *lh, *le;
@@ -170,6 +191,9 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
return;
}
+ if (list_empty(&sbi->sbi_cchead))
+ return;
+
lh = le = &sbi->sbi_cchead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -180,15 +204,17 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
}
}
}
-
+
+/* check if the mask has been matched against the acl
+ already */
int coda_cache_check(struct inode *inode, int mask)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct list_head *lh, *le;
struct coda_cache *cc = NULL;
- le = lh = &cnp->c_cnhead;
+ le = lh = &cii->c_cnhead;
while( (le = le->next ) != lh ) {
/* compare name and creds */
cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -204,110 +230,70 @@ int coda_cache_check(struct inode *inode, int mask)
}
-/* DENTRY related stuff */
+/* DCACHE & ZAPPING related stuff */
-/* when the dentry count falls to 0 this is called. If Venus has
- asked for it to be flushed, we take it out of the dentry hash
- table with d_drop */
-
-static void coda_flag_children(struct dentry *parent)
+/* the following routines set flags in the inodes. They are
+ detected by:
+ - a dentry method: coda_dentry_revalidate (for lookups)
+ if the flag is C_PURGE
+ - an inode method coda_revalidate (for attributes) if the
+ flag is C_ATTR
+*/
+static void coda_flag_children(struct dentry *parent, int flag)
{
struct list_head *child;
- struct coda_inode_info *cnp;
struct dentry *de;
child = parent->d_subdirs.next;
while ( child != &parent->d_subdirs ) {
de = list_entry(child, struct dentry, d_child);
- cnp = ITOC(de->d_inode);
- if (cnp)
- cnp->c_flags |= C_ZAPFID;
- CDEBUG(D_CACHE, "ZAPFID for %s\n", coda_f2s(&cnp->c_fid));
-
+ coda_flag_inode(de->d_inode, flag);
+ CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag,
+ de->d_name.len, de->d_name.name,
+ de->d_parent->d_name.len, de->d_parent->d_name.name);
child = child->next;
+ if ( !de->d_inode )
+ d_drop(de);
}
return;
}
-/* flag dentry and possibly children of a dentry with C_ZAPFID */
-void coda_dentry_delete(struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
- struct coda_inode_info *cnp = NULL;
- ENTRY;
- if (inode) {
- cnp = ITOC(inode);
- if ( cnp )
- CHECK_CNODE(cnp);
- } else {
- CDEBUG(D_CACHE, "No inode for dentry_delete!\n");
- return;
- }
-
-
- if ( !cnp ) {
- printk("No cnode for dentry_delete!\n");
- return;
- }
-
- if ( cnp->c_flags & (C_ZAPFID | C_ZAPDIR) )
- d_drop(dentry);
- if ( (cnp->c_flags & C_ZAPDIR) && S_ISDIR(inode->i_mode) ) {
- coda_flag_children(dentry);
- }
- return;
-}
-
-static void coda_zap_cnode(struct coda_inode_info *cnp, int flags)
+void coda_flag_alias_children(struct inode *inode, int flag)
{
- cnp->c_flags |= flags;
- coda_cache_clear_cnp(cnp);
+ struct list_head *alias;
+ struct dentry *alias_de;
+
+ if ( !inode )
+ return;
+ alias = inode->i_dentry.next;
+ while ( alias != &inode->i_dentry ) {
+ alias_de = list_entry(alias, struct dentry, d_alias);
+ if ( !alias_de ) {
+ printk("Corrupt alias list for %*s\n",
+ alias_de->d_name.len, alias_de->d_name.name);
+ return;
+ }
+ coda_flag_children(alias_de, flag);
+ alias= alias->next;
+ }
}
-
-
-/* the dache will notice the flags and drop entries (possibly with
- children) the moment they are no longer in use */
-void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag)
+void coda_flag_inode(struct inode *inode, int flag)
{
- struct inode *inode = NULL;
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
- ENTRY;
-
- if ( !sb ) {
- printk("coda_zapfid: no sb!\n");
+ if ( !inode ) {
+ CDEBUG(D_CACHE, " no inode!\n");
return;
}
+ cii = ITOC(inode);
+ cii->c_flags |= flag;
+}
- if ( !fid ) {
- printk("coda_zapfid: no fid!\n");
- return;
- }
- if ( coda_fid_is_volroot(fid) ) {
- struct list_head *lh, *le;
- struct coda_sb_info *sbi = coda_sbp(sb);
- le = lh = &sbi->sbi_volroothead;
- while ( (le = le->next) != lh ) {
- cnp = list_entry(le, struct coda_inode_info, c_volrootlist);
- if ( cnp->c_fid.Volume == fid->Volume)
- coda_zap_cnode(cnp, flag);
- }
- return;
- }
- inode = coda_fid_to_inode(fid, sb);
- if ( !inode ) {
- CDEBUG(D_CACHE, "coda_zapfid: no inode!\n");
- return;
- }
- cnp = ITOC(inode);
- coda_zap_cnode(cnp, flag);
-}
-
int
cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 67133f275..aa67a22e4 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -15,8 +15,6 @@ extern int coda_print_entry;
/* cnode.c */
-
-
static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
{
CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
@@ -56,8 +54,8 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
ENTRY;
/*
- * We get inode numbers from Venus -- see venus source
- */
+ * We get inode numbers from Venus -- see venus source
+ */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
@@ -79,7 +77,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
memset(cnp, 0, (int) sizeof(struct coda_inode_info));
cnp->c_fid = *fid;
cnp->c_magic = CODA_CNODE_MAGIC;
- cnp->c_flags = C_VATTR;
+ cnp->c_flags = 0;
cnp->c_vnode = *inode;
INIT_LIST_HEAD(&(cnp->c_cnhead));
INIT_LIST_HEAD(&(cnp->c_volrootlist));
@@ -111,20 +109,51 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
-/* convert a fid to an inode. Avoids having a hash table
- such as present in the Mach minicache */
+/* convert a fid to an inode. Mostly we can compute
+ the inode number from the FID, but not for volume
+ mount points: those are in a list */
struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
{
ino_t nr;
struct inode *inode;
struct coda_inode_info *cnp;
-ENTRY;
+ ENTRY;
CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
+ if ( !sb ) {
+ printk("coda_fid_to_inode: no sb!\n");
+ return NULL;
+ }
+
+ if ( !fid ) {
+ printk("coda_fid_to_inode: no fid!\n");
+ return NULL;
+ }
+
+
+ if ( coda_fid_is_volroot(fid) ) {
+ struct coda_inode_info *cii;
+ struct list_head *lh, *le;
+ struct coda_sb_info *sbi = coda_sbp(sb);
+ le = lh = &sbi->sbi_volroothead;
+
+ while ( (le = le->next) != lh ) {
+ cii = list_entry(le, struct coda_inode_info,
+ c_volrootlist);
+ if ( cii->c_fid.Volume == fid->Volume) {
+ inode = cii->c_vnode;
+ CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
+ return cii->c_vnode;
+ }
+
+ }
+ return NULL;
+ }
+
+ /* fid is not volume root, hence ino is computable */
nr = coda_f2i(fid);
inode = iget(sb, nr);
-
if ( !inode ) {
printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
sb, nr);
@@ -133,19 +162,25 @@ ENTRY;
/* check if this inode is linked to a cnode */
cnp = ITOC(inode);
-
if ( cnp->c_magic != CODA_CNODE_MAGIC ) {
+ CDEBUG(D_INODE, "uninitialized inode. Return.\n");
iput(inode);
return NULL;
}
- /* make sure fid is the one we want */
- if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+ /* make sure fid is the one we want;
+ unfortunately Venus will shamelessly send us mount-symlinks.
+ These have the same inode as the root of the volume they
+ mount, but the fid will be wrong.
+ */
+ if ( !coda_fideq(fid, &(cnp->c_fid)) &&
+ !coda_fid_is_volroot(&(cnp->c_fid))) {
printk("coda_fid2inode: bad cnode! Tell Peter.\n");
iput(inode);
return NULL;
}
+ CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
iput(inode);
return inode;
}
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index e968f3add..4fe096df9 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -32,14 +32,15 @@ int coda_access_cache = 1;
/* caller must allocate 36 byte string ! */
char * coda_f2s(ViceFid *f)
{
- static char s[50];
+ static char s[60];
if ( f ) {
- sprintf(s, "(%10lx,%10lx,%10lx)",
+ sprintf(s, "(%-#lx,%-#lx,%-#lx)",
f->Volume, f->Vnode, f->Unique);
}
return s;
}
+/* recognize special .CONTROL name */
int coda_iscontrol(const char *name, size_t length)
{
if ((CFS_CONTROLLEN == length) &&
@@ -48,16 +49,23 @@ int coda_iscontrol(const char *name, size_t length)
return 0;
}
+/* recognize /coda inode */
int coda_isroot(struct inode *i)
{
if ( i->i_sb->s_root->d_inode == i ) {
- return 1;
+ return 1;
} else {
- return 0;
+ return 0;
}
}
-
+/* is this a volume root FID */
+int coda_fid_is_volroot(struct ViceFid *fid)
+{
+ return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
+}
+
+/* put the current process credentials in the cred */
void coda_load_creds(struct coda_cred *cred)
{
cred->cr_uid = (vuid_t) current->uid;
@@ -98,11 +106,6 @@ unsigned short coda_flags_to_cflags(unsigned short flags)
}
-int coda_fid_is_volroot(struct ViceFid *fid)
-{
- return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
-}
-
/* utility functions below */
void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
{
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index dd20499dc..8fed69242 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -40,17 +40,21 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
/* dir file-ops */
static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
+/* dentry ops */
+int coda_dentry_revalidate(struct dentry *de);
+
/* support routines */
static int coda_venus_readdir(struct file *filp, void *dirent,
filldir_t filldir);
int coda_fsync(struct file *, struct dentry *dentry);
+static int coda_refresh_inode(struct dentry *dentry);
struct dentry_operations coda_dentry_operations =
{
- NULL, /* revalidate */
+ coda_dentry_revalidate, /* revalidate */
NULL, /* hash */
NULL,
- coda_dentry_delete
+ NULL,
};
struct inode_operations coda_dir_inode_operations =
@@ -74,7 +78,7 @@ struct inode_operations coda_dir_inode_operations =
coda_permission, /* permission */
NULL, /* smap */
NULL, /* update page */
- NULL /* revalidate */
+ coda_revalidate_inode /* revalidate */
};
struct file_operations coda_dir_operations = {
@@ -117,7 +121,6 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
}
dircnp = ITOC(dir);
- CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
printk("name too long: lookup, %s (%*s)\n",
@@ -141,9 +144,13 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
(const char *)name, length, &type, &resfid);
res_inode = NULL;
- if (!error || (error == -CFS_NOCACHE) ) {
- if (error == -CFS_NOCACHE)
+ if (!error) {
+ if (type & CFS_NOCACHE) {
+ type &= (~CFS_NOCACHE);
+ CDEBUG(D_INODE, "dropme set for %s\n",
+ coda_f2s(&resfid));
dropme = 1;
+ }
error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
if (error)
return -error;
@@ -152,7 +159,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
coda_f2s(&dircnp->c_fid), length, name, error);
return error;
}
- CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+ CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
name, coda_f2s(&resfid), type, error, dropme);
exit:
@@ -228,7 +235,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
- char str[50];
printk("name too long: create, %s(%s)\n",
coda_f2s(&dircnp->c_fid), name);
return -ENAMETOOLONG;
@@ -238,7 +244,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
0, mode, &newfid, &attrs);
if ( error ) {
- char str[50];
CDEBUG(D_INODE, "create: %s, result %d\n",
coda_f2s(&newfid), error);
d_drop(de);
@@ -321,7 +326,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
const char * name = de->d_name.name;
int len = de->d_name.len;
struct coda_inode_info *dir_cnp, *cnp;
- char str[50];
int error;
ENTRY;
@@ -408,7 +412,6 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int error;
const char *name = de->d_name.name;
int len = de->d_name.len;
- char fidstr[50];
ENTRY;
@@ -781,3 +784,82 @@ exit:
CODA_FREE(buff, size);
return error;
}
+
+int coda_dentry_revalidate(struct dentry *de)
+{
+ int valid = 1;
+ struct inode *inode = de->d_inode;
+ struct coda_inode_info *cii;
+ ENTRY;
+
+ if (inode) {
+ if (is_bad_inode(inode))
+ return 0;
+ cii = ITOC(de->d_inode);
+ if (cii->c_flags & C_PURGE)
+ valid = 0;
+ }
+ return valid || coda_isroot(de->d_inode);
+}
+
+
+static int coda_refresh_inode(struct dentry *dentry)
+{
+ struct coda_vattr attr;
+ int error;
+ int old_mode;
+ ino_t old_ino;
+ struct inode *inode = dentry->d_inode;
+ struct coda_inode_info *cii = ITOC(inode);
+
+ ENTRY;
+ error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
+ if ( error ) {
+ make_bad_inode(inode);
+ return -EIO;
+ }
+
+ /* this baby may be lost if:
+ - it's type changed
+ - it's ino changed
+ */
+ old_mode = inode->i_mode;
+ old_ino = inode->i_ino;
+ coda_vattr_to_iattr(inode, &attr);
+
+ if ((inode->i_ino != old_ino) ||
+ ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) {
+ make_bad_inode(inode);
+ inode->i_mode = old_mode;
+ return -EIO;
+ }
+
+ cii->c_flags &= ~C_VATTR;
+ return 0;
+}
+
+
+/*
+ * This is called when we want to check if the inode has
+ * changed on the server. Coda makes this easy since the
+ * cache manager Venus issues a downcall to the kernel when this
+ * happens
+ */
+
+int coda_revalidate_inode(struct dentry *dentry)
+{
+ int error = 0;
+ struct coda_inode_info *cii = ITOC(dentry->d_inode);
+
+ ENTRY;
+ CDEBUG(D_INODE, "revalidating: %*s/%*s\n",
+ dentry->d_name.len, dentry->d_name.name,
+ dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
+
+ if ( cii->c_flags & (C_VATTR | C_PURGE )) {
+ error = coda_refresh_inode(dentry);
+ }
+
+ return error;
+}
+
diff --git a/fs/coda/file.c b/fs/coda/file.c
index b33680cc3..ae1dd9776 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -30,7 +30,7 @@ static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *o
static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off);
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
-/* exported from this file */
+/* also exported from this file (used for dirs) */
int coda_fsync(struct file *, struct dentry *dentry);
struct inode_operations coda_file_inode_operations = {
@@ -43,7 +43,7 @@ struct inode_operations coda_file_inode_operations = {
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
- NULL, /* rename */
+ NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
coda_readpage, /* readpage */
@@ -53,7 +53,7 @@ struct inode_operations coda_file_inode_operations = {
coda_permission, /* permission */
NULL, /* smap */
NULL, /* update page */
- NULL /* revalidate */
+ coda_revalidate_inode /* revalidate */
};
struct file_operations coda_file_operations = {
@@ -74,41 +74,47 @@ struct file_operations coda_file_operations = {
};
/* File file operations */
-static int coda_readpage(struct file * file, struct page * page)
+static int coda_readpage(struct file * coda_file, struct page * page)
{
- struct dentry *de = file->f_dentry;
- struct inode *inode = de->d_inode;
+ struct dentry *de = coda_file->f_dentry;
+ struct inode *coda_inode = de->d_inode;
struct dentry cont_dentry;
- struct inode *cont_inode;
- struct coda_inode_info *cnp;
+ struct file cont_file;
+ struct coda_inode_info *cii;
ENTRY;
- cnp = ITOC(inode);
- CHECK_CNODE(cnp);
+ cii = ITOC(coda_inode);
- if ( ! cnp->c_ovp ) {
- printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino);
+ if ( ! cii->c_ovp ) {
+ printk("coda_readpage: no open inode for ino %ld, %s\n",
+ coda_inode->i_ino, de->d_name.name);
return -ENXIO;
}
+
+ coda_prepare_openfile(coda_inode, coda_file, cii->c_ovp,
+ &cont_file, &cont_dentry);
- cont_inode = cnp->c_ovp;
- cont_dentry.d_inode = cont_inode;
-
- CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset);
+ CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n",
+ coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
- generic_readpage(&cont_dentry, page);
+ generic_readpage(&cont_file, page);
EXIT;
return 0;
}
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct coda_inode_info *cnp;
- cnp = ITOC(file->f_dentry->d_inode);
- cnp->c_mmcount++;
+ struct coda_inode_info *cii;
+ int res;
+
+ ENTRY;
+ cii = ITOC(file->f_dentry->d_inode);
+ cii->c_mmcount++;
- return generic_file_mmap(file, vma);
+ res =generic_file_mmap(file, vma);
+ EXIT;
+ return res;
}
static ssize_t coda_file_read(struct file *coda_file, char *buff,
@@ -120,7 +126,6 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
struct file cont_file;
struct dentry cont_dentry;
int result = 0;
-
ENTRY;
cnp = ITOC(coda_inode);
diff --git a/fs/coda/super.c b/fs/coda/inode.c
index 5410fb50d..96d07e265 100644
--- a/fs/coda/super.c
+++ b/fs/coda/inode.c
@@ -4,7 +4,7 @@
* Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
* Michael Callahan <callahan@maths.ox.ac.uk>
*
- * Rewritten for Linux 2.1.?? Peter Braam <braam@cs.cmu.edu>
+ * Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu>
* Copyright (C) Carnegie Mellon University
*/
@@ -81,7 +81,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
ViceFid fid;
kdev_t dev = sb->s_dev;
int error;
- char str[50];
ENTRY;
MOD_INC_USE_COUNT;
@@ -180,10 +179,10 @@ static void coda_put_super(struct super_block *sb)
/* all filling in of inodes postponed until lookup */
static void coda_read_inode(struct inode *inode)
{
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
ENTRY;
- cnp = ITOC(inode);
- cnp->c_magic = 0;
+ cii = ITOC(inode);
+ cii->c_magic = 0;
return;
}
@@ -200,32 +199,32 @@ static void coda_put_inode(struct inode *in)
static void coda_delete_inode(struct inode *inode)
{
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
struct inode *open_inode;
ENTRY;
CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n",
inode->i_ino, inode->i_count);
- cnp = ITOC(inode);
- if ( inode->i_ino == CTL_INO || cnp->c_magic != CODA_CNODE_MAGIC ) {
+ cii = ITOC(inode);
+ if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) {
clear_inode(inode);
return;
}
- if ( coda_fid_is_volroot(&cnp->c_fid) )
- list_del(&cnp->c_volrootlist);
+ if ( coda_fid_is_volroot(&cii->c_fid) )
+ list_del(&cii->c_volrootlist);
- open_inode = cnp->c_ovp;
+ open_inode = cii->c_ovp;
if ( open_inode ) {
CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",
open_inode->i_ino, open_inode->i_count);
- cnp->c_ovp = NULL;
+ cii->c_ovp = NULL;
iput(open_inode);
}
- coda_cache_clear_cnp(cnp);
+ coda_cache_clear_inode(inode);
inode->u.generic_ip = NULL;
clear_inode(inode);
@@ -235,24 +234,24 @@ static void coda_delete_inode(struct inode *inode)
static int coda_notify_change(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
struct coda_vattr vattr;
int error;
ENTRY;
memset(&vattr, 0, sizeof(vattr));
- cnp = ITOC(inode);
- CHECK_CNODE(cnp);
+ cii = ITOC(inode);
+ CHECK_CNODE(cii);
coda_iattr_to_vattr(iattr, &vattr);
vattr.va_type = C_VNON; /* cannot set type */
CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
- error = venus_setattr(inode->i_sb, &cnp->c_fid, &vattr);
+ error = venus_setattr(inode->i_sb, &cii->c_fid, &vattr);
if ( !error ) {
coda_vattr_to_iattr(inode, &vattr);
- coda_cache_clear_cnp(cnp);
+ coda_cache_clear_inode(inode);
}
CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n",
inode->i_mode, error);
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 04333e046..119d14f51 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -65,7 +65,7 @@ extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, i
/* statistics */
struct coda_upcallstats coda_callstats;
int coda_hard = 0; /* introduces a timeout on upcalls */
-unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */
+unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
struct vcomm psdev_vcomm[MAX_CODADEVS];
@@ -447,7 +447,7 @@ MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
int init_module(void)
{
int status;
- printk(KERN_INFO "Coda Kernel/User communications module 1.0\n");
+ printk(KERN_INFO "Coda Kernel/User communications module 2.0\n");
status = init_coda_psdev();
if ( status ) {
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index ac625ad17..13d3127c6 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -500,7 +500,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
union outputArgs *outp;
int insize, outsize, error;
int iocsize;
- char str[50];
insize = VC_MAXMSGSIZE;
UPARG(CFS_IOCTL);
@@ -587,7 +586,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
static inline void coda_waitfor_upcall(struct vmsg *vmp)
{
struct wait_queue wait = { current, NULL };
- old_sigset_t pending;
vmp->vm_posttime = jiffies;
@@ -608,13 +606,9 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp)
if ( jiffies > vmp->vm_posttime + coda_timeout * HZ )
break;
- spin_lock_irq(&current->sigmask_lock);
- pending = current->blocked.sig[0] & current->signal.sig[0];
- spin_unlock_irq(&current->sigmask_lock);
-
/* if this process really wants to die, let it go */
- if ( sigismember(&pending, SIGKILL) ||
- sigismember(&pending, SIGINT) )
+ if ( sigismember(&current->signal, SIGKILL) ||
+ sigismember(&current->signal, SIGINT) )
break;
else
schedule();
@@ -765,10 +759,14 @@ ENTRY;
* This call is a result of token expiration.
*
* The next arise as the result of callbacks on a file or directory.
- * CFS_ZAPDIR -- flush the attributes for the dir from its cnode.
- * Zap all children of this directory from the namecache.
* CFS_ZAPFILE -- flush the cached attributes for a file.
- * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. Not used?
+
+ * CFS_ZAPDIR -- flush the attributes for the dir and
+ * force a new lookup for all the children
+ of this dir.
+
+ * CFS_ZAPVNODE -- intended to be a zapfile for just one cred.
+ Not used?
*
* The next is a result of Venus detecting an inconsistent file.
* CFS_PURGEFID -- flush the attribute for the file
@@ -803,53 +801,48 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
return(0);
}
case CFS_ZAPDIR : {
+ struct inode *inode;
ViceFid *fid = &out->cfs_zapdir.CodaFid;
- char str[50];
if ( !fid ) {
printk("ZAPDIR: Null fid\n");
return 0;
}
CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
clstats(CFS_ZAPDIR);
- coda_zapfid(fid, sb, C_ZAPDIR);
- return(0);
- }
- case CFS_ZAPVNODE : {
- ViceFid *fid = &out->cfs_zapvnode.VFid;
- char str[50];
- struct coda_cred *cred = &out->cfs_zapvnode.cred;
- if ( !fid || !cred ) {
- printk("ZAPVNODE: Null fid or cred\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid));
- coda_zapfid(fid, sb, C_ZAPFID);
- coda_cache_clear_cred(sb, cred);
- clstats(CFS_ZAPVNODE);
+ inode = coda_fid_to_inode(fid, sb);
+ coda_flag_inode(inode, C_VATTR);
+ coda_cache_clear_inode(inode);
+ coda_flag_alias_children(inode, C_PURGE);
return(0);
}
+
+ case CFS_ZAPVNODE :
case CFS_ZAPFILE : {
+ struct inode *inode;
struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
- char str[50];
clstats(CFS_ZAPFILE);
if ( !fid ) {
printk("ZAPFILE: Null fid\n");
return 0;
}
CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
- coda_zapfid(fid, sb, C_ZAPFID);
+ inode = coda_fid_to_inode(fid, sb);
+ coda_flag_inode(inode, C_VATTR);
+ coda_cache_clear_inode(inode);
return 0;
}
case CFS_PURGEFID : {
+ struct inode *inode;
ViceFid *fid = &out->cfs_purgefid.CodaFid;
- char str[50];
if ( !fid ) {
printk("PURGEFID: Null fid\n");
return 0;
}
CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
clstats(CFS_PURGEFID);
- coda_zapfid(fid, sb, C_ZAPDIR);
+ inode = coda_fid_to_inode(fid, sb);
+ coda_flag_inode(inode, C_PURGE);
+ coda_cache_clear_inode(inode);
return 0;
}
case CFS_REPLACE : {
diff --git a/fs/devices.c b/fs/devices.c
index 9cae0441e..6a8a60627 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -6,6 +6,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Added kerneld support: Jacques Gelinas and Bjorn Ekwall
+ * (changed to kmod)
*/
#include <linux/config.h>
@@ -16,12 +17,12 @@
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#include <linux/tty.h>
-/* serial module kerneld load support */
+/* serial module kmod load support */
struct tty_driver *get_tty_driver(kdev_t device);
#define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
@@ -74,12 +75,12 @@ static struct file_operations * get_fops(
struct file_operations *ret = NULL;
if (major < maxdev){
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
/*
* I do get request for device 0. I have no idea why. It happen
* at shutdown time for one. Without the following test, the
* kernel will happily trigger a request_module() which will
- * trigger kerneld and modprobe for nothing (since there
+ * trigger kmod and modprobe for nothing (since there
* is no device with major number == 0. And furthermore
* it locks the reboot process :-(
*
@@ -87,7 +88,7 @@ static struct file_operations * get_fops(
*
* A. Haritsis <ah@doc.ic.ac.uk>: fix for serial module
* though we need the minor here to check if serial dev,
- * we pass only the normal major char dev to kerneld
+ * we pass only the normal major char dev to kmod
* as there is no other loadable dev on these majors
*/
if ((isa_tty_dev(major) && need_serial(major,minor)) ||
diff --git a/fs/exec.c b/fs/exec.c
index f023054c6..c3d420973 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -49,8 +49,9 @@
#include <asm/mmu_context.h>
#include <linux/config.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
asmlinkage int sys_exit(int exit_code);
@@ -421,6 +422,7 @@ static int exec_mmap(void)
retval = new_page_tables(current);
if (retval)
goto fail_restore;
+ up(&mm->mmap_sem);
mmput(old_mm);
return 0;
@@ -697,7 +699,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
}
if (retval != -ENOEXEC) {
break;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
}else{
#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
char modname[20];
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 8743916ee..5cfeb3658 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -9,6 +9,7 @@
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
+#include <linux/file.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
@@ -22,18 +23,32 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
static inline int dupfd(unsigned int fd, unsigned int arg)
{
struct files_struct * files = current->files;
+ struct file * file;
+ int error;
- if (fd >= NR_OPEN || !files->fd[fd])
- return -EBADF;
+ error = -EINVAL;
if (arg >= NR_OPEN)
- return -EINVAL;
+ goto out;
+
+ error = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ error = -EMFILE;
arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
- return -EMFILE;
+ goto out_putf;
FD_SET(arg, &files->open_fds);
FD_CLR(arg, &files->close_on_exec);
- (files->fd[arg] = files->fd[fd])->f_count++;
- return arg;
+ fd_install(arg, file);
+ error = arg;
+out:
+ return error;
+
+out_putf:
+ fput(file);
+ goto out;
}
asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
@@ -41,7 +56,7 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
int err = -EBADF;
lock_kernel();
- if (oldfd >= NR_OPEN || !current->files->fd[oldfd])
+ if (!fcheck(oldfd))
goto out;
err = newfd;
if (newfd == oldfd)
@@ -51,7 +66,7 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
goto out; /* following POSIX.1 6.2.1 */
sys_close(newfd);
- err = dupfd(oldfd,newfd);
+ err = dupfd(oldfd, newfd);
out:
unlock_kernel();
return err;
@@ -62,7 +77,7 @@ asmlinkage int sys_dup(unsigned int fildes)
int ret;
lock_kernel();
- ret = dupfd(fildes,0);
+ ret = dupfd(fildes, 0);
unlock_kernel();
return ret;
}
@@ -101,12 +116,13 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
long err = -EBADF;
lock_kernel();
- if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+ filp = fget(fd);
+ if (!filp)
goto out;
err = 0;
switch (cmd) {
case F_DUPFD:
- err = dupfd(fd,arg);
+ err = dupfd(fd, arg);
break;
case F_GETFD:
err = FD_ISSET(fd, &current->files->close_on_exec);
@@ -158,6 +174,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = -EINVAL;
break;
}
+ fput(filp);
out:
unlock_kernel();
return err;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 01a2a6d24..f56b35c53 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -30,8 +30,8 @@
#include <linux/major.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <linux/lockd/bind.h>
#include <linux/lockd/xdr.h>
@@ -192,12 +192,12 @@ asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
ret = do_nfsservctl(cmd, argp, resp);
goto out;
}
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (request_module ("nfsd") == 0) {
if (do_nfsservctl)
ret = do_nfsservctl(cmd, argp, resp);
}
-#endif /* CONFIG_KERNELD */
+#endif /* CONFIG_KMOD */
out:
unlock_kernel();
return ret;
diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog
index aa465a0a6..c063e3f2d 100644
--- a/fs/hfs/ChangeLog
+++ b/fs/hfs/ChangeLog
@@ -1,12 +1,55 @@
-Wed Jan 7 19:33:33 1998 a sun <asun@zoology.washington.edu>
+Wed Jan 21 14:04:26 1998 a sun <asun@zoology.washington.edu>
+
+ * inode.c, sysdep.c
+ use d_iput to uncache dentry from catalog entry instead of relying
+ on put_inode. no more NULL pointer dereferences!
+
+ * catalog.c
+ cleaned up hfs_cat_put a little.
+
+ ISSUES (non-fatal): mv dir dir2 while creating files in dir screws
+ up directory counts.
+
+ deletion using netatalk screws up directory
+ counts.
+
+Thu Jan 15 19:14:28 1998 a sun <asun@zoology.washington.edu>
+
+ * catalog.c
+ make deletion happen when requested instead of waiting until
+ an hfs_cat_put as the dcache can hold onto entries for quite
+ some time.
+
+Wed Jan 14 14:43:16 1998 a sun <asun@zoology.washington.edu>
+
+ * catalog.c
+ the current catalog allocation scheme allocates
+ PAGE_SIZE/sizeof(struct hfs_cat_entry) entries at a time and keeps
+ a pool of free entries up to this allocation unit * 8.
* inode.c
- don't hfs_cat_put in hfs_iget. that's a bad idea and results
- in screwed up entry counts.
+ make sure to always hfs_cat_put if hfs_iget is going to return
+ NULL.
+
+ * string.c, catalog.c
+ use linux' hashing method to generate hashes. the old hashing was
+ getting collisions. catalog.c also has a larger hash table to
+ prevent collisions.
+
+Tue Jan 13 13:06:01 1998 a sun <asun@zoology.washington.edu>
+
+ * version.c
+ bumped to 0.95+asun3
* catalog.c
- modified hfs_cat_put to undirty deleted entries without trying to
- write them out.
+ re-wrote to dynamically allocate/delete catalog entries. on a 486,
+ entries fit into the size-256 slab.
+
+Wed Jan 7 19:33:33 1998 a sun <asun@zoology.washington.edu>
+
+ * inode.c
+ don't hfs_cat_put gratuitously in hfs_iget. that's a bad
+ idea and results in screwed up entry counts.
Tue Jan 6 14:38:24 1998 a sun <asun@zoology.washington.edu>
diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile
index bab9a6e4b..7ea8e6560 100644
--- a/fs/hfs/Makefile
+++ b/fs/hfs/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for the linux nfs-filesystem routines.
+# Makefile for the linux hfs-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 4055012f1..2435ceb31 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -10,6 +10,7 @@
*
* Cache code shamelessly stolen from
* linux/fs/inode.c Copyright (C) 1991, 1992 Linus Torvalds
+ * re-shamelessly stolen Copyright (C) 1997 Linus Torvalds
*
* In function preconditions the term "valid" applied to a pointer to
* a structure means that the pointer is non-NULL and the structure it
@@ -24,16 +25,15 @@
/*================ Variable-like macros ================*/
-#define NUM_FREE_ENTRIES 8
-
/* Number of hash table slots */
-#define CCACHE_NR 128
-
-/* Max number of entries in memory */
-#define CCACHE_MAX 1024
+#define C_HASHBITS 10
+#define C_HASHSIZE (1UL << C_HASHBITS)
+#define C_HASHMASK (C_HASHSIZE - 1)
-/* Number of entries to fit in a single page on an i386 */
-#define CCACHE_INC ((PAGE_SIZE - sizeof(void *))/sizeof(struct hfs_cat_entry))
+/* Number of entries to fit in a single page on an i386.
+ * Actually, now it's used to increment the free entry pool. */
+#define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry))
+#define CCACHE_MAX (CCACHE_INC * 8)
/*================ File-local data types ================*/
@@ -94,18 +94,11 @@ struct hfs_cat_rec {
} u;
};
-
-struct allocation_unit {
- struct allocation_unit *next;
- struct hfs_cat_entry entries[CCACHE_INC];
-};
-
/*================ File-local variables ================*/
static LIST_HEAD(entry_in_use);
-static LIST_HEAD(entry_dirty); /* all the dirty entries */
static LIST_HEAD(entry_unused);
-static struct list_head hash_table[CCACHE_NR];
+static struct list_head hash_table[C_HASHSIZE];
spinlock_t entry_lock = SPIN_LOCK_UNLOCKED;
@@ -114,8 +107,6 @@ static struct {
int nr_free_entries;
} entries_stat;
-static struct allocation_unit *allocation = NULL;
-
/*================ File-local functions ================*/
/*
@@ -136,13 +127,16 @@ static inline hfs_u32 brec_to_id(struct hfs_brec *brec)
*
* hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer.
*/
-static inline unsigned int hashfn(const struct hfs_mdb *mdb,
+static inline unsigned long hashfn(const struct hfs_mdb *mdb,
const struct hfs_cat_key *key)
{
#define LSB(X) (((unsigned char *)(&X))[3])
- return ((unsigned int)LSB(mdb->create_date) ^
- (unsigned int)key->ParID[3] ^
- hfs_strhash(&key->CName)) % CCACHE_NR;
+ unsigned long hash;
+
+ hash = (unsigned long) mdb | (unsigned long) key->ParID[3] |
+ hfs_strhash(&key->CName);
+ hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2);
+ return hash & C_HASHMASK;
#undef LSB
}
@@ -208,24 +202,7 @@ static void unlock_entry(struct hfs_cat_entry * entry)
hfs_wake_up(&entry->wait);
}
-/*
- * clear_entry()
- *
- * Zero all the fields of an entry and place it on the free list.
- */
-static void clear_entry(struct hfs_cat_entry * entry)
-{
- wait_on_entry(entry);
- /* zero all but the wait queue */
- memset(&entry->wait, 0,
- sizeof(*entry) - offsetof(struct hfs_cat_entry, wait));
- INIT_LIST_HEAD(&entry->hash);
- INIT_LIST_HEAD(&entry->list);
- INIT_LIST_HEAD(&entry->dirty);
-}
-
-/* put entry on mdb dirty list. this only does it if it's on the hash
- * list. we also add it to the global dirty list as well. */
+/* put entry on mdb dirty list. */
void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
{
struct hfs_mdb *mdb = entry->mdb;
@@ -234,153 +211,74 @@ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry)
if (!(entry->state & HFS_DIRTY)) {
entry->state |= HFS_DIRTY;
- /* Only add valid (ie hashed) entries to the
- * dirty list */
+ /* Only add valid (ie hashed) entries to the dirty list. */
if (!list_empty(&entry->hash)) {
list_del(&entry->list);
list_add(&entry->list, &mdb->entry_dirty);
- INIT_LIST_HEAD(&entry->dirty);
- list_add(&entry->dirty, &entry_dirty);
}
}
spin_unlock(&entry_lock);
}
-/* prune all entries */
-static void dispose_list(struct list_head *head)
+/* delete an entry and remove it from the hash table. */
+static void delete_entry(struct hfs_cat_entry *entry)
{
- struct list_head *next;
- int count = 0;
-
- next = head->next;
- for (;;) {
- struct list_head * tmp = next;
-
- next = next->next;
- if (tmp == head)
- break;
- hfs_cat_prune(list_entry(tmp, struct hfs_cat_entry, list));
- count++;
- }
-}
-
-/*
- * try_to_free_entries works by getting the underlying
- * cache system to release entries. it gets called with the entry lock
- * held.
- *
- * count can be up to 2 due to both a resource and data fork being
- * listed. we can unuse dirty entries as well.
- */
-#define CAN_UNUSE(tmp) (((tmp)->count < 3) && ((tmp)->state <= HFS_DIRTY))
-static int try_to_free_entries(const int goal)
-{
- struct list_head *tmp, *head = &entry_in_use;
- LIST_HEAD(freeable);
- int found = 0, depth = goal << 1;
-
- /* try freeing from entry_in_use */
- while ((tmp = head->prev) != head && depth--) {
- struct hfs_cat_entry *entry =
- list_entry(tmp, struct hfs_cat_entry, list);
- list_del(tmp);
- if (CAN_UNUSE(entry)) {
- list_del(&entry->hash);
- INIT_LIST_HEAD(&entry->hash);
- list_add(tmp, &freeable);
- if (++found < goal)
- continue;
- break;
+ if (!(entry->state & HFS_DELETED)) {
+ entry->state |= HFS_DELETED;
+ list_del(&entry->hash);
+ INIT_LIST_HEAD(&entry->hash);
+
+ if (entry->type == HFS_CDR_FIL) {
+ /* free all extents */
+ entry->u.file.data_fork.lsize = 0;
+ hfs_extent_adj(&entry->u.file.data_fork);
+ entry->u.file.rsrc_fork.lsize = 0;
+ hfs_extent_adj(&entry->u.file.rsrc_fork);
}
- list_add(tmp, head);
}
+}
- if (found < goal) { /* try freeing from global dirty list */
- head = &entry_dirty;
- depth = goal << 1;
- while ((tmp = head->prev) != head && depth--) {
- struct hfs_cat_entry *entry =
- list_entry(tmp, struct hfs_cat_entry, dirty);
- list_del(tmp);
- if (CAN_UNUSE(entry)) {
- list_del(&entry->hash);
- INIT_LIST_HEAD(&entry->hash);
- list_del(&entry->list);
- INIT_LIST_HEAD(&entry->list);
- list_add(&entry->list, &freeable);
- if (++found < goal)
- continue;
- break;
- }
- list_add(tmp, head);
- }
- }
-
- if (found) {
- spin_unlock(&entry_lock);
- dispose_list(&freeable);
- spin_lock(&entry_lock);
- }
- return found;
-}
-
-/* init_once */
-static inline void init_once(struct hfs_cat_entry *entry)
+static inline void init_entry(struct hfs_cat_entry *entry)
{
- init_waitqueue(&entry->wait);
+ memset(entry, 0, sizeof(*entry));
+ hfs_init_waitqueue(&entry->wait);
INIT_LIST_HEAD(&entry->hash);
INIT_LIST_HEAD(&entry->list);
- INIT_LIST_HEAD(&entry->dirty);
}
/*
- * grow_entries()
+ * hfs_cat_alloc()
*
- * Try to allocate more entries, adding them to the free list. this returns
- * with the spinlock held if successful
+ * Try to allocate another entry.
*/
-static struct hfs_cat_entry *grow_entries(struct hfs_mdb *mdb)
+static inline struct hfs_cat_entry *hfs_cat_alloc(void)
{
- struct allocation_unit *tmp;
- struct hfs_cat_entry * entry;
- int i;
+ struct hfs_cat_entry *entry;
- spin_unlock(&entry_lock);
- if ((entries_stat.nr_entries < CCACHE_MAX) &&
- HFS_NEW(tmp)) {
- spin_lock(&entry_lock);
- memset(tmp, 0, sizeof(*tmp));
- tmp->next = allocation;
- allocation = tmp;
- entry = tmp->entries;
- for (i = 1; i < CCACHE_INC; i++) {
- entry++;
- init_once(entry);
- list_add(&entry->list, &entry_unused);
- }
- init_once(tmp->entries);
+ if (!HFS_NEW(entry))
+ return NULL;
- entries_stat.nr_entries += CCACHE_INC;
- entries_stat.nr_free_entries += CCACHE_INC - 1;
- return tmp->entries;
- }
+ init_entry(entry);
+ return entry;
+}
- /* allocation failed. do some pruning and try again */
- spin_lock(&entry_lock);
- try_to_free_entries(entries_stat.nr_entries >> 2);
- {
- struct list_head *tmp = entry_unused.next;
- if (tmp != &entry_unused) {
- entries_stat.nr_free_entries--;
- list_del(tmp);
- entry = list_entry(tmp, struct hfs_cat_entry, list);
- return entry;
- }
+/* this gets called with the spinlock held. */
+static int grow_entries(void)
+{
+ struct hfs_cat_entry *entry;
+ int i;
+
+ for (i = 0; i < CCACHE_INC; i++) {
+ if (!(entry = hfs_cat_alloc()))
+ break;
+ list_add(&entry->list, &entry_unused);
}
- spin_unlock(&entry_lock);
- return NULL;
+ entries_stat.nr_entries += i;
+ entries_stat.nr_free_entries += i;
+
+ return i;
}
/*
@@ -537,7 +435,8 @@ static void __write_entry(const struct hfs_cat_entry *entry,
/*
* write_entry()
*
- * Write a modified entry back to the catalog B-tree.
+ * Write a modified entry back to the catalog B-tree. this gets called
+ * with the entry locked.
*/
static void write_entry(struct hfs_cat_entry * entry)
{
@@ -577,6 +476,7 @@ static void write_entry(struct hfs_cat_entry * entry)
}
+/* this gets called with the spinlock held. */
static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
const struct hfs_cat_key *key)
{
@@ -592,8 +492,9 @@ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb,
entry = list_entry(tmp, struct hfs_cat_entry, hash);
if (entry->mdb != mdb)
continue;
- if (hfs_cat_compare(&entry->key, key))
+ if (hfs_cat_compare(&entry->key, key)) {
continue;
+ }
entry->count++;
break;
}
@@ -609,13 +510,14 @@ static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb,
{
struct hfs_cat_entry *entry;
struct list_head *head = hash(mdb, key);
- struct list_head *tmp = entry_unused.next;
+ struct list_head *tmp;
- if (tmp != &entry_unused) {
+add_new_entry:
+ tmp = entry_unused.next;
+ if ((tmp != &entry_unused) ) {
list_del(tmp);
entries_stat.nr_free_entries--;
entry = list_entry(tmp, struct hfs_cat_entry, list);
-add_new_entry:
list_add(&entry->list, &entry_in_use);
list_add(&entry->hash, head);
entry->mdb = mdb;
@@ -629,7 +531,8 @@ add_new_entry:
if (hfs_bfind(&brec, mdb->cat_tree,
HFS_BKEY(key), HFS_BFIND_READ_EQ)) {
- /* uh oh. we failed to read the record */
+ /* uh oh. we failed to read the record.
+ * the entry doesn't actually exist. */
entry->state |= HFS_DELETED;
goto read_fail;
}
@@ -651,28 +554,18 @@ add_new_entry:
return entry;
}
- /*
- * Uhhuh.. We need to expand. Note that "grow_entries()" will
- * release the spinlock, but will return with the lock held
- * again if the allocation succeeded.
- */
- entry = grow_entries(mdb);
- if (entry) {
- /* We released the lock, so.. */
- struct hfs_cat_entry * old = find_entry(mdb, key);
- if (!old)
- goto add_new_entry;
- list_add(&entry->list, &entry_unused);
- entries_stat.nr_free_entries++;
- spin_unlock(&entry_lock);
- wait_on_entry(old);
- return old;
- }
- return entry;
+ /* try to allocate more entries. grow_entries() doesn't release
+ * the spinlock. */
+ if (grow_entries())
+ goto add_new_entry;
+ spin_unlock(&entry_lock);
+ return NULL;
-read_fail:
+read_fail:
+ /* spinlock unlocked already. we don't need to mark the entry
+ * dirty here because we know that it doesn't exist. */
remove_hash(entry);
entry->state &= ~HFS_LOCK;
hfs_wake_up(&entry->wait);
@@ -694,11 +587,6 @@ static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb,
struct hfs_cat_entry * entry;
spin_lock(&entry_lock);
- if (!entries_stat.nr_free_entries &&
- (entries_stat.nr_entries >= CCACHE_MAX))
- goto restock;
-
-search:
entry = find_entry(mdb, key);
if (!entry) {
return get_new_entry(mdb, key, read);
@@ -706,10 +594,6 @@ search:
spin_unlock(&entry_lock);
wait_on_entry(entry);
return entry;
-
-restock:
- try_to_free_entries(8);
- goto search;
}
/*
@@ -753,6 +637,9 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,
/*
* Add a writer to dir, excluding readers.
+ *
+ * XXX: this is wrong. it allows a move to occur when a directory
+ * is being written to.
*/
static inline void start_write(struct hfs_cat_entry *dir)
{
@@ -880,7 +767,10 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
goto done;
bail1:
+ /* entry really didn't exist, so we don't need to really delete it.
+ * we do need to remove it from the hash, though. */
entry->state |= HFS_DELETED;
+ remove_hash(entry);
unlock_entry(entry);
bail2:
hfs_cat_put(entry);
@@ -900,13 +790,21 @@ done:
* entry that the entry is in a consistent state, since another
* process may get the entry while we sleep. That is why we
* 'goto repeat' after each operation that might sleep.
+ *
+ * ADDITIONAL NOTE: the sys_entries will remove themselves from
+ * the sys_entry list on the final iput, so we don't need
+ * to worry about them here.
+ *
+ * nothing in hfs_cat_put goes to sleep now except
+ * on the initial entry.
*/
void hfs_cat_put(struct hfs_cat_entry * entry)
{
if (entry) {
wait_on_entry(entry);
- if (!entry->count) {/* just in case */
+ /* just in case. this should never happen. */
+ if (!entry->count) {
hfs_warn("hfs_cat_put: trying to free free entry: %p\n",
entry);
return;
@@ -914,52 +812,41 @@ void hfs_cat_put(struct hfs_cat_entry * entry)
spin_lock(&entry_lock);
if (!--entry->count) {
-repeat:
- if ((entry->state & HFS_DELETED)) {
- if (entry->type == HFS_CDR_FIL) {
- /* free all extents */
- entry->u.file.data_fork.lsize = 0;
- hfs_extent_adj(&entry->u.file.data_fork);
- entry->u.file.rsrc_fork.lsize = 0;
- hfs_extent_adj(&entry->u.file.rsrc_fork);
- }
- entry->state = 0;
- } else if (entry->type == HFS_CDR_FIL) {
+ if ((entry->state & HFS_DELETED))
+ goto entry_deleted;
+
+ if ((entry->type == HFS_CDR_FIL)) {
/* clear out any cached extents */
if (entry->u.file.data_fork.first.next) {
hfs_extent_free(&entry->u.file.data_fork);
- spin_unlock(&entry_lock);
- wait_on_entry(entry);
- spin_lock(&entry_lock);
- goto repeat;
}
if (entry->u.file.rsrc_fork.first.next) {
hfs_extent_free(&entry->u.file.rsrc_fork);
- spin_unlock(&entry_lock);
- wait_on_entry(entry);
- spin_lock(&entry_lock);
- goto repeat;
}
}
/* if we put a dirty entry, write it out. */
if ((entry->state & HFS_DIRTY)) {
- list_del(&entry->dirty);
- INIT_LIST_HEAD(&entry->dirty);
- spin_unlock(&entry_lock);
+ entry->state ^= HFS_DIRTY | HFS_LOCK;
write_entry(entry);
- spin_lock(&entry_lock);
- entry->state &= ~HFS_DIRTY;
- goto repeat;
+ entry->state &= ~HFS_LOCK;
}
list_del(&entry->hash);
+entry_deleted: /* deleted entries have already been removed
+ * from the hash list. */
list_del(&entry->list);
- spin_unlock(&entry_lock);
- clear_entry(entry);
- spin_lock(&entry_lock);
- list_add(&entry->list, &entry_unused);
- entries_stat.nr_free_entries++;
+ if (entries_stat.nr_free_entries > CCACHE_MAX) {
+ HFS_DELETE(entry);
+ entries_stat.nr_entries--;
+ } else {
+ spin_unlock(&entry_lock);
+ wait_on_entry(entry);
+ init_entry(entry);
+ spin_lock(&entry_lock);
+ list_add(&entry->list, &entry_unused);
+ entries_stat.nr_free_entries++;
+ }
}
spin_unlock(&entry_lock);
}
@@ -995,20 +882,37 @@ static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb,
if (entry->mdb != mdb) {
continue;
}
+
if (!entry->count) {
list_del(&entry->hash);
INIT_LIST_HEAD(&entry->hash);
- list_del(&entry->dirty);
- INIT_LIST_HEAD(&entry->dirty);
list_del(&entry->list);
list_add(&entry->list, dispose);
continue;
}
- hfs_warn("hfs_fs: entry %p(%u:%lu) busy on removed device %s.\n",
- entry, entry->count, entry->state,
+
+ hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n",
+ entry, entry->count,
hfs_mdb_name(entry->mdb->sys_mdb));
}
+}
+
+/* delete entries from a list */
+static void delete_list(struct list_head *head)
+{
+ struct list_head *next = head->next;
+ struct hfs_cat_entry *entry;
+
+ for (;;) {
+ struct list_head * tmp = next;
+ next = next->next;
+ if (tmp == head) {
+ break;
+ }
+ entry = list_entry(tmp, struct hfs_cat_entry, list);
+ HFS_DELETE(entry);
+ }
}
/*
@@ -1026,7 +930,7 @@ void hfs_cat_invalidate(struct hfs_mdb *mdb)
invalidate_list(&mdb->entry_dirty, mdb, &throw_away);
spin_unlock(&entry_lock);
- dispose_list(&throw_away);
+ delete_list(&throw_away);
}
/*
@@ -1052,9 +956,6 @@ void hfs_cat_commit(struct hfs_mdb *mdb)
if (!entry->count)
insert = entry_in_use.prev;
- /* remove from global dirty list */
- list_del(&entry->dirty);
- INIT_LIST_HEAD(&entry->dirty);
/* add to in_use list */
list_del(&entry->list);
@@ -1077,16 +978,13 @@ void hfs_cat_commit(struct hfs_mdb *mdb)
*
* Releases all the memory allocated in grow_entries().
* Must call hfs_cat_invalidate() on all MDBs before calling this.
+ * This only gets rid of the unused pool of entries. all the other
+ * entry references should have either been freed by cat_invalidate
+ * or moved onto the unused list.
*/
void hfs_cat_free(void)
{
- struct allocation_unit *tmp;
-
- while (allocation) {
- tmp = allocation->next;
- HFS_DELETE(allocation);
- allocation = tmp;
- }
+ delete_list(&entry_unused);
}
/*
@@ -1272,6 +1170,9 @@ struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry)
* Create a new file with the indicated name in the indicated directory.
* The file will have the indicated flags, type and creator.
* If successful an (struct hfs_cat_entry) is returned in '*result'.
+ *
+ * XXX: the presence of "record" probably means that the following two
+ * aren't currently SMP safe and need spinlocks.
*/
int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,
hfs_u8 flags, hfs_u32 type, hfs_u32 creator,
@@ -1358,7 +1259,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
/* try to delete the file or directory */
if (!error) {
- lock_entry(entry);
+ lock_entry(entry);
if ((entry->state & HFS_DELETED)) {
/* somebody beat us to it */
error = -ENOENT;
@@ -1371,8 +1272,8 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
if (!error) {
/* Mark the entry deleted and remove it from the cache */
- entry->state |= HFS_DELETED;
- remove_hash(entry);
+ lock_entry(entry);
+ delete_entry(entry);
/* try to delete the thread entry if it exists */
if (with_thread) {
@@ -1380,6 +1281,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,
(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));
}
+ unlock_entry(entry);
update_dir(mdb, parent, is_dir, -1);
}
@@ -1430,10 +1332,12 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,
return -EINVAL;
}
+ spin_lock(&entry_lock);
while (mdb->rename_lock) {
hfs_sleep_on(&mdb->rename_wait);
}
mdb->rename_lock = 1;
+ spin_unlock(&entry_lock);
/* keep readers from getting confused by changing dir size */
start_write(new_dir);
@@ -1501,7 +1405,7 @@ restart:
&new_record, is_dir ? 2 + sizeof(DIR_REC) :
2 + sizeof(FIL_REC));
if (error == -EEXIST) {
- dest->state |= HFS_DELETED;
+ delete_entry(dest);
unlock_entry(dest);
hfs_cat_put(dest);
goto restart;
@@ -1590,8 +1494,7 @@ have_distinct:
/* Something went seriously wrong.
The dir/file has been deleted. */
/* XXX try some recovery? */
- entry->state |= HFS_DELETED;
- remove_hash(entry);
+ delete_entry(entry);
goto bail1;
}
}
@@ -1620,7 +1523,7 @@ have_distinct:
/* delete any pre-existing or place-holder entry */
if (dest) {
- dest->state |= HFS_DELETED;
+ delete_entry(dest);
unlock_entry(dest);
if (removed && dest->cnid) {
*removed = dest;
@@ -1639,7 +1542,7 @@ bail2:
(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key));
update_dir(mdb, new_dir, is_dir, -1);
bail3:
- dest->state |= HFS_DELETED;
+ delete_entry(dest);
}
unlock_entry(dest);
hfs_cat_put(dest);
@@ -1649,8 +1552,10 @@ done:
end_write(old_dir);
}
end_write(new_dir);
+ spin_lock(&entry_lock);
mdb->rename_lock = 0;
hfs_wake_up(&mdb->rename_wait);
+ spin_unlock(&entry_lock);
return error;
}
@@ -1663,7 +1568,7 @@ void hfs_cat_init(void)
int i;
struct list_head *head = hash_table;
- i = CCACHE_NR;
+ i = C_HASHSIZE;
do {
INIT_LIST_HEAD(head);
head++;
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 144d9d42d..afd794155 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -95,7 +95,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
}
/*
- * update_dirs_plus()
+ * update_dirs_minus()
*
* Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
* 'i_version' of the inodes associated with a directory that has
@@ -138,10 +138,9 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry,
for (i = 0; i < 4; ++i) {
if ((de = entry->sys_entry[i]) && (dentry != de)) {
- entry->sys_entry[i] = NULL;
- dget(de);
- d_delete(de);
- dput(de);
+ dget(de);
+ d_delete(de);
+ dput(de);
}
}
}
@@ -198,7 +197,7 @@ int hfs_create(struct inode * dir, struct dentry *dentry, int mode)
error = -EIO;
} else {
if (HFS_I(dir)->d_drop_op)
- HFS_I(dir)->d_drop_op(HFS_I(dir)->file_type, dentry);
+ HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
d_instantiate(dentry, inode);
}
}
@@ -285,7 +284,7 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry)
struct hfs_cat_key key;
int error;
- if (build_key(&key, dir, dentry->d_name.name,
+ if (build_key(&key, dir, dentry->d_name.name,
dentry->d_name.len)) {
error = -EPERM;
} else if (!(victim = hfs_cat_get(entry->mdb, &key))) {
@@ -386,15 +385,15 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} else {
/* no existing inodes. just drop negative dentries */
if (HFS_I(new_dir)->d_drop_op)
- HFS_I(new_dir)->d_drop_op(HFS_I(new_dir)->file_type,
- new_dentry);
+ HFS_I(new_dir)->d_drop_op(new_dentry,
+ HFS_I(new_dir)->file_type);
update_dirs_plus(new_parent, is_dir);
}
/* update dcache */
d_move(old_dentry, new_dentry);
}
-
+
hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
return error;
}
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index d489c86ca..a7bb7f633 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -1,5 +1,4 @@
-/* linux/fs/hfs/dir_cap.c
- *
+/*
* Copyright (C) 1995-1997 Paul H. Hargrove
* This file may be distributed under the terms of the GNU Public License.
*
@@ -154,11 +153,12 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
struct hfs_cat_entry *entry;
struct hfs_cat_key key;
struct inode *inode = NULL;
-
+
if (!dir || !S_ISDIR(dir->i_mode)) {
- goto done;
+ return -ENOENT;
}
+ dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
dtype = HFS_ITYPE(dir->i_ino);
@@ -215,13 +215,13 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
HFS_I(dir)->file_type, dentry);
/* Don't return a resource fork for a directory */
- if (inode && (dtype == HFS_CAP_RDIR) &&
+ if (inode && (dtype == HFS_CAP_RDIR) &&
(HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
+ iput(inode); /* this does an hfs_cat_put */
inode = NULL;
}
done:
- dentry->d_op = &hfs_dentry_operations;
d_add(dentry, inode);
return 0;
}
@@ -261,7 +261,7 @@ static int cap_readdir(struct file * filp,
return -EBADF;
}
- entry = HFS_I(dir)->entry;
+ entry = HFS_I(dir)->entry;
type = HFS_ITYPE(dir->i_ino);
skip_dirs = (type == HFS_CAP_RDIR);
@@ -368,7 +368,7 @@ static int cap_readdir(struct file * filp,
* related calls (create, rename, and mknod). the directory calls
* should be immune. the relevant calls in dir.c call drop_dentry
* upon successful completion. */
-void hfs_cap_drop_dentry(const ino_t type, struct dentry *dentry)
+void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
{
if (type == HFS_CAP_DATA) { /* given name */
hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry);
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index c97247dc9..553fe8ef9 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -135,11 +135,12 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
struct hfs_cat_entry *entry;
struct hfs_cat_key key;
struct inode *inode = NULL;
-
+
if (!dir || !S_ISDIR(dir->i_mode)) {
- goto done;
+ return -ENOENT;
}
+ dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
/* Perform name-mangling */
@@ -175,12 +176,11 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
hfs_nameout(dir, &cname, dentry->d_name.name+1,
dentry->d_name.len-1);
hfs_cat_build_key(entry->cnid, &cname, &key);
- inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
+ inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
HFS_DBL_HDR, dentry);
}
done:
- dentry->d_op = &hfs_dentry_operations;
d_add(dentry, inode);
return 0;
}
@@ -219,7 +219,7 @@ static int dbl_readdir(struct file * filp,
return -EBADF;
}
- entry = HFS_I(dir)->entry;
+ entry = HFS_I(dir)->entry;
if (filp->f_pos == 0) {
/* Entry 0 is for "." */
@@ -414,14 +414,14 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
- if (is_hdr(new_dir, new_dentry->d_name.name,
+ if (is_hdr(new_dir, new_dentry->d_name.name,
new_dentry->d_name.len)) {
error = -EPERM;
} else {
error = hfs_rename(old_dir, old_dentry,
new_dir, new_dentry);
if ((error == -ENOENT) /*&& !must_be_dir*/ &&
- is_hdr(old_dir, old_dentry->d_name.name,
+ is_hdr(old_dir, old_dentry->d_name.name,
old_dentry->d_name.len)) {
error = -EPERM;
}
@@ -435,9 +435,8 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
* as far as i can tell, the calls that need to do this are the file
* related calls (create, rename, and mknod). the directory calls
* should be immune. the relevant calls in dir.c call drop_dentry
- * upon successful completion. this allocates an array for %name
- * on the first attempt to access it. */
-void hfs_dbl_drop_dentry(const ino_t type, struct dentry *dentry)
+ * upon successful completion. */
+void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type)
{
unsigned char tmp_name[HFS_NAMEMAX + 1];
struct dentry *de = NULL;
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index 62c9ea2cb..b29bfdc17 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -142,9 +142,10 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
struct inode *inode = NULL;
if (!dir || !S_ISDIR(dir->i_mode)) {
- goto done;
+ return -ENOENT;
}
+ dentry->d_op = &hfs_dentry_operations;
entry = HFS_I(dir)->entry;
dtype = HFS_ITYPE(dir->i_ino);
@@ -200,12 +201,11 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
if (inode && (dtype == HFS_NAT_HDIR) &&
(HFS_I(inode)->entry != entry) &&
(HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
- iput(inode);
+ iput(inode); /* this does an hfs_cat_put */
inode = NULL;
}
done:
- dentry->d_op = &hfs_dentry_operations;
d_add(dentry, inode);
return 0;
}
@@ -241,7 +241,7 @@ static int nat_readdir(struct file * filp,
return -EBADF;
}
- entry = HFS_I(dir)->entry;
+ entry = HFS_I(dir)->entry;
type = HFS_ITYPE(dir->i_ino);
skip_dirs = (type == HFS_NAT_HDIR);
@@ -329,7 +329,7 @@ static int nat_readdir(struct file * filp,
* related calls (create, rename, and mknod). the directory calls
* should be immune. the relevant calls in dir.c call drop_dentry
* upon successful completion. */
-void hfs_nat_drop_dentry(const ino_t type, struct dentry *dentry)
+void hfs_nat_drop_dentry(struct dentry *dentry, const ino_t type)
{
struct dentry *de;
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index 26f498305..e12792036 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -98,11 +98,10 @@ struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create)
to the file until we return, so it can't have moved.
*/
if (tmp) {
- hfs_cat_mark_dirty(fork->entry);
- return getblk(dev, tmp, HFS_SECTOR_SIZE);
+ hfs_cat_mark_dirty(fork->entry);
+ return getblk(dev, tmp, HFS_SECTOR_SIZE);
}
return NULL;
-
} else {
/* If reading the block, then retry since the
location on disk could have changed while
@@ -236,6 +235,7 @@ static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf,
*/
static void hfs_file_truncate(struct inode * inode)
{
+ /*struct inode *inode = dentry->d_inode;*/
struct hfs_fork *fork = HFS_I(inode)->fork;
fork->lsize = inode->i_size;
@@ -268,7 +268,7 @@ static inline void xlate_to_user(char *buf, const char *data, int count)
*/
static inline void xlate_from_user(char *data, const char *buf, int count)
{
- copy_from_user(data, buf, count);
+ count -= copy_from_user(data, buf, count);
while (count--) {
if (*data == '\n') {
*data = '\r';
@@ -398,16 +398,16 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
} else {
chars = HFS_SECTOR_SIZE - offset;
}
- count -= chars;
- read += chars;
p = (*bhe)->b_data + offset;
if (convert) {
xlate_to_user(buf, p, chars);
} else {
- copy_to_user(buf, p, chars);
+ chars -= copy_to_user(buf, p, chars);
}
brelse(*bhe);
+ count -= chars;
buf += chars;
+ read += chars;
offset = 0;
if (++bhe == &buflist[NBUF]) {
bhe = buflist;
@@ -479,7 +479,7 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
if (convert) {
xlate_from_user(p, buf, c);
} else {
- copy_from_user(p, buf, c);
+ c -= copy_from_user(p, buf, c);
}
update_vm_cache(inode,pos,p,c);
pos += c;
diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
index 7c298264a..10f39f751 100644
--- a/fs/hfs/file_cap.c
+++ b/fs/hfs/file_cap.c
@@ -164,8 +164,7 @@ static hfs_rwret_t cap_info_read(struct file *filp, char *buf,
memcount = left;
}
cap_build_meta(&meta, entry);
- /* is copy_to_user guaranteed to write memcount? */
- copy_to_user(buf, ((char *)&meta) + pos, memcount);
+ memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount);
left -= memcount;
read += memcount;
pos += memcount;
@@ -291,6 +290,8 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
*/
static void cap_info_truncate(struct inode *inode)
{
+ /*struct inode *inode = dentry->d_inode;*/
+
if (inode->i_size > HFS_FORK_MAX) {
inode->i_size = HFS_FORK_MAX;
}
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index 468a3f518..049381dd0 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -288,12 +288,10 @@ static inline void adjust_forks(struct hfs_cat_entry *entry,
(descr->length != entry->u.file.data_fork.lsize)) {
entry->u.file.data_fork.lsize = descr->length;
hfs_extent_adj(&entry->u.file.data_fork);
- hfs_cat_mark_dirty(entry);
} else if ((descr->id == HFS_HDR_RSRC) &&
(descr->length != entry->u.file.rsrc_fork.lsize)) {
entry->u.file.rsrc_fork.lsize = descr->length;
hfs_extent_adj(&entry->u.file.rsrc_fork);
- hfs_cat_mark_dirty(entry);
}
}
}
@@ -414,7 +412,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf,
}
hdr_build_meta(&meta, layout, entry);
- copy_to_user(buf, ((char *)&meta) + pos, left);
+ left -= copy_to_user(buf, ((char *)&meta) + pos, left);
count -= left;
read += left;
pos += left;
@@ -531,7 +529,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf,
/* transfer the data */
if (p) {
- copy_to_user(buf, p + offset, left);
+ left -= copy_to_user(buf, p + offset, left);
} else if (fork) {
left = hfs_do_read(inode, fork, offset, buf, left,
filp->f_reada != 0);
@@ -654,6 +652,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
/* Handle possible size changes for the forks */
if (entry->type == HFS_CDR_FIL) {
adjust_forks(entry, layout);
+ hfs_cat_mark_dirty(entry);
}
}
@@ -887,6 +886,8 @@ done:
*/
static void hdr_truncate(struct inode *inode)
{
+ /*struct inode *inode = dentry->d_inode;*/
+ struct hfs_cat_entry *entry = HFS_I(inode)->entry;
struct hfs_hdr_layout *layout;
size_t size = inode->i_size;
int lcv, last;
@@ -907,14 +908,14 @@ static void hdr_truncate(struct inode *inode)
}
if (descr->id == HFS_HDR_RSRC) {
- fork = &HFS_I(inode)->entry->u.file.rsrc_fork;
+ fork = &entry->u.file.rsrc_fork;
#if 0
/* Can't yet truncate the data fork via a header file, since there is the
* possibility to truncate via the data file, and the only locking is at
* the inode level.
*/
} else if (descr->id == HFS_HDR_DATA) {
- fork = &HFS_I(inode)->entry->u.file.data_fork;
+ fork = &entry->u.file.data_fork;
#endif
} else {
continue;
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
index ccc2f0cae..9112a6db8 100644
--- a/fs/hfs/hfs.h
+++ b/fs/hfs/hfs.h
@@ -11,10 +11,10 @@
#define _HFS_H
#include <linux/hfs_sysdep.h>
-#include <linux/hfs_fs.h>
#define HFS_NEW(X) ((X) = hfs_malloc(sizeof(*(X))))
-#define HFS_DELETE(X) { hfs_free((X), sizeof(*(X))); (X) = NULL; }
+#define HFS_DELETE(X) do { hfs_free((X), sizeof(*(X))); (X) = NULL; } \
+ while (0)
/* offsets to various blocks */
#define HFS_DD_BLK 0 /* Driver Descriptor block */
@@ -337,13 +337,12 @@ struct hfs_file {
* This structure holds information about a
* file or directory in an HFS filesystem.
*
- * 'wait' must remain 1st and 'next' 2nd since we do some pointer arithmetic.
+ * 'wait' must remain 1st and 'hash' 2nd since we do some pointer arithmetic.
*/
struct hfs_cat_entry {
hfs_wait_queue wait;
struct list_head hash;
struct list_head list;
- struct list_head dirty;
struct hfs_mdb *mdb;
hfs_sysentry sys_entry;
struct hfs_cat_key key;
@@ -366,7 +365,6 @@ struct hfs_cat_entry {
#define HFS_KEYDIRTY 2
#define HFS_LOCK 4
#define HFS_DELETED 8
-#define HFS_SUPERBLK 16
/*
* struct hfs_bnode_ref
@@ -486,14 +484,11 @@ extern void hfs_mdb_put(struct hfs_mdb *, int);
extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *);
/* string.c */
-extern unsigned int hfs_strhash(const struct hfs_name *);
+extern unsigned long hfs_strhash(const struct hfs_name *);
extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *);
extern int hfs_streq(const struct hfs_name *, const struct hfs_name *);
extern void hfs_tolower(unsigned char *, int);
-/* sysdep.c */
-extern void hfs_cat_prune(struct hfs_cat_entry *);
-
extern __inline__ struct dentry
*hfs_lookup_dentry(const char *name, const int len,
struct dentry *base)
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index a0bf3d576..340e9be79 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -73,17 +73,13 @@ static void init_file_inode(struct inode *inode, hfs_u8 fork)
*/
void hfs_put_inode(struct inode * inode)
{
- struct hfs_cat_entry *entry = HFS_I(inode)->entry;
-
- entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
- hfs_cat_put(entry);
-
if (inode->i_count == 1) {
- struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
- if (tmp) {
- HFS_I(inode)->layout = NULL;
- HFS_DELETE(tmp);
- }
+ struct hfs_hdr_layout *tmp = HFS_I(inode)->layout;
+
+ if (tmp) {
+ HFS_I(inode)->layout = NULL;
+ HFS_DELETE(tmp);
+ }
}
}
@@ -153,7 +149,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
/* We must change all in-core inodes corresponding to this file. */
for (i = 0; i < 4; ++i) {
if (de[i] && (de[i] != dentry)) {
- inode_setattr(de[i]->d_inode, attr);
+ inode_setattr(de[i]->d_inode, attr);
}
}
@@ -213,7 +209,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
* benefit from a way to pass an additional (void *) through iget() to
* the VFS read_inode() function.
*
- * hfs_iget no longer touches hfs_cat_entries.
+ * this will hfs_cat_put() the entry if it fails.
*/
struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
struct dentry *dentry)
@@ -239,25 +235,15 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
sb = entry->mdb->sys_mdb;
sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)];
- if (*sys_entry && (inode = (*sys_entry)->d_inode)) {
- /* There is an existing inode for this file/dir. Use it. */
- ++inode->i_count;
- return inode;
- }
-
- if (!(inode = iget(sb, ntohl(entry->cnid) | type)))
+ if (!(inode = iget(sb, ntohl(entry->cnid) | type))) {
+ hfs_cat_put(entry);
return NULL;
+ }
if (inode->i_dev != sb->s_dev) {
- iput(inode);
+ iput(inode); /* automatically does an hfs_cat_put */
inode = NULL;
- } else if (inode->i_mode) {
- /* The inode has been initialized by another process.
- Note that if hfs_put_inode() is sleeping in hfs_cat_put()
- then we still need to attach it to the entry. */
- if (!(*sys_entry))
- *sys_entry = dentry; /* cache dentry */
- } else {
+ } else if (!inode->i_mode) {
/* Initialize the inode */
struct hfs_sb_info *hsb = HFS_SB(sb);
@@ -281,10 +267,11 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
if (!inode->i_mode) {
clear_inode(inode);
+ hfs_cat_put(entry);
inode = NULL;
- }
+ } else
+ *sys_entry = dentry; /* cache dentry */
- *sys_entry = dentry; /* cache dentry */
}
return inode;
diff --git a/fs/hfs/string.c b/fs/hfs/string.c
index cacc0a604..030850b82 100644
--- a/fs/hfs/string.c
+++ b/fs/hfs/string.c
@@ -81,11 +81,14 @@ static unsigned char casefold[256] = {
/*
* Hash a string to an integer in a case-independent way
*/
-unsigned int hfs_strhash(const struct hfs_name *cname)
+unsigned long hfs_strhash(const struct hfs_name *cname)
{
- /* Currently just sum of the 'order' of first and last characters */
- return ((unsigned int)caseorder[cname->Name[0]] +
- (unsigned int)caseorder[cname->Name[cname->Len - 1]]);
+ unsigned long hash = init_name_hash();
+ unsigned int i;
+ for (i = 0; i < cname->Len; i++) {
+ hash = partial_name_hash(caseorder[cname->Name[i]], hash);
+ }
+ return end_name_hash(hash);
}
/*
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 897130297..9e278d383 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -163,8 +163,8 @@ static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len)
tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
tmp.f_bavail = tmp.f_bfree;
- tmp.f_files = mdb->fs_ablocks; /* According to the statfs manual page, -1 is the */
- tmp.f_ffree = mdb->free_ablocks; /* correct value when the meaning is undefined. */
+ tmp.f_files = mdb->fs_ablocks;
+ tmp.f_ffree = mdb->free_ablocks;
tmp.f_namelen = HFS_NAMELEN;
return copy_to_user(buf, &tmp, len) ? -EFAULT : 0;
@@ -459,16 +459,13 @@ struct super_block *hfs_read_super(struct super_block *s, void *data,
if (!root_inode)
goto bail_no_root;
- /* cache the dentry in the inode */
- s->s_root =
- HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
- d_alloc_root(root_inode, NULL);
+ s->s_root = d_alloc_root(root_inode, NULL);
if (!s->s_root)
goto bail_no_root;
- /* HFS_SUPERBLK prevents the root inode from being flushed
- * inadvertantly. */
- HFS_I(root_inode)->entry->state = HFS_SUPERBLK;
+ /* fix up pointers. */
+ HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] =
+ s->s_root;
s->s_root->d_op = &hfs_dentry_operations;
/* everything's okay */
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
index fc7368a75..659d0b2fc 100644
--- a/fs/hfs/sysdep.c
+++ b/fs/hfs/sysdep.c
@@ -19,13 +19,16 @@
#include <linux/hfs_fs.h>
static int hfs_hash_dentry(struct dentry *, struct qstr *);
-static int hfs_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
+static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
+static void hfs_dentry_iput(struct dentry *, struct inode *);
struct dentry_operations hfs_dentry_operations =
{
NULL, /* d_validate(struct dentry *) */
hfs_hash_dentry, /* d_hash */
hfs_compare_dentry, /* d_compare */
- NULL /* d_delete(struct dentry *) */
+ NULL, /* d_delete(struct dentry *) */
+ NULL, /* d_release(struct dentry *) */
+ hfs_dentry_iput /* d_iput(struct dentry *, struct inode *) */
};
/*
@@ -55,19 +58,16 @@ hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) {
/* dentry case-handling: just lowercase everything */
-/* should we use hfs_strhash? if so, it probably needs to be beefed
- * up a little. */
+/* hfs_strhash now uses the same hashing function as the dcache. */
static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
{
- unsigned char name[HFS_NAMELEN];
- int len = this->len;
+ struct hfs_name cname;
- if (len > HFS_NAMELEN)
+ if ((cname.Len = this->len) > HFS_NAMELEN)
return 0;
-
- strncpy(name, this->name, len);
- hfs_tolower(name, len);
- this->hash = full_name_hash(name, len);
+
+ strncpy(cname.Name, this->name, this->len);
+ this->hash = hfs_strhash(&cname);
return 0;
}
@@ -86,18 +86,11 @@ static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a,
return hfs_streq(&s1, &s2);
}
-
-/* toss a catalog entry. this does it by dropping the dentry. */
-void hfs_cat_prune(struct hfs_cat_entry *entry)
+static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{
- int i;
+ struct hfs_cat_entry *entry = HFS_I(inode)->entry;
- for (i = 0; i < 4; i++) {
- struct dentry *de = entry->sys_entry[i];
- if (de) {
- dget(de);
- d_drop(de);
- dput(de);
- }
- }
+ entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
+ hfs_cat_put(entry);
+ iput(inode);
}
diff --git a/fs/hfs/version.c b/fs/hfs/version.c
index 8eb74084d..8652c1cca 100644
--- a/fs/hfs/version.c
+++ b/fs/hfs/version.c
@@ -7,4 +7,4 @@
* This file contains the version string for this release.
*/
-const char hfs_version[]="0.95+asun2";
+const char hfs_version[]="0.95+asun3";
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index 48cf4aa86..bdb973e41 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -1,7 +1,7 @@
#
# NCP Filesystem configuration
#
-# bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING
+bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING
bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile
index 5c83ada11..9c33bc515 100644
--- a/fs/ncpfs/Makefile
+++ b/fs/ncpfs/Makefile
@@ -8,7 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := ncpfs.o
-O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o
+O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
+ ncpsign_kernel.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 8424b2ec7..bec1c55a2 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -112,7 +112,7 @@ static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
static void ncp_delete_dentry(struct dentry *);
-static struct dentry_operations ncp_dentry_operations =
+struct dentry_operations ncp_dentry_operations =
{
ncp_lookup_validate, /* d_validate(struct dentry *) */
ncp_hash_dentry, /* d_hash */
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index f11f4640c..c872c2b84 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -25,9 +25,6 @@
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
@@ -287,6 +284,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->buffer_size = 0;
server->conn_status = 0;
server->root_dentry = NULL;
+ server->root_setuped = 0;
#ifdef CONFIG_NCPFS_PACKET_SIGNING
server->sign_wanted = 0;
server->sign_active = 0;
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 078d26596..2df6fee09 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -32,6 +32,22 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
struct ncp_ioctl_request request;
struct ncp_fs_info info;
+#ifdef NCP_IOC_GETMOUNTUID_INT
+ /* remove after ncpfs-2.0.13/2.2.0 gets released */
+ if ((NCP_IOC_GETMOUNTUID != NCP_IOC_GETMOUNTUID_INT) &&
+ (cmd == NCP_IOC_GETMOUNTUID_INT)) {
+ int tmp = server->m.mounted_uid;
+
+ if ( (permission(inode, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid))
+ {
+ return -EACCES;
+ }
+ if (put_user(tmp, (unsigned int*) arg)) return -EFAULT;
+ return 0;
+ }
+#endif /* NCP_IOC_GETMOUNTUID_INT */
+
switch (cmd) {
case NCP_IOC_NCPREQUEST:
@@ -80,6 +96,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
&& (current->uid != server->m.mounted_uid)) {
return -EACCES;
}
+ if (server->root_setuped) return -EBUSY;
+ server->root_setuped = 1;
return ncp_conn_logged_in(server);
case NCP_IOC_GET_FS_INFO:
@@ -121,19 +139,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
put_user(server->m.mounted_uid, (uid_t *) arg);
return 0;
- case NCP_IOC_GETMOUNTUID_INT:
- if ( (permission(inode, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
- return -EACCES;
- }
-
- {
- unsigned int tmp=server->m.mounted_uid;
- if (put_user(tmp, (unsigned long*) arg)) return -EFAULT;
- }
- return 0;
-
#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
case NCP_IOC_GETROOT:
{
@@ -168,6 +173,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
{
return -EACCES;
}
+ if (server->root_setuped) return -EBUSY;
if (copy_from_user(&sr,
(struct ncp_setroot_ioctl*)arg,
sizeof(sr))) return -EFAULT;
@@ -184,6 +190,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
}
}
dentry = server->root_dentry;
+ server->root_setuped = 1;
if (dentry) {
struct inode* inode = dentry->d_inode;
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
new file mode 100644
index 000000000..bae89c197
--- /dev/null
+++ b/fs/ncpfs/ncpsign_kernel.c
@@ -0,0 +1,114 @@
+/*
+ * ncpsign_kernel.c
+ *
+ * Arne de Bruijn (arne@knoware.nl), 1997
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_NCPFS_PACKET_SIGNING
+
+#include <linux/string.h>
+#include <linux/ncp.h>
+#include "ncpsign_kernel.h"
+
+#define rol32(i,c) (((((i)&0xffffffff)<<c)&0xffffffff)| \
+ (((i)&0xffffffff)>>(32-c)))
+/* i386: 32-bit, little endian, handles mis-alignment */
+#ifdef __i386__
+#define GET_LE32(p) (*(int *)(p))
+#define PUT_LE32(p,v) { *(int *)(p)=v; }
+#else
+/* from include/ncplib.h */
+#define BVAL(buf,pos) (((__u8 *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
+#define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
+
+static inline word
+WVAL_LH(__u8 * buf, int pos)
+{
+ return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
+}
+static inline dword
+DVAL_LH(__u8 * buf, int pos)
+{
+ return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
+}
+static inline void
+WSET_LH(__u8 * buf, int pos, word val)
+{
+ BSET(buf, pos, val & 0xff);
+ BSET(buf, pos + 1, val >> 8);
+}
+static inline void
+DSET_LH(__u8 * buf, int pos, dword val)
+{
+ WSET_LH(buf, pos, val & 0xffff);
+ WSET_LH(buf, pos + 2, val >> 16);
+}
+
+#define GET_LE32(p) DVAL_LH(p,0)
+#define PUT_LE32(p,v) DSET_LH(p,0,v)
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+static void nwsign(char *r_data1, char *r_data2, char *outdata) {
+ int i;
+ unsigned int w0,w1,w2,w3;
+ static int rbit[4]={0, 2, 1, 3};
+#ifdef __i386__
+ unsigned int *data2=(int *)r_data2;
+#else
+ unsigned int data2[16];
+ for (i=0;i<16;i++)
+ data2[i]=GET_LE32(r_data2+(i<<2));
+#endif
+ w0=GET_LE32(r_data1);
+ w1=GET_LE32(r_data1+4);
+ w2=GET_LE32(r_data1+8);
+ w3=GET_LE32(r_data1+12);
+ for (i=0;i<16;i+=4) {
+ w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3);
+ w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7);
+ w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11);
+ w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19);
+ }
+ for (i=0;i<4;i++) {
+ w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3);
+ w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5);
+ w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9);
+ w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13);
+ }
+ for (i=0;i<4;i++) {
+ w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3);
+ w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9);
+ w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11);
+ w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15);
+ }
+ PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff);
+ PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff);
+ PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff);
+ PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff);
+}
+
+/* Make a signature for the current packet and add it at the end of the */
+/* packet. */
+void sign_packet(struct ncp_server *server, int *size) {
+ char data[64];
+
+ memset(data,0,64);
+ memcpy(data,server->sign_root,8);
+ PUT_LE32(data+8,(*size));
+ memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1,
+ min((*size)-sizeof(struct ncp_request_header)+1,52));
+
+ nwsign(server->sign_last,data,server->sign_last);
+
+ memcpy(server->packet+(*size),server->sign_last,8);
+ (*size)+=8;
+}
+
+#endif /* CONFIG_NCPFS_PACKET_SIGNING */
+
diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h
new file mode 100644
index 000000000..85974f346
--- /dev/null
+++ b/fs/ncpfs/ncpsign_kernel.h
@@ -0,0 +1,16 @@
+/*
+ * ncpsign_kernel.h
+ *
+ * Arne de Bruijn (arne@knoware.nl), 1997
+ *
+ */
+
+#ifndef _NCPSIGN_KERNEL_H
+#define _NCPSIGN_KERNEL_H
+
+#include <linux/ncp_fs.h>
+#include <linux/ncp_fs_sb.h>
+
+void sign_packet(struct ncp_server *server, int *size);
+
+#endif
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 8300fee67..2de790e42 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -650,10 +650,31 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
inode->i_ino);
status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
if (status) {
+ int error;
+ u32 *fh;
+ struct nfs_fh fhandle;
#ifdef NFS_PARANOIA
printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
#endif
+ if (status != -ESTALE)
+ goto out;
+ /*
+ * A "stale filehandle" error ... show the current fh
+ * and find out what the filehandle should be.
+ */
+ fh = (u32 *) NFS_FH(dentry);
+ printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
+ fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
+ error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent),
+ dentry->d_name.name, &fhandle, &fattr);
+ if (error) {
+ printk("NFS: lookup failed, error=%d\n", error);
+ goto out;
+ }
+ fh = (u32 *) &fhandle;
+ printk(" %08x%08x%08x%08x%08x%08x%08x%08x\n",
+ fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
goto out;
}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 216aafb80..1c6a74a71 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -22,6 +22,9 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
+/* Uncomment this to support servers requiring longword lengths */
+#define NFS_PAD_WRITES 1
+
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
@@ -181,7 +184,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
/*
* Arguments to a READ call. Since we read data directly into the page
* cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page wewant to fetch.
+ * exactly to the page we want to fetch.
*/
static int
nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
@@ -258,18 +261,38 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
static int
nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
+ u32 count = args->count;
+
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->offset);
*p++ = htonl(args->offset);
- *p++ = htonl(args->count);
- *p++ = htonl(args->count);
+ *p++ = htonl(count);
+ *p++ = htonl(count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
req->rq_svec[1].iov_base = (void *) args->buffer;
- req->rq_svec[1].iov_len = args->count;
- req->rq_slen += args->count;
+ req->rq_svec[1].iov_len = count;
+ req->rq_slen += count;
req->rq_snr = 2;
+#ifdef NFS_PAD_WRITES
+ /*
+ * Some old servers require that the message length
+ * be a multiple of 4, so we pad it here if needed.
+ */
+ count = ((count + 3) & ~3) - count;
+ if (count) {
+#if 0
+printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n",
+req->rq_svec[1].iov_len, req->rq_slen, count);
+#endif
+ req->rq_svec[2].iov_base = (void *) "\0\0\0";
+ req->rq_svec[2].iov_len = count;
+ req->rq_slen += count;
+ req->rq_snr = 3;
+ }
+#endif
+
return 0;
}
@@ -334,12 +357,21 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
static int
nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_task *task = req->rq_task;
+ struct rpc_auth *auth = task->tk_auth;
+ u32 bufsiz = args->bufsiz;
int replen;
+ /*
+ * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
+ * to be in longwords ... check whether to convert the size.
+ */
+ if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
+ bufsiz = bufsiz >> 2;
+
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->cookie);
- *p++ = htonl(args->bufsiz);
+ *p++ = htonl(bufsiz); /* see above */
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
/* set up reply iovec */
@@ -380,10 +412,9 @@ static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
struct iovec *iov = req->rq_rvec;
- int status, nr, len;
+ int status, nr;
char *string, *start;
- u32 *end;
- __u32 fileid, cookie, *entry;
+ u32 *end, *entry, len, fileid, cookie;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -398,17 +429,25 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
end = (u32 *) ((u8 *) p + iov[1].iov_len);
/* Get start and end of dirent buffer */
- entry = (__u32 *) res->buffer;
+ entry = (u32 *) res->buffer;
start = (char *) res->buffer;
string = (char *) res->buffer + res->bufsiz;
for (nr = 0; *p++; nr++) {
fileid = ntohl(*p++);
len = ntohl(*p++);
+ /*
+ * Check whether the server has exceeded our reply buffer,
+ * and set a flag to convert the size to longwords.
+ */
if ((p + QUADLEN(len) + 3) > end) {
- printk(KERN_WARNING "NFS: short readdir reply! "
- "nr=%d, slots=%d, len=%d\n",
+ struct rpc_clnt *clnt = req->rq_task->tk_client;
+ printk(KERN_WARNING
+ "NFS: server %s, readdir reply truncated\n",
+ clnt->cl_server);
+ printk(KERN_WARNING "NFS: nr=%d, slots=%d, len=%d\n",
nr, (end - p), len);
+ clnt->cl_flags |= NFS_CLNTF_BUFSIZE;
break;
}
if (len > NFS_MAXNAMLEN) {
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 33e6dfd26..afc219838 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -12,8 +12,8 @@
#include <linux/config.h>
#include <linux/nls.h>
#include <linux/malloc.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <asm/byteorder.h>
@@ -205,7 +205,7 @@ struct nls_table *find_nls(char *charset)
struct nls_table *load_nls(char *charset)
{
struct nls_table *nls;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
char buf[40];
int ret;
#endif
@@ -216,7 +216,7 @@ struct nls_table *load_nls(char *charset)
return nls;
}
-#ifndef CONFIG_KERNELD
+#ifndef CONFIG_KMOD
return NULL;
#else
if (strlen(charset) > sizeof(buf) - sizeof("nls_")) {
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index aa6a7c40c..d190b21e4 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -776,13 +776,13 @@ struct super_block * ntfs_read_super(struct super_block *sb,
struct buffer_head *bh;
int i;
- /* When the driver is compiled as a module, kerneld must know when it
+ /* When the driver is compiled as a module, kmod must know when it
* can safely remove it from memory. To do this, each module owns a
* reference counter.
*/
MOD_INC_USE_COUNT;
/* Don't put ntfs_debug() before MOD_INC_USE_COUNT, printk() can block
- * so this could lead to a race condition with kerneld.
+ * so this could lead to a race condition with kmod.
*/
ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
@@ -939,7 +939,7 @@ __initfunc(int init_ntfs_fs(void))
#ifdef MODULE
/* A module is a piece of code which can be inserted in and removed
* from the running kernel whenever you want using lsmod, or on demand using
- * kerneld
+ * kmod
*/
/* No function of this module is needed by another module */
@@ -956,7 +956,7 @@ MODULE_PARM_DESC(ntdebug, "Debug level");
/* When this code is compiled as a module, if you use mount -t ntfs when no
* ntfs filesystem is registered (see /proc/filesystems), get_fs_type() in
- * fs/super.c asks kerneld to load the module named ntfs in memory.
+ * fs/super.c asks kmod to load the module named ntfs in memory.
*
* Therefore, this function is the main entry point in this case
*/
@@ -965,7 +965,7 @@ int init_module(void)
return init_ntfs_fs();
}
-/* Called by kerneld just before the kernel removes the module from memory */
+/* Called by kmod just before the kernel removes the module from memory */
void cleanup_module(void)
{
SYSCTL(0);
diff --git a/fs/open.c b/fs/open.c
index 5b0ff9924..204294cc3 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -681,24 +681,37 @@ out:
}
/*
- * Find an empty file descriptor entry, and mark it busy
+ * Find an empty file descriptor entry, and mark it busy.
*/
int get_unused_fd(void)
{
- int fd;
struct files_struct * files = current->files;
+ int fd, error;
+ error = -EMFILE;
fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
/*
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
*/
- if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) {
- FD_SET(fd, &files->open_fds);
- FD_CLR(fd, &files->close_on_exec);
- return fd;
+ if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+ goto out;
+
+ /* Check here for fd > files->max_fds to do dynamic expansion */
+
+ FD_SET(fd, &files->open_fds);
+ FD_CLR(fd, &files->close_on_exec);
+#if 1
+ /* Sanity check */
+ if (files->fd[fd] != NULL) {
+ printk("get_unused_fd: slot %d not NULL!\n", fd);
+ files->fd[fd] = NULL;
}
- return -EMFILE;
+#endif
+ error = fd;
+
+out:
+ return error;
}
inline void put_unused_fd(unsigned int fd)
@@ -796,15 +809,15 @@ asmlinkage int sys_close(unsigned int fd)
{
int error;
struct file * filp;
- struct files_struct * files;
lock_kernel();
- files = current->files;
error = -EBADF;
- if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) {
+ filp = fcheck(fd);
+ if (filp) {
+ struct files_struct * files = current->files;
+ files->fd[fd] = NULL;
put_unused_fd(fd);
FD_CLR(fd, &files->close_on_exec);
- files->fd[fd] = NULL;
error = close_fp(filp, files);
}
unlock_kernel();
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 5364cea14..33df2c56a 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -446,7 +446,11 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e
static int get_env(int pid, char * buffer)
{
- struct task_struct *p = find_task_by_pid(pid);
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p || !p->mm)
return 0;
@@ -455,8 +459,11 @@ static int get_env(int pid, char * buffer)
static int get_arg(int pid, char * buffer)
{
- struct task_struct *p = find_task_by_pid(pid);
+ struct task_struct *p;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p || !p->mm)
return 0;
return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
@@ -781,8 +788,11 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
static int get_status(int pid, char * buffer)
{
char * orig = buffer;
- struct task_struct *tsk = find_task_by_pid(pid);
+ struct task_struct *tsk;
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
buffer = task_name(tsk, buffer);
@@ -794,7 +804,7 @@ static int get_status(int pid, char * buffer)
static int get_stat(int pid, char * buffer)
{
- struct task_struct *tsk = find_task_by_pid(pid);
+ struct task_struct *tsk;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
int tty_pgrp;
@@ -805,6 +815,9 @@ static int get_stat(int pid, char * buffer)
char sigcatch_str[sizeof(sigset_t)*2+1];
char state;
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
state = *get_task_state(tsk);
@@ -959,6 +972,9 @@ static int get_statm(int pid, char * buffer)
struct task_struct *tsk = find_task_by_pid(pid);
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
if (tsk->mm && tsk->mm != &init_mm) {
@@ -1041,7 +1057,9 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
goto out;
retval = -EINVAL;
+ read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!p)
goto freepage_out;
@@ -1152,9 +1170,11 @@ static int get_pidcpu(int pid, char * buffer)
{
struct task_struct * tsk = current ;
int i, len;
-
+
+ read_lock(&tasklist_lock);
if (pid != tsk->pid)
tsk = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (tsk == NULL)
return 0;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index dc182682a..e535276bb 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -60,12 +60,14 @@ static void proc_pid_fill_inode(struct inode * inode, int fill)
int pid = inode->i_ino >> 16;
int ino = inode->i_ino & 0xffff;
+ read_lock(&tasklist_lock);
if (fill && (p = find_task_by_pid(pid)) != NULL) {
if (p->dumpable || ino == PROC_PID_INO) {
inode->i_uid = p->euid;
inode->i_gid = p->gid;
}
}
+ read_unlock(&tasklist_lock);
}
/*
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 4baa299fc..8897578d6 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -96,7 +96,9 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
break;
}
}
+ read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */
if (!pid || !p)
return -ENOENT;
@@ -149,7 +151,9 @@ static int proc_readfd(struct file * filp,
return 0;
}
+ read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */
if(!p)
return 0;
tarrayp = p->tarray_ptr;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index c33616604..9a0e29a84 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -260,7 +260,13 @@ void proc_read_inode(struct inode * inode)
inode->i_size = 0;
pid = ino >> 16;
- if (!pid || ((p = find_task_by_pid(pid)) == NULL))
+ if (!pid)
+ return;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!! This should be done only after we have stopped using 'p' */
+
+ if (!p)
return;
ino &= 0x0000ffff;
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index c49f187c0..1cbdbad9a 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -83,7 +83,9 @@ static ssize_t mem_read(struct file * file, char * buf,
char *tmp;
ssize_t scount, i;
+ read_lock(&tasklist_lock);
tsk = get_task(inode->i_ino >> 16);
+ read_unlock(&tasklist_lock); /* FIXME: This should really be done only afetr not using tsk any more!!! */
if (!tsk)
return -ESRCH;
addr = *ppos;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 3e344bd09..ad3a541cb 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -14,8 +14,8 @@
#include <linux/stat.h>
#include <linux/config.h>
#include <asm/bitops.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
/*
@@ -234,7 +234,7 @@ proc_openprom_deregister(void)
}
#endif
-#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
+#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KMOD)
static int
proc_openprom_defreaddir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
@@ -812,14 +812,18 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
break;
}
}
+ read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
inode = NULL;
if (pid && p) {
unsigned long ino = (pid << 16) + PROC_PID_INO;
inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
- if (!inode)
+ if (!inode) {
+ read_unlock(&tasklist_lock);
return -EINVAL;
+ }
}
+ read_unlock(&tasklist_lock);
dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
diff --git a/fs/super.c b/fs/super.c
index 84ef3ffb8..50a6cb9a6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -37,14 +37,14 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
-
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
#include <linux/nfs_mount.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
/*
* We use a semaphore to synchronize all mount/umount
* activity - imagine the mess if we have a race between
@@ -405,7 +405,7 @@ struct file_system_type *get_fs_type(const char *name)
return fs;
for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (!fs && (request_module(name) == 0)) {
for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
;
diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt
index e48a4d184..ddc2911fc 100644
--- a/fs/umsdos/README-WIP.txt
+++ b/fs/umsdos/README-WIP.txt
@@ -32,34 +32,42 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver
- long file names - works
- read file - works
- switching MSDOS/UMSDOS - works?
-- switching UMSDOS/MSDOS - untested
-- pseudo root things - commented out mostly currently. To be fixed when
+- switching UMSDOS/MSDOS - UNTESTED
+- pseudo root things - COMMENTED OUT mostly currently. To be fixed when
dentries stuff is straightened out.
- resolve symlink - seems to work fully now!
- dereference symlink - seems to work fully now!
- hard links - seems to work now
- special files (block/char device, fifos, sockets...) - seems to work ok.
-- other ioctls - mostly untested
+- other ioctls - MOSTLY UNTESTED
- dangling symlink - UNTESTED !
-- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- create file - creates, but corrupts. after reboot seem ok ?
-- create special file - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- write to file - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- rename file (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- rename file (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- rename dir (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- rename dir (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- delete file - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- delete hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
-- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- create symlink - works on short names, but fails (gets
+ truncated on long ones) (also
+ due to some dentries problems, it may not
+ be visible right away always - eg. before
+ umount/mount)
+- create hardlink - WARNING: NOT FIXED YET!
+- create file - creates short names, but probs with long ones ?
+- create special file - seems to work on short names.
+- write to file - seems to work on short names.
+- rename file (same dir) - WARNING: NOT FIXED YET!
+- rename file (dif. dir) - WARNING: NOT FIXED YET!
+- rename dir (same dir) - WARNING: NOT FIXED YET!
+- rename dir (dif. dir) - WARNING: NOT FIXED YET!
+- delete file - WARNING: NOT FIXED YET!
+- notify_change (chown,perms) - seems to work!
+- delete hardlink - WARNING: NOT FIXED YET!
+- mkdir - seems to work, even with long names ! (but
+ due to some dentries problems, it may not
+ be visible right away always - eg. before
+ umount/mount)
+- rmdir - WARNING: NOT FIXED YET!
+- umssyncing - does something :-), but NEEDS EXTENSIVE TESTING
Notes: moderate dentry/inode kernel structures trashing. Probably some other
kernel structures compromised. Have SysRq support compiled in, and use
-Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then
+Sync/Emergency-remount-RO. And if you don't try mounting read/write -
you should have no big problems...
Notes2: kernel structures trashing seems to be _MUCH_ lower if no
@@ -69,6 +77,17 @@ Notes3: Notes2 is probably somewhat outdated now that hardlink/symlink stuff
is supposed to be fixed enough to work, but I haven't got the time to test
it.
+Note4: on failure of creating of long filenames: MSDOS filename gets
+created, and EMD entry gets created. Check: either they mismatch, or EMD
+entry contains some wrong flags.
+
+Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which
+uses dentry->d_parent, which we neglect to set, so it returns -ENOENT.
+Probably same problem on unlink(2) ? What to do ? How to set
+dentry->d_parent to something useful ?? Must I recurse down whole pathname
+and set one by one all directory components ?! or only last one is really
+needed ? help !
+
------------------------------------------------------------------------------
Some general notes:
@@ -85,7 +104,7 @@ compile/test/reboot/set_environment/recompile cycle by removing
'reboot/set_environment' component that now occures every few cycles.
But I need some help from someone knowing about dentries/inodes use more
-than I. If you can help, please contact me... I'm mostly worries about
+than I. If you can help, please contact me... I'm mostly worried about
iget/iput and dget/dput, and deallocating temporary dentries we create.
should we destroy temp dentries ? using d_invalidate ? using d_drop ? just
dput them ?
@@ -96,9 +115,9 @@ any direct Email in few days. If I don't - probably I never got your
message. You can try mnalis@open.hr or mnalis@voyager.hr; however
mnalis@jagor.srce.hr is preferable one.
-------------------------------------------------------------------------------
-some of my notes for myself:
+------------------------------------------------------------------------------
+some of my notes for myself /mn/:
+ hardlinks/symlinks. test with files in not_the_same_dir
- also test not_the_same_dir for other file operations like rename etc.
@@ -108,3 +127,17 @@ some of my notes for myself:
- what about .dotfiles ? working ? multiple dots ? etc....
- fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular?
+
+- umsdos_create_any - calling msdos_create will create dentry for shor name. Hmmmm..?
+- kill_dentry - put it where is needed. Also dput() at needed places.
+
+- when should dput()/iput() be used ?!!
+
+- probably problem with filename mangling somewhere, since both create and
+ write to file work on short filenames, but fail on long ones. Path
+ components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will
+ succeed, but mkfifo /mnt/very_long_filename.txt won't)
+
+
+- what is dir->i_count++ ? locking directory ? should this be lock_parent or
+something ?
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index be1af20f7..52a72367e 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -31,7 +31,7 @@ extern struct inode *pseudo_root;
uses. It's easier to do once than hack all the other instances. Probably safer as well
*/
-int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode)
+int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struct inode **inode)
{
int rv;
struct dentry *dentry;
@@ -39,6 +39,7 @@ int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct
dentry = creat_dentry (name, len, NULL);
rv = umsdos_real_lookup(dir,dentry);
if (inode) *inode = dentry->d_inode;
+ kill_dentry (dentry);
return rv;
}
@@ -458,6 +459,7 @@ void umsdos_lookup_patch (
if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n");
}
}
+
struct UMSDOS_DIRENT_K{
off_t f_pos; /* will hold the offset of the entry in EMD */
ino_t ino;
@@ -533,6 +535,9 @@ int umsdos_inode2entry (
/* This is a DOS directory */
struct UMSDOS_DIR_SEARCH bufk;
struct file filp;
+
+ fill_new_filp (&filp, NULL);
+
Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n"));
filp.f_reada = 1;
filp.f_pos = 0;
@@ -548,6 +553,8 @@ int umsdos_inode2entry (
}else{
/* skip . and .. see umsdos_readdir_x() */
struct file filp;
+ fill_new_filp (&filp, NULL);
+
filp.f_reada = 1;
filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n"));
@@ -856,6 +863,9 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
struct file filp;
loff_t offs = 0;
+ fill_new_filp (&filp, NULL);
+
+
dentry_src = creat_dentry ("hlink-mn", 8, hlink);
memset (&filp, 0, sizeof (filp));
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 169a75a45..8ba6571eb 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -14,6 +14,7 @@
#include <linux/string.h>
#include <linux/msdos_fs.h>
#include <linux/umsdos_fs.h>
+#include <linux/dcache.h>
#include <asm/uaccess.h>
@@ -23,6 +24,29 @@
#define Printk(x) printk x
/*
+ * makes empty filp
+ *
+ */
+
+void fill_new_filp (struct file *filp, struct dentry *dentry)
+{
+ Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp));
+ if (dentry)
+ Printk ((" dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
+ else
+ Printk ((" dentry is NULL ! you must fill it later...\n"));
+
+ memset (filp, 0, sizeof (struct file));
+
+ filp->f_pos = 0;
+ filp->f_reada = 1;
+ filp->f_flags = O_RDWR;
+ filp->f_dentry = dentry;
+ filp->f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with SOMETHING */
+}
+
+
+/*
* makes dentry. for name name with length len. /mn/
* if inode is not NULL, puts it also.
*
@@ -34,19 +58,49 @@ struct dentry *creat_dentry (const char *name, const int len, struct inode *inod
struct qstr qname;
if (inode)
- Printk (("/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name));
+ Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name));
else
- Printk (("/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name));
+ Printk ((KERN_DEBUG "/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name));
qname.name = name;
qname.len = len;
qname.hash = 0;
ret = d_alloc (parent,&qname); /* create new dentry */
- ret->d_inode = inode;
+ ret->d_inode = NULL;
+
+ if (inode) d_add (ret, inode);
+
+/* ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */
return ret;
}
+/*
+ * removes temporary dentry created by creat_dentry
+ *
+ */
+
+void kill_dentry (struct dentry *dentry)
+{
+ if (dentry) {
+ Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name));
+ if (dentry->d_inode)
+ Printk (("inode=%lu\n", dentry->d_inode->i_ino));
+ else
+ Printk (("inode is NULL\n"));
+
+ /* FIXME: is this ok ?! /mn/ */
+ /* d_invalidate (dentry); */
+ /*dput (dentry);*/
+ } else {
+ Printk (("/mn/ kill_dentry: dentry is NULL ?!\n"));
+ }
+
+
+ Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n"));
+ return;
+}
+
/*
@@ -126,23 +180,24 @@ ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
/*
- Write to a file from kernel space
-*/
-ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
- struct file *filp,
+ * Write to file from kernel space.
+ * Does the real job, assumes all structures are initialized !
+ */
+
+
+ssize_t umsdos_file_write_kmem_real (struct file *filp,
const char *buf,
size_t count,
- loff_t *offs
- )
+ loff_t *offs)
{
- int ret;
+ ssize_t ret;
mm_segment_t old_fs = get_fs();
- struct dentry *old_dentry;
- Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n"));
+ set_fs (KERNEL_DS);
Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
- Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino));
+ Printk ((KERN_ERR " struct dentry=%p\n", filp->f_dentry));
+ Printk ((KERN_ERR " struct inode=%p\n", filp->f_dentry->d_inode));
Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs));
Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos));
@@ -152,23 +207,49 @@ ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid));
Printk ((KERN_ERR " f_version=%ld\n", filp->f_version));
Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+ ret = fat_file_write (filp, buf, count, offs);
+ PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret));
+
+ set_fs (old_fs);
+ return ret;
+}
+
+
+/*
+ * Write to a file from kernel space
+ */
+
+ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
+ struct file *filp,
+ const char *buf,
+ size_t count,
+ loff_t *offs
+ )
+{
+ int ret;
+ struct dentry *old_dentry;
+
- set_fs (KERNEL_DS);
+ Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n"));
+ Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino));
+
old_dentry=filp->f_dentry; /* save it */
filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
- *offs = filp->f_pos;
- ret = fat_file_write (filp, buf, count, offs);
- PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret));
+ *offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */
+
+ ret=umsdos_file_write_kmem_real (filp, buf, count, offs);
filp->f_pos = *offs;
filp->f_dentry=old_dentry;
- set_fs (old_fs);
return ret;
}
+
+
/*
Write a block of bytes into one EMD file.
The block of data is NOT in user space.
@@ -201,7 +282,7 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir,
#endif
if (offs) myofs=*offs; /* if offs is not NULL, read it */
- Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %ld, %Ld\n", emd_dir, filp, buf, count, myofs));
+ Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %d, %Ld\n", emd_dir, filp, buf, count, myofs));
written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs);
Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n"));
if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */
@@ -216,6 +297,12 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir,
d->rdev = le16_to_cpu (d->rdev);
d->mode = le16_to_cpu (d->mode);
#endif
+
+#ifdef 1
+ if (written != count) Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count));
+#endif
+
+
return written != count ? -EIO : 0;
}
@@ -409,7 +496,9 @@ int umsdos_writeentry (
struct file filp;
struct umsdos_dirent *entry = &info->entry;
struct umsdos_dirent entry0;
-
+
+ fill_new_filp (&filp, NULL);
+
Printk (("umsdos_writeentry /mn/: entering...\n"));
emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir);
@@ -444,7 +533,7 @@ int umsdos_writeentry (
filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */
ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL);
- Printk (("emd_dir_write returned !\n"));
+ Printk (("emd_dir_write returned with %d!\n", ret));
if (ret != 0){
printk ("UMSDOS: problem with EMD file. Can't write\n");
}else{
@@ -452,7 +541,7 @@ int umsdos_writeentry (
/* dir->i_dirt = 1; FIXME iput/dput ??? */
}
- Printk (("umsdos_writeentry /mn/: returning...\n"));
+ Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
return ret;
}
@@ -541,10 +630,13 @@ static int umsdos_find (
record, multiple contiguous record are allocated.
*/
int ret = -ENOENT;
- /* FIXME -- /mn/ fixed ? */
- struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1);
+ struct inode *emd_dir;
+ struct umsdos_dirent *entry = &info->entry;
+
+ Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino));
+
+ emd_dir = umsdos_emd_dir_lookup (dir, 1);
if (emd_dir != NULL){
- struct umsdos_dirent *entry = &info->entry;
int recsize = info->recsize;
struct {
off_t posok; /* Position available to store the entry */
@@ -560,11 +652,7 @@ static int umsdos_find (
dentry = creat_dentry ("umsfind-mn", 10, emd_dir);
- buf.filp.f_pos = 0;
- buf.filp.f_reada = 1;
- buf.filp.f_flags = O_RDONLY;
- buf.filp.f_dentry = dentry;
- buf.filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */
+ fill_new_filp (&buf.filp, dentry);
buf.pos = 0;
buf.size = 0;
@@ -631,6 +719,8 @@ static int umsdos_find (
umsdos_manglename(info);
}
*pt_emd_dir = emd_dir;
+
+ Printk (("umsdos_find: returning %d\n", ret));
return ret;
}
@@ -651,7 +741,7 @@ int umsdos_newentry (
ret = -EEXIST;
}else if (ret == -ENOENT){
ret = umsdos_writeentry(dir,emd_dir,info,0);
- Printk (("umsdos_newentry EDM ret = %d\n",ret));
+ Printk (("umsdos_newentry EMD ret = %d\n",ret));
}
iput (emd_dir);
return ret;
@@ -729,6 +819,8 @@ int umsdos_isempty (struct inode *dir)
/* If the EMD file does not exist, it is certainly empty :-) */
if (emd_dir != NULL){
struct file filp;
+ fill_new_filp (&filp, NULL);
+
/* Find an empty slot */
memset (&filp, 0, sizeof (filp));
@@ -779,6 +871,7 @@ int umsdos_findentry (
}
}
iput (emd_dir);
+ Printk (("umsdos_findentry: returning %d\n", ret));
return ret;
}
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 059a780e3..e8b65558c 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -105,7 +105,7 @@ void umsdos_setup_dir_inode (struct inode *inode)
inode->i_op = &umsdos_dir_inode_operations;
}
- iput (emd_dir);
+/* iput (emd_dir); FIXME /mn/ ! */
}
}
@@ -119,9 +119,10 @@ void umsdos_set_dirinfo(
off_t f_pos)
{
struct inode *emd_owner;
- /* FIXME, I don't have a clue on this one */
- Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue\n"));
+ /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */
+/* Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino));*/
emd_owner = umsdos_emd_dir_lookup(dir,1);
+ Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
inode->u.umsdos_i.i_dir_owner = dir->i_ino;
inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
iput (emd_owner);
@@ -317,10 +318,10 @@ void UMSDOS_write_inode(struct inode *inode)
/* FIXME inode->i_dirt = 0; */
}
-int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
+
+int internal_notify_change(struct inode *inode, struct iattr *attr)
{
int ret = 0;
- struct inode *inode = dentry->d_inode;
Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n"));
@@ -362,10 +363,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
}else{
struct file filp;
struct umsdos_dirent entry;
+ struct dentry *emd_dentry;
loff_t offs;
- offs = 0;
+
+ emd_dentry = creat_dentry ("notify_emd", 10, emd_owner);
+ fill_new_filp (&filp, emd_dentry);
+
filp.f_pos = inode->u.umsdos_i.pos;
filp.f_reada = 0;
+ offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */
Printk (("pos = %Lu ", filp.f_pos));
/* Read only the start of the entry since we don't touch */
/* the name */
@@ -386,7 +392,7 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
entry.nlink = inode->i_nlink;
filp.f_pos = inode->u.umsdos_i.pos;
- offs = 0; /* FIXME */
+ offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */
ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs);
Printk (("notify pos %lu ret %d nlink %d "
@@ -407,6 +413,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
return ret;
}
+
+int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
+{
+ return internal_notify_change (dentry->d_inode, attr);
+}
+
+
+
+
/* #Specification: function name / convention
A simple convention for function name has been used in
the UMSDOS file system. First all function use the prefix
@@ -457,7 +472,7 @@ struct super_block *UMSDOS_read_super(
PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb));
res = msdos_read_super(sb,data,silent);
PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res));
- printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-1 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+ printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; }
@@ -504,7 +519,7 @@ struct super_block *UMSDOS_read_super(
The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
in the macro UMSDOS_PSDROOT_NAME.
*/
- struct dentry *root, *etc, *etc_rc, *init, *sbin; /* FIXME */
+ struct dentry *root, *etc, *etc_rc, *init, *sbin;
root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL);
sbin = creat_dentry ("sbin", 4, NULL);
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 76c486405..dcea137fe 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -39,6 +39,7 @@ static int umsdos_waitcreate(struct inode *dir)
}
return ret;
}
+
/*
Wait for any lookup process to finish
*/
@@ -48,6 +49,7 @@ static void umsdos_waitlookup (struct inode *dir)
sleep_on(&dir->u.umsdos_i.u.dir_info.p);
}
}
+
/*
Lock all other process out of this directory.
*/
@@ -90,6 +92,7 @@ void umsdos_lockcreate (struct inode *dir)
dir->u.umsdos_i.u.dir_info.pid = current->pid;
umsdos_waitlookup (dir);
}
+
/*
Lock all other process out of those two directories.
*/
@@ -115,6 +118,7 @@ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
umsdos_waitlookup(dir1);
umsdos_waitlookup(dir2);
}
+
/*
Wait until creation is finish in this directory.
*/
@@ -157,6 +161,7 @@ void umsdos_startlookup (struct inode *dir){}
static void umsdos_unlockcreate (struct inode *dir){}
void umsdos_endlookup (struct inode *dir){}
#endif
+
static int umsdos_nevercreat(
struct inode *dir,
struct dentry *dentry,
@@ -210,7 +215,11 @@ static int umsdos_create_any (
/* file */
{
- int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+ int ret;
+
+ Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
+ ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+ Printk (("%d/\n", ret));
if (ret == 0){
struct umsdos_info info;
ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info);
@@ -237,8 +246,8 @@ static int umsdos_create_any (
if (ret == 0){
struct inode *inode = dentry->d_inode;
umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
- Printk (("inode %p[%d] ",inode,inode->i_count));
- Printk (("Creation OK: [%lu] %.*s %d pos %ld\n", dir->i_ino,
+ Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count));
+ Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
info.fake.len, info.fake.fname, current->pid, info.f_pos));
}else{
/* #Specification: create / file exist in DOS
@@ -276,9 +285,10 @@ static int umsdos_create_any (
umsdos_unlockcreate(dir);
}
}
- d_add(dentry,dir);
+ /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */
return ret;
}
+
/*
Initialise the new_entry from the old for a rename operation.
(Only useful for umsdos_rename_f() below).
@@ -425,6 +435,7 @@ static int umsdos_rename_f(
Printk (("\n"));
return ret;
}
+
/*
Setup un Symbolic link or a (pseudo) hard link
Return a negative error code or 0 if ok.
@@ -456,11 +467,13 @@ static int umsdos_symlink_x(
if (ret == 0){
int len = strlen(symname);
struct file filp;
- filp.f_pos = 0;
+ loff_t myofs=0;
+ fill_new_filp (&filp, dentry);
+
/* Make the inode acceptable to MSDOS FIXME */
Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
- ret = umsdos_file_write_kmem (dentry->d_inode, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast...
- PTW dentry->d_inode is "less incorrect" */
+ Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
+ ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs);
/* dput(dentry); ?? where did this come from FIXME */
if (ret >= 0){
if (ret != len){
@@ -480,6 +493,7 @@ static int umsdos_symlink_x(
Printk (("\n"));
return ret;
}
+
/*
Setup un Symbolic link.
Return a negative error code or 0 if ok.
@@ -492,6 +506,7 @@ int UMSDOS_symlink(
{
return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0);
}
+
/*
Add a link to an inode in a directory
*/
@@ -671,6 +686,9 @@ int UMSDOS_link (
Printk (("umsdos_link %d\n",ret));
return ret;
}
+
+
+
/*
Add a new file into the alternate directory.
The file is added to the real MSDOS directory. If successful, it
@@ -680,13 +698,16 @@ int UMSDOS_link (
*/
int UMSDOS_create (
struct inode *dir,
- struct dentry *dentry, /* Length of the name */
+ struct dentry *dentry,
int mode /* Permission bit + file type ??? */
) /* Will hold the inode of the newly created */
/* file */
{
return umsdos_create_any (dir,dentry,mode,0,0);
}
+
+
+
/*
Add a sub-directory in a directory
*/
@@ -735,7 +756,7 @@ int UMSDOS_mkdir(
ret = compat_umsdos_real_lookup (dir,info.fake.fname,
info.fake.len,&subdir);
if (ret == 0){
- struct inode *result;
+/* struct inode *result; FIXME /mn/ hmmm what is this supposed to be ? */
struct dentry *tdentry;
tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
@@ -753,9 +774,10 @@ int UMSDOS_mkdir(
}
}
Printk (("umsdos_mkdir %d\n",ret));
- dput (dentry);
+/* dput (dentry); FIXME /mn/ */
return ret;
}
+
/*
Add a new device special file into a directory.
*/
@@ -779,8 +801,9 @@ int UMSDOS_mknod(
for ordinary files was causing major trouble with hard link
in particular and other parts of the kernel I guess.
*/
+
int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
- dput(dentry);
+/* dput(dentry); /mn/ FIXME! */
return ret;
}
@@ -952,13 +975,20 @@ int UMSDOS_unlink (
struct inode * dir,
struct dentry *dentry)
{
- int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+ int ret;
+ Printk ((" *** UMSDOS_unlink entering /mn/ *** \n"));
+
+ ret = umsdos_nevercreat(dir,dentry,-EPERM);
+
+ Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret));
+
if (ret == 0){
struct umsdos_info info;
ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
if (ret == 0){
umsdos_lockcreate(dir);
ret = umsdos_findentry(dir,&info,1);
+ Printk (("UMSDOS_unlink: findentry returned %d\n", ret));
if (ret == 0){
Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname));
/* check sticky bit */
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 38baba6ca..3ed550742 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -39,7 +39,8 @@ static int umsdos_readlink_x (
int ret;
loff_t loffs = 0;
struct file filp;
-
+
+ fill_new_filp (&filp, NULL);
ret = dentry->d_inode->i_size;
diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h
index ab9b28f6e..333e5caeb 100644
--- a/include/asm-alpha/fpu.h
+++ b/include/asm-alpha/fpu.h
@@ -37,21 +37,21 @@
* compatibly. The corresponding definitions are in
* /usr/include/machine/fpu.h under OSF/1.
*/
-#define IEEE_TRAP_ENABLE_INV (1<<1) /* invalid op */
-#define IEEE_TRAP_ENABLE_DZE (1<<2) /* division by zero */
-#define IEEE_TRAP_ENABLE_OVF (1<<3) /* overflow */
-#define IEEE_TRAP_ENABLE_UNF (1<<4) /* underflow */
-#define IEEE_TRAP_ENABLE_INE (1<<5) /* inexact */
+#define IEEE_TRAP_ENABLE_INV (1UL<<1) /* invalid op */
+#define IEEE_TRAP_ENABLE_DZE (1UL<<2) /* division by zero */
+#define IEEE_TRAP_ENABLE_OVF (1UL<<3) /* overflow */
+#define IEEE_TRAP_ENABLE_UNF (1UL<<4) /* underflow */
+#define IEEE_TRAP_ENABLE_INE (1UL<<5) /* inexact */
#define IEEE_TRAP_ENABLE_MASK (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\
IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\
IEEE_TRAP_ENABLE_INE)
/* status bits coming from fpcr: */
-#define IEEE_STATUS_INV (1<<17)
-#define IEEE_STATUS_DZE (1<<18)
-#define IEEE_STATUS_OVF (1<<19)
-#define IEEE_STATUS_UNF (1<<20)
-#define IEEE_STATUS_INE (1<<21)
+#define IEEE_STATUS_INV (1UL<<17)
+#define IEEE_STATUS_DZE (1UL<<18)
+#define IEEE_STATUS_OVF (1UL<<19)
+#define IEEE_STATUS_UNF (1UL<<20)
+#define IEEE_STATUS_INE (1UL<<21)
#define IEEE_STATUS_MASK (IEEE_STATUS_INV | IEEE_STATUS_DZE | \
IEEE_STATUS_OVF | IEEE_STATUS_UNF | \
@@ -64,7 +64,7 @@
#define IEEE_INHERIT (1UL<<63) /* inherit on thread create? */
/*
- * Convert the spftware IEEE trap enable and status bits into the
+ * Convert the software IEEE trap enable and status bits into the
* hardware fpcr format.
*/
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 4744df9c8..5889ec880 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -1,12 +1,15 @@
#ifndef _I386_PAGE_H
#define _I386_PAGE_H
+#include <linux/config.h>
+
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
#define STRICT_MM_TYPECHECKS
@@ -52,12 +55,14 @@ typedef unsigned long pgprot_t;
#define __pgprot(x) (x)
#endif
+#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* This handles the memory map.. */
-#define PAGE_OFFSET 0xC0000000
+#define __PAGE_OFFSET ((0x1000-CONFIG_MAX_MEMSIZE)<<20)
+#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index fe0864913..47e1d2cfc 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -13,6 +13,7 @@
* the i386 page table tree.
*/
+#ifndef __ASSEMBLY__
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
@@ -155,6 +156,7 @@ static inline void flush_tlb_range(struct mm_struct *mm,
}
#endif
#endif
+#endif /* !__ASSEMBLY__ */
/* Certain architectures need to do special things when pte's
@@ -181,6 +183,16 @@ static inline void flush_tlb_range(struct mm_struct *mm,
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 1024
+/*
+ * pgd entries used up by user/kernel:
+ */
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+#define __USER_PGD_PTRS ((__PAGE_OFFSET >> PGDIR_SHIFT) & 0x3ff)
+#define __KERNEL_PGD_PTRS (PTRS_PER_PGD-__USER_PGD_PTRS)
+
+#ifndef __ASSEMBLY__
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
@@ -497,4 +509,6 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
#define module_map vmalloc
#define module_unmap vfree
+#endif /* !__ASSEMBLY__ */
+
#endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 778466bbe..fc62069a5 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -10,6 +10,7 @@
#include <asm/vm86.h>
#include <asm/math_emu.h>
#include <asm/segment.h>
+#include <asm/page.h>
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
@@ -71,10 +72,9 @@ extern unsigned int machine_submodel_id;
extern unsigned int BIOS_revision;
/*
- * User space process size: 3GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
+ * User space process size: 3GB (default).
*/
-#define TASK_SIZE (0xC0000000UL)
+#define TASK_SIZE (PAGE_OFFSET)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index ef08ac510..9da2fff06 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -5,6 +5,7 @@
* User space memory access functions
*/
#include <linux/sched.h>
+#include <asm/page.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -21,7 +22,7 @@
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
-#define USER_DS MAKE_MM_SEG(0xC0000000)
+#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
diff --git a/include/linux/coda.h b/include/linux/coda.h
index 3faa2e9ca..5c3cb563e 100644
--- a/include/linux/coda.h
+++ b/include/linux/coda.h
@@ -587,9 +587,9 @@ struct cfs_open_by_path_out {
};
/*
- * Occasionally, don't cache the fid returned by CFS_LOOKUP. For instance, if
- * the fid is inconsistent. This case is handled by setting the top bit of the
- * return result parameter.
+ * Occasionally, we don't cache the fid returned by CFS_LOOKUP.
+ * For instance, if the fid is inconsistent.
+ * This case is handled by setting the top bit of the type result parameter.
*/
#define CFS_NOCACHE 0x80000000
diff --git a/include/linux/coda_cache.h b/include/linux/coda_cache.h
index 44251867f..fc607fdba 100644
--- a/include/linux/coda_cache.h
+++ b/include/linux/coda_cache.h
@@ -21,19 +21,16 @@ struct coda_cache {
struct coda_cred cc_cred;
};
-void coda_ccinsert(struct coda_cache *el, struct super_block *sb);
-void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp);
-void coda_ccremove(struct coda_cache *el);
-void coda_cnremove(struct coda_cache *el);
-void coda_cache_create(struct inode *inode, int mask);
-struct coda_cache *coda_cache_find(struct inode *inode);
+/* credential cache */
void coda_cache_enter(struct inode *inode, int mask);
-void coda_cache_clear_cnp(struct coda_inode_info *cnp);
+void coda_cache_clear_inode(struct inode *);
void coda_cache_clear_all(struct super_block *sb);
void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred);
int coda_cache_check(struct inode *inode, int mask);
-void coda_dentry_delete(struct dentry *dentry);
-void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag);
+
+/* for downcalls and attributes and lookups */
+void coda_flag_inode(struct inode *inode, int flag);
+void coda_flag_alias_children(struct inode *inode, int flag);
/*
diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
index 1277445b9..d312013d5 100644
--- a/include/linux/coda_fs_i.h
+++ b/include/linux/coda_fs_i.h
@@ -17,7 +17,7 @@
#define CODA_CNODE_MAGIC 0x47114711
/*
- * smb fs inode data (in memory only)
+ * coda fs inode data
*/
struct coda_inode_info {
struct ViceFid c_fid; /* Coda identifier */
@@ -36,7 +36,7 @@ struct coda_inode_info {
#define C_VATTR 0x1 /* Validity of vattr in the cnode */
#define C_SYMLINK 0x2 /* Validity of symlink pointer in the cnode */
#define C_DYING 0x4 /* Set for outstanding cnodes from venus (which died) */
-#define C_ZAPFID 0x8
+#define C_PURGE 0x8
#define C_ZAPDIR 0x10
#define C_INITED 0x20
@@ -44,9 +44,6 @@ int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
-/* inode to cnode */
-#define ITOC(inode) ((struct coda_inode_info *)&((inode)->u.coda_i))
-
#endif
#endif
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index fa477cb52..9dd30eaeb 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -36,6 +36,7 @@ extern struct file_operations coda_ioctl_operations;
int coda_open(struct inode *i, struct file *f);
int coda_release(struct inode *i, struct file *f);
int coda_permission(struct inode *inode, int mask);
+int coda_revalidate_inode(struct dentry *);
/* global variables */
extern int coda_debug;
@@ -43,10 +44,13 @@ extern int coda_print_entry;
extern int coda_access_cache;
/* this file: heloers */
+static __inline__ struct ViceFid *coda_i2f(struct inode *);
char *coda_f2s(ViceFid *f);
int coda_isroot(struct inode *i);
int coda_fid_is_volroot(struct ViceFid *);
int coda_iscontrol(const char *name, size_t length);
+
+
void coda_load_creds(struct coda_cred *cred);
int coda_mycred(struct coda_cred *);
void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
@@ -112,4 +116,18 @@ do { \
#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0)
+/* inode to cnode */
+
+static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
+{
+ return &(inode->u.coda_i.c_fid);
+}
+
+#define ITOC(inode) (&((inode)->u.coda_i))
+
+
+
+
+
+
#endif
diff --git a/include/linux/file.h b/include/linux/file.h
index 3f3870b9e..240a5039c 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -1,19 +1,41 @@
+/*
+ * Wrapper functions for accessing the file_struct fd array.
+ */
+
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
-extern inline struct file * fget(unsigned long fd)
+extern int __fput(struct file *);
+extern void insert_file_free(struct file *file);
+
+/*
+ * Check whether the specified fd has an open file.
+ */
+extern inline struct file * fcheck(unsigned int fd)
{
struct file * file = NULL;
- if (fd < NR_OPEN) {
+
+ if (fd < NR_OPEN)
file = current->files->fd[fd];
- if (file)
- file->f_count++;
- }
return file;
}
-extern int __fput(struct file *);
-extern void insert_file_free(struct file *file);
+extern inline struct file * fget(unsigned int fd)
+{
+ struct file * file = fcheck(fd);
+
+ if (file)
+ file->f_count++;
+ return file;
+}
+
+/*
+ * Install a file pointer in the fd array.
+ */
+extern inline void fd_install(unsigned int fd, struct file *file)
+{
+ current->files->fd[fd] = file;
+}
/* It does not matter which list it is on. */
extern inline void remove_filp(struct file *file)
@@ -47,12 +69,4 @@ extern inline void put_filp(struct file *file)
}
}
-/*
- * Install a file pointer in the files structure.
- */
-extern inline void fd_install(unsigned long fd, struct file *file)
-{
- current->files->fd[fd] = file;
-}
-
#endif
diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h
index de51db0b1..9b43579c0 100644
--- a/include/linux/hfs_fs.h
+++ b/include/linux/hfs_fs.h
@@ -237,20 +237,20 @@ extern const struct hfs_name hfs_cap_reserved2[];
extern struct inode_operations hfs_cap_ndir_inode_operations;
extern struct inode_operations hfs_cap_fdir_inode_operations;
extern struct inode_operations hfs_cap_rdir_inode_operations;
-extern void hfs_cap_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_cap_drop_dentry(struct dentry *, const ino_t);
/* dir_dbl.c */
extern const struct hfs_name hfs_dbl_reserved1[];
extern const struct hfs_name hfs_dbl_reserved2[];
extern struct inode_operations hfs_dbl_dir_inode_operations;
-extern void hfs_dbl_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t);
/* dir_nat.c */
extern const struct hfs_name hfs_nat_reserved1[];
extern const struct hfs_name hfs_nat_reserved2[];
extern struct inode_operations hfs_nat_ndir_inode_operations;
extern struct inode_operations hfs_nat_hdir_inode_operations;
-extern void hfs_nat_drop_dentry(const ino_t, struct dentry *);
+extern void hfs_nat_drop_dentry(struct dentry *, const ino_t);
/* dir_sngl.c */
extern const struct hfs_name hfs_sngl_reserved1[];
diff --git a/include/linux/hfs_fs_i.h b/include/linux/hfs_fs_i.h
index cf9ed53e0..453896882 100644
--- a/include/linux/hfs_fs_i.h
+++ b/include/linux/hfs_fs_i.h
@@ -34,7 +34,7 @@ struct hfs_inode_info {
struct hfs_hdr_layout *layout;
/* for dentry cleanup */
- void (*d_drop_op)(const ino_t, struct dentry *);
+ void (*d_drop_op)(struct dentry *, const ino_t);
};
#endif
diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h
index 93de05aad..22e2ac66b 100644
--- a/include/linux/hfs_sysdep.h
+++ b/include/linux/hfs_sysdep.h
@@ -78,6 +78,10 @@ extern inline hfs_u32 hfs_time(void) {
*/
typedef struct wait_queue *hfs_wait_queue;
+extern inline void hfs_init_waitqueue(hfs_wait_queue *queue) {
+ init_waitqueue(queue);
+}
+
extern inline void hfs_sleep_on(hfs_wait_queue *queue) {
sleep_on(queue);
}
diff --git a/include/linux/kerneld.h b/include/linux/kerneld.h
deleted file mode 100644
index b2db5f8c7..000000000
--- a/include/linux/kerneld.h
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef _LINUX_KERNELD_H
-#define _LINUX_KERNELD_H
-
-#define KERNELD_SYSTEM 1
-#define KERNELD_REQUEST_MODULE 2 /* "insmod" */
-#define KERNELD_RELEASE_MODULE 3 /* "rmmod" */
-#define KERNELD_DELAYED_RELEASE_MODULE 4 /* "rmmod" */
-#define KERNELD_CANCEL_RELEASE_MODULE 5 /* "rmmod" */
-#define KERNELD_REQUEST_ROUTE 6 /* from net/ipv4/route.c */
-#define KERNELD_BLANKER 7 /* from drivers/char/console.c */
-#define KERNELD_PNP 8 /* from drivers/pnp/kerneld.c */
-#define KERNELD_ARP 256 /* from net/ipv4/arp.c */
-
-/*
- * Uncomment the following line for the new kerneld protocol
- * This includes the pid of the kernel level requester into the kerneld header
- */
-/*
-#define NEW_KERNELD_PROTOCOL
- */
-#ifdef NEW_KERNELD_PROTOCOL
-#define OLDIPC_KERNELD 00040000 /* use the kerneld message channel */
-#define IPC_KERNELD 00140000 /* use the kerneld message channel, new protocol */
-#define KDHDR (sizeof(long) + sizeof(short) + sizeof(short))
-#define NULL_KDHDR 0, 2, 0
-#else
-#define IPC_KERNELD 00040000 /* use the kerneld message channel */
-#define KDHDR (sizeof(long))
-#define NULL_KDHDR 0
-#endif
-#define KERNELD_MAXCMD 0x7ffeffff
-#define KERNELD_MINSEQ 0x7fff0000 /* "commands" legal up to 0x7ffeffff */
-#define KERNELD_WAIT 0x80000000
-#define KERNELD_NOWAIT 0
-
-struct kerneld_msg {
- long mtype;
- long id;
-#ifdef NEW_KERNELD_PROTOCOL
- short version;
- short pid;
-#endif
-#ifdef __KERNEL__
- char *text;
-#else
- char text[1];
-#endif /* __KERNEL__ */
-};
-
-#ifdef __KERNEL__
-#include <linux/string.h>
-
-extern int kerneld_send(int msgtype, int ret_size, int msgsz,
- const char *text, const char *ret_val);
-
-/*
- * Request that a module should be loaded.
- * Wait for the exit status from insmod/modprobe.
- * If it fails, it fails... at least we tried...
- */
-static inline int request_module(const char *name)
-{
- return kerneld_send(KERNELD_REQUEST_MODULE,
- 0 | KERNELD_WAIT,
- strlen(name), name, NULL);
-}
-
-/*
- * Request the removal of a module, maybe don't wait for it.
- * It doesn't matter if the removal fails, now does it?
- */
-static inline int release_module(const char *name, int waitflag)
-{
- return kerneld_send(KERNELD_RELEASE_MODULE,
- 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT),
- strlen(name), name, NULL);
-}
-
-/*
- * Request a delayed removal of a module, but don't wait for it.
- * The delay is done by kerneld (default: 60 seconds)
- */
-static inline int delayed_release_module(const char *name)
-{
- return kerneld_send(KERNELD_DELAYED_RELEASE_MODULE,
- 0 | KERNELD_NOWAIT,
- strlen(name), name, NULL);
-}
-
-/*
- * Attempt to cancel a previous request for removal of a module,
- * but don't wait for it.
- * This call can be made if the kernel wants to prevent a delayed
- * unloading of a module.
- */
-static inline int cancel_release_module(const char *name)
-{
- return kerneld_send(KERNELD_CANCEL_RELEASE_MODULE,
- 0 | KERNELD_NOWAIT,
- strlen(name), name, NULL);
-}
-
-/*
- * Perform an "inverted" system call, maybe return the exit status
- */
-static inline int ksystem(const char *cmd, int waitflag)
-{
- return kerneld_send(KERNELD_SYSTEM,
- 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT),
- strlen(cmd), cmd, NULL);
-}
-
-/*
- * Try to create a route, possibly by opening a ppp-connection
- */
-static inline int kerneld_route(const char *ip_route)
-{
- return kerneld_send(KERNELD_REQUEST_ROUTE,
- 0 | KERNELD_WAIT,
- strlen(ip_route), ip_route, NULL);
-}
-
-/*
- * Handle an external screen blanker
- */
-static inline int kerneld_blanker(int on_off)
-{
- char *s = on_off ? "on" : "off";
- return kerneld_send(KERNELD_BLANKER,
- 0 | (on_off ? KERNELD_NOWAIT : KERNELD_WAIT),
- strlen(s), s, NULL);
-}
-
-#endif /* __KERNEL__ */
-#endif
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
new file mode 100644
index 000000000..876c7f222
--- /dev/null
+++ b/include/linux/kmod.h
@@ -0,0 +1,4 @@
+/*
+ kmod header
+*/
+extern int request_module(const char * name);
diff --git a/include/linux/module.h b/include/linux/module.h
index 475c68854..ad3d10baf 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -148,7 +148,7 @@ const char __module_author[] __attribute__((section(".modinfo"))) = \
const char __module_description[] __attribute__((section(".modinfo"))) = \
"description=" desc
-/* Could potentially be used by kerneld... */
+/* Could potentially be used by kmod... */
#define MODULE_SUPPORTED_DEVICE(dev) \
const char __module_device[] __attribute__((section(".modinfo"))) = \
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index 55193867d..b57519b72 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -217,7 +217,7 @@ extern int pim_rcv(struct sk_buff * , unsigned short);
extern int pim_rcv_v1(struct sk_buff * , unsigned short len);
struct rtmsg;
-extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm);
+extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
#endif
#endif
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 03904df71..eb83cfe01 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -83,8 +83,15 @@ struct ncp_privatedata_ioctl
};
#define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request)
-#define NCP_IOC_GETMOUNTUID _IOW('n', 2, uid_t)
-#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int)
+#define NCP_IOC_GETMOUNTUID _IOW('n', 2, __kernel_uid_t)
+
+#if 1
+#ifdef __KERNEL__
+/* remove after ncpfs-2.0.13 gets released or at the beginning of kernel-2.1. codefreeze */
+#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int)
+#endif
+#endif
+
#define NCP_IOC_CONN_LOGGED_IN _IO('n', 3)
#define NCP_GET_FS_INFO_VERSION (1)
diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h
index efcc20556..38492fc92 100644
--- a/include/linux/ncp_fs_sb.h
+++ b/include/linux/ncp_fs_sb.h
@@ -51,11 +51,9 @@ struct ncp_server {
int ncp_reply_size;
struct ncp_inode_info root;
-#if 0
- char root_path; /* '\0' */
-#else
struct dentry* root_dentry;
-#endif
+
+ int root_setuped;
/* info for packet signing */
int sign_wanted; /* 1=Server needs signed packets */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 72430508a..d1c005c70 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -125,6 +125,9 @@ struct net_device_stats
unsigned long tx_heartbeat_errors;
unsigned long tx_window_errors;
+ /* for cslip etc */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
};
#ifdef CONFIG_NET_FASTROUTE
@@ -352,6 +355,7 @@ extern __inline__ int unregister_gifconf(unsigned int family)
#define HAVE_NETIF_RX 1
extern void netif_rx(struct sk_buff *skb);
extern void net_bh(void);
+extern void dev_tint(struct device *dev);
extern int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
extern int dev_ioctl(unsigned int cmd, void *);
extern int dev_change_flags(struct device *, unsigned);
@@ -423,7 +427,7 @@ extern int dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
extern void dev_mc_discard(struct device *dev);
extern void dev_set_promiscuity(struct device *dev, int inc);
extern void dev_set_allmulti(struct device *dev, int inc);
-/* Load a device via the kerneld */
+/* Load a device via the kmod */
extern void dev_load(const char *name);
extern void dev_mcast_init(void);
extern int netdev_register_fc(struct device *dev, void (*stimul)(struct device *dev));
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index a7b51b977..b72ad4ed1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -85,6 +85,9 @@ do { \
*/
#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
+/* Flags in the RPC client structure */
+#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
+
#ifdef __KERNEL__
/*
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 4a309eb91..8c6467010 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -66,7 +66,7 @@ struct rtattr
#define RTA_ALIGNTO 4
#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
-#define RTA_OK(rta,len) ((rta)->rta_len > sizeof(struct rtattr) && \
+#define RTA_OK(rta,len) ((rta)->rta_len >= sizeof(struct rtattr) && \
(rta)->rta_len <= (len))
#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 096d0656c..7eae346a5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -86,6 +86,12 @@ extern int last_pid;
#define SCHED_FIFO 1
#define SCHED_RR 2
+/*
+ * This is an additional bit set when we want to
+ * yield the CPU for one re-schedule..
+ */
+#define SCHED_YIELD 0x10
+
struct sched_param {
int sched_priority;
};
@@ -113,19 +119,24 @@ extern void trap_init(void);
asmlinkage void schedule(void);
-/* Open file table structure */
+
+/*
+ * Open file table structure
+ */
struct files_struct {
int count;
+ int max_fds;
+ struct file ** fd; /* current fd array */
fd_set close_on_exec;
fd_set open_fds;
- struct file * fd[NR_OPEN];
};
#define INIT_FILES { \
1, \
+ NR_OPEN, \
+ &init_fd_array[0], \
{ { 0, } }, \
- { { 0, } }, \
- { NULL, } \
+ { { 0, } } \
}
struct fs_struct {
@@ -387,43 +398,32 @@ extern __inline__ struct task_struct **get_free_taskslot(void)
/* PID hashing. */
#define PIDHASH_SZ (NR_TASKS >> 2)
extern struct task_struct *pidhash[PIDHASH_SZ];
-extern spinlock_t pidhash_lock;
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
extern __inline__ void hash_pid(struct task_struct *p)
{
struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
- unsigned long flags;
- spin_lock_irqsave(&pidhash_lock, flags);
if((p->pidhash_next = *htable) != NULL)
(*htable)->pidhash_pprev = &p->pidhash_next;
*htable = p;
p->pidhash_pprev = htable;
- spin_unlock_irqrestore(&pidhash_lock, flags);
}
extern __inline__ void unhash_pid(struct task_struct *p)
{
- unsigned long flags;
-
- spin_lock_irqsave(&pidhash_lock, flags);
if(p->pidhash_next)
p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
*p->pidhash_pprev = p->pidhash_next;
- spin_unlock_irqrestore(&pidhash_lock, flags);
}
extern __inline__ struct task_struct *find_task_by_pid(int pid)
{
struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
- unsigned long flags;
- spin_lock_irqsave(&pidhash_lock, flags);
for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
;
- spin_unlock_irqrestore(&pidhash_lock, flags);
return p;
}
@@ -571,19 +571,6 @@ extern void exit_sighand(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.
- */
-extern inline struct file *file_from_fd(const unsigned int fd)
-{
-
- if (fd >= NR_OPEN)
- return NULL;
- /* either valid or null */
- return current->files->fd[fd];
-}
-
/*
* The wait-queues are circular lists, and you have to be *very* sure
* to keep them correct. Use only these two functions to add/remove
@@ -627,11 +614,9 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
write_unlock_irqrestore(&waitqueue_lock, flags);
}
-#define REMOVE_LINKS(p) do { unsigned long flags; \
- write_lock_irqsave(&tasklist_lock, flags); \
+#define REMOVE_LINKS(p) do { \
(p)->next_task->prev_task = (p)->prev_task; \
(p)->prev_task->next_task = (p)->next_task; \
- write_unlock_irqrestore(&tasklist_lock, flags); \
if ((p)->p_osptr) \
(p)->p_osptr->p_ysptr = (p)->p_ysptr; \
if ((p)->p_ysptr) \
@@ -640,13 +625,11 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
(p)->p_pptr->p_cptr = (p)->p_osptr; \
} while (0)
-#define SET_LINKS(p) do { unsigned long flags; \
- write_lock_irqsave(&tasklist_lock, flags); \
+#define SET_LINKS(p) do { \
(p)->next_task = &init_task; \
(p)->prev_task = init_task.prev_task; \
init_task.prev_task->next_task = (p); \
init_task.prev_task = (p); \
- write_unlock_irqrestore(&tasklist_lock, flags); \
(p)->p_ysptr = NULL; \
if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
(p)->p_osptr->p_ysptr = p; \
diff --git a/include/linux/socket.h b/include/linux/socket.h
index e274a3c51..afff2fd5c 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -137,6 +137,7 @@ struct ucred {
#define AF_NETLINK 16
#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
#define AF_PACKET 17 /* Packet family */
+#define AF_ASH 18 /* Ash */
#define AF_MAX 32 /* For now.. */
/* Protocol families, same as address families. */
@@ -160,6 +161,7 @@ struct ucred {
#define PF_NETLINK AF_NETLINK
#define PF_ROUTE AF_ROUTE
#define PF_PACKET AF_PACKET
+#define PF_ASH AF_ASH
#define PF_MAX AF_MAX
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 60fb2d74f..da2b2cdd1 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -30,6 +30,7 @@ struct rpc_portmap {
* The high-level client handle
*/
struct rpc_clnt {
+ unsigned int cl_users; /* number of references */
struct rpc_xprt * cl_xprt; /* transport */
struct rpc_procinfo * cl_procinfo; /* procedure info */
u32 cl_maxproc; /* max procedure number */
@@ -37,7 +38,6 @@ struct rpc_clnt {
char * cl_server; /* server machine name */
char * cl_protname; /* protocol name */
struct rpc_auth * cl_auth; /* authenticator */
- struct rpc_portmap cl_pmap; /* port mapping */
struct rpc_stat * cl_stats; /* statistics */
unsigned int cl_softrtry : 1,/* soft timeouts */
@@ -47,10 +47,11 @@ struct rpc_clnt {
cl_binding : 1,/* doing a getport() */
cl_oneshot : 1,/* dispose after use */
cl_dead : 1;/* abandoned */
+ unsigned int cl_flags; /* misc client flags */
unsigned long cl_hardmax; /* max hard timeout */
+ struct rpc_portmap cl_pmap; /* port mapping */
struct rpc_wait_queue cl_bindwait; /* waiting on getport() */
- unsigned int cl_users; /* number of references */
};
#define cl_timeout cl_xprt->timeout
#define cl_prog cl_pmap.pm_prog
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 4d291146e..494490c32 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -36,10 +36,10 @@ struct swap_info_struct {
extern int nr_swap_pages;
extern int nr_free_pages;
extern atomic_t nr_async_pages;
-extern int min_free_pages;
-extern int free_pages_low;
-extern int free_pages_high;
extern struct inode swapper_inode;
+extern unsigned long page_cache_size;
+extern int buffermem;
+#define BUFFER_MEM ((buffermem >> PAGE_SHIFT) + page_cache_size)
/* Incomplete types for prototype declarations: */
struct task_struct;
diff --git a/include/linux/swapctl.h b/include/linux/swapctl.h
index e71dcd067..cc169d2da 100644
--- a/include/linux/swapctl.h
+++ b/include/linux/swapctl.h
@@ -6,29 +6,18 @@
/* Swap tuning control */
-/* First, enumerate the different reclaim policies */
-enum RCL_POLICY {RCL_ROUND_ROBIN, RCL_BUFF_FIRST, RCL_PERSIST};
-
-typedef struct swap_control_v5
+typedef struct swap_control_v6
{
unsigned int sc_max_page_age;
unsigned int sc_page_advance;
unsigned int sc_page_decline;
unsigned int sc_page_initial_age;
- unsigned int sc_max_buff_age;
- unsigned int sc_buff_advance;
- unsigned int sc_buff_decline;
- unsigned int sc_buff_initial_age;
unsigned int sc_age_cluster_fract;
unsigned int sc_age_cluster_min;
unsigned int sc_pageout_weight;
unsigned int sc_bufferout_weight;
- unsigned int sc_buffer_grace;
- unsigned int sc_nr_buffs_to_free;
- unsigned int sc_nr_pages_to_free;
- enum RCL_POLICY sc_policy;
-} swap_control_v5;
-typedef struct swap_control_v5 swap_control_t;
+} swap_control_v6;
+typedef struct swap_control_v6 swap_control_t;
extern swap_control_t swap_control;
typedef struct swapstat_v1
@@ -42,7 +31,23 @@ typedef struct swapstat_v1
typedef swapstat_v1 swapstat_t;
extern swapstat_t swapstats;
-extern int min_free_pages, free_pages_low, free_pages_high;
+typedef struct buffer_mem_v1
+{
+ unsigned int min_percent;
+ unsigned int borrow_percent;
+ unsigned int max_percent;
+} buffer_mem_v1;
+typedef buffer_mem_v1 buffer_mem_t;
+extern buffer_mem_t buffer_mem;
+
+typedef struct freepages_v1
+{
+ unsigned int min;
+ unsigned int low;
+ unsigned int high;
+} freepages_v1;
+typedef freepages_v1 freepages_t;
+extern freepages_t freepages;
#define SC_VERSION 1
#define SC_MAX_VERSION 1
@@ -55,17 +60,11 @@ extern int min_free_pages, free_pages_low, free_pages_high;
failure to free a resource at any priority */
#define RCL_FAILURE (RCL_MAXPRI + 1)
-#define RCL_POLICY (swap_control.sc_policy)
#define AGE_CLUSTER_FRACT (swap_control.sc_age_cluster_fract)
#define AGE_CLUSTER_MIN (swap_control.sc_age_cluster_min)
#define PAGEOUT_WEIGHT (swap_control.sc_pageout_weight)
#define BUFFEROUT_WEIGHT (swap_control.sc_bufferout_weight)
-#define NR_BUFFS_TO_FREE (swap_control.sc_nr_buffs_to_free)
-#define NR_PAGES_TO_FREE (swap_control.sc_nr_pages_to_free)
-
-#define BUFFERMEM_GRACE (swap_control.sc_buffer_grace)
-
/* Page aging (see mm/swap.c) */
#define MAX_PAGE_AGE (swap_control.sc_max_page_age)
@@ -73,11 +72,6 @@ extern int min_free_pages, free_pages_low, free_pages_high;
#define PAGE_DECLINE (swap_control.sc_page_decline)
#define PAGE_INITIAL_AGE (swap_control.sc_page_initial_age)
-#define MAX_BUFF_AGE (swap_control.sc_max_buff_age)
-#define BUFF_ADVANCE (swap_control.sc_buff_advance)
-#define BUFF_DECLINE (swap_control.sc_buff_decline)
-#define BUFF_INITIAL_AGE (swap_control.sc_buff_initial_age)
-
/* Given a resource of N units (pages or buffers etc), we only try to
* age and reclaim AGE_CLUSTER_FRACT per 1024 resources each time we
* scan the resource list. */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 865bdd1dd..b7550ba2c 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -70,7 +70,9 @@ enum
KERN_PRINTK, /* sturct: control printk logging parameters */
KERN_NAMETRANS, /* Name translation */
KERN_STATINODE,
- KERN_DENTRY /* dentry statistics */
+ KERN_DENTRY, /* dentry statistics */
+ KERN_MODPROBE,
+ KERN_KMOD_UNLOAD_DELAY
};
@@ -82,6 +84,7 @@ enum
VM_FREEPG, /* struct: Set free page thresholds */
VM_BDFLUSH, /* struct: Control buffer cache flushing */
VM_OVERCOMMIT_MEMORY, /* Turn off the virtual memory safety limit */
+ VM_BUFFERMEM /* struct: Set cache memory thresholds */
};
@@ -118,6 +121,7 @@ enum
NET_CORE_FASTROUTE,
NET_CORE_MSG_COST,
NET_CORE_MSG_BURST,
+ NET_CORE_OPTMEM_MAX,
};
/* /proc/sys/net/ethernet */
@@ -145,8 +149,6 @@ enum
NET_IPV4_FIB_HASH = 19,
NET_IPV4_TCP_HOE_RETRANSMITS=32,
- NET_IPV4_TCP_SACK,
- NET_IPV4_TCP_TSACK,
NET_IPV4_TCP_TIMESTAMPS,
NET_IPV4_TCP_WINDOW_SCALING,
NET_IPV4_TCP_VEGAS_CONG_AVOID,
@@ -167,6 +169,7 @@ enum
NET_IPV4_IP_MASQ_DEBUG,
NET_TCP_SYNCOOKIES,
NET_TCP_STDURG,
+ NET_TCP_RFC1337,
NET_TCP_SYN_TAILDROP,
NET_TCP_MAX_SYN_BACKLOG,
NET_IPV4_LOCAL_PORT_RANGE,
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6b00c4329..34c88d721 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -320,8 +320,7 @@ extern int espserial_init(void);
extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
const char *routine);
-extern char *_tty_name(struct tty_struct *tty, char *buf);
-extern char *tty_name(struct tty_struct *tty);
+extern char *tty_name(struct tty_struct *tty, char *buf);
extern void tty_wait_until_sent(struct tty_struct * tty, int timeout);
extern int tty_check_change(struct tty_struct * tty);
extern void stop_tty(struct tty_struct * tty);
diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p
index 62ce67d0c..7c0e64ec3 100644
--- a/include/linux/umsdos_fs.p
+++ b/include/linux/umsdos_fs.p
@@ -1,9 +1,6 @@
/* check.c 23/01/95 03.38.30 */
void check_page_tables (void);
/* dir.c 22/06/95 00.22.12 */
-struct dentry *creat_dentry (const char *name,
- const int len,
- struct inode *inode);
int compat_msdos_create(struct inode *dir,
const char *name,
int len,
@@ -30,6 +27,16 @@ int UMSDOS_lookup(struct inode *dir,struct dentry *dentry);
int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
/* emd.c 22/06/95 00.22.04 */
+void fill_new_filp (struct file *filp, struct dentry *dentry);
+void kill_dentry (struct dentry *dentry);
+struct dentry *creat_dentry (const char *name,
+ const int len,
+ struct inode *inode);
+ssize_t umsdos_file_write_kmem_real (struct file *filp,
+ const char *buf,
+ size_t count,
+ loff_t *offs);
+
ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
struct file *filp,
char *buf,
diff --git a/include/net/dst.h b/include/net/dst.h
index b879bb059..0d18f60d2 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -120,6 +120,8 @@ extern void dst_destroy(struct dst_entry * dst);
extern __inline__
void dst_free(struct dst_entry * dst)
{
+ if (dst->obsolete > 1)
+ return;
if (!atomic_read(&dst->use)) {
dst_destroy(dst);
return;
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 42233aadf..863037b23 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -114,7 +114,7 @@ extern __inline__ void ip6_dst_store(struct sock *sk, struct dst_entry *dst)
struct rt6_info *rt;
np = &sk->net_pinfo.af_inet6;
- sk->dst_cache = dst;
+ dst_release(xchg(&sk->dst_cache,dst));
rt = (struct rt6_info *) dst;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index b6055ae44..1a322a498 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -4,7 +4,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ipv6.h,v 1.8 1997/12/29 19:52:09 kuznet Exp $
+ * $Id: ipv6.h,v 1.9 1998/03/08 05:55:20 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/include/net/route.h b/include/net/route.h
index 338e158fd..624fd233a 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -102,6 +102,7 @@ extern unsigned inet_addr_type(u32 addr);
extern void ip_rt_multicast_event(struct in_device *);
extern int ip_rt_ioctl(unsigned int cmd, void *arg);
extern void ip_rt_get_source(u8 *src, struct rtable *rt);
+extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb);
extern __inline__ void ip_rt_put(struct rtable * rt)
diff --git a/include/net/sock.h b/include/net/sock.h
index c225a0015..589f58c7c 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -191,42 +191,75 @@ struct raw_opt {
struct tcp_opt
{
+ int tcp_header_len; /* Bytes of tcp header to send */
+
+/*
+ * Header prediction flags
+ * 0x5?10 << 16 + snd_wnd in net byte order
+ */
+ __u32 pred_flags;
+
/*
* RFC793 variables by their proper names. This means you can
* read the code and the spec side by side (and laugh ...)
* See RFC793 and RFC1122. The RFC writes these in capitals.
*/
__u32 rcv_nxt; /* What we want to receive next */
- __u32 rcv_up; /* The urgent point (may not be valid) */
- __u32 rcv_wnd; /* Current receiver window */
__u32 snd_nxt; /* Next sequence we send */
+
__u32 snd_una; /* First byte we want an ack for */
- __u32 snd_up; /* Outgoing urgent pointer */
- __u32 snd_wl1; /* Sequence for window update */
- __u32 snd_wl2; /* Ack sequence for update */
+ __u32 rcv_tstamp; /* timestamp of last received packet */
+ __u32 lrcvtime; /* timestamp of last received data packet*/
+ __u32 srtt; /* smothed round trip time << 3 */
- __u32 rcv_wup; /* rcv_nxt on last window update sent */
+ __u32 ato; /* delayed ack timeout */
+ __u32 snd_wl1; /* Sequence for window update */
- __u32 fin_seq; /* XXX This one should go, we don't need it. -DaveM */
+ __u32 snd_wl2; /* Ack sequence for update */
+ __u32 snd_wnd; /* The window we expect to receive */
+ __u32 max_window;
+ __u8 pending; /* pending events */
+ __u8 retransmits;
+ __u32 last_ack_sent; /* last ack we sent */
- __u32 srtt; /* smothed round trip time << 3 */
+ __u32 backoff; /* backoff */
__u32 mdev; /* medium deviation */
+ __u32 snd_cwnd; /* Sending congestion window */
__u32 rto; /* retransmit timeout */
- __u32 backoff; /* backoff */
+
+ __u32 packets_out; /* Packets which are "in flight" */
+ __u32 high_seq; /* highest sequence number sent by onset of congestion */
/*
* Slow start and congestion control (see also Nagle, and Karn & Partridge)
*/
- __u32 snd_cwnd; /* Sending congestion window */
__u32 snd_ssthresh; /* Slow start size threshold */
__u16 snd_cwnd_cnt;
- __u16 max_window;
+ __u8 dup_acks; /* Consequetive duplicate acks seen from other end */
+ __u8 delayed_acks;
+
+ /* Two commonly used timers in both sender and receiver paths. */
+ struct timer_list retransmit_timer; /* Resend (no ack) */
+ struct timer_list delack_timer; /* Ack delay */
+
+ struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
+ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */
+ struct sk_buff *send_head; /* Front of stuff to transmit */
+ struct sk_buff *retrans_head; /* retrans head can be
+ * different to the head of
+ * write queue if we are doing
+ * fast retransmit
+ */
+
+ __u32 rcv_wnd; /* Current receiver window */
+ __u32 rcv_wup; /* rcv_nxt on last window update sent */
+ __u32 write_seq;
+ __u32 copied_seq;
/*
* Options received (usually on last packet, some only on SYN packets).
*/
char tstamp_ok, /* TIMESTAMP seen on SYN packet */
- wscale_ok, /* Wscale seen on SYN packet */
- sack_ok; /* SACK_PERM seen on SYN packet */
+ wscale_ok; /* Wscale seen on SYN packet */
char saw_tstamp; /* Saw TIMESTAMP on last packet */
__u16 in_mss; /* MSS option received from sender */
__u8 snd_wscale; /* Window scaling received from sender */
@@ -235,60 +268,20 @@ struct tcp_opt
__u32 rcv_tsecr; /* Time stamp echo reply */
__u32 ts_recent; /* Time stamp to echo next */
__u32 ts_recent_stamp;/* Time we stored ts_recent (for aging) */
- __u32 last_ack_sent; /* last ack we sent */
- int sacks; /* Number of SACK blocks if any */
- __u32 left_sack[4]; /* Left edges of blocks */
- __u32 right_sack[4]; /* Right edges of blocks */
- int tcp_header_len; /* Bytes of tcp header to send */
-/*
- * Timers used by the TCP protocol layer
- */
- struct timer_list delack_timer; /* Ack delay */
- struct timer_list idle_timer; /* Idle watch */
- struct timer_list completion_timer; /* Up/Down timer */
struct timer_list probe_timer; /* Probes */
- struct timer_list retransmit_timer; /* Resend (no ack) */
-
- __u32 basertt; /* Vegas baseRTT */
- __u32 packets_out; /* Packets which are "in flight" */
- __u32 window_clamp; /* XXX Document this... -DaveM */
-
- __u8 pending; /* pending events */
- __u8 delayed_acks;
- __u8 dup_acks; /* Consequetive duplicate acks seen from other end */
- __u8 retransmits;
-
- __u32 lrcvtime; /* timestamp of last received data packet */
- __u32 rcv_tstamp; /* timestamp of last received packet */
- __u32 iat_mdev; /* interarrival time medium deviation */
- __u32 iat; /* interarrival time */
- __u32 ato; /* delayed ack timeout */
- __u32 high_seq; /* highest sequence number sent by onset of congestion */
-
-/*
- * new send pointers
- */
- struct sk_buff * send_head;
- struct sk_buff * retrans_head; /* retrans head can be
- * different to the head of
- * write queue if we are doing
- * fast retransmit
- */
-/*
- * Header prediction flags
- * 0x5?10 << 16 + snd_wnd in net byte order
- */
- __u32 pred_flags;
- __u32 snd_wnd; /* The window we expect to receive */
-
- __u32 probes_out; /* unanswered 0 window probes */
+ __u32 basertt; /* Vegas baseRTT */
+ __u32 window_clamp; /* XXX Document this... -DaveM */
+ __u32 probes_out; /* unanswered 0 window probes */
+ __u32 syn_seq;
+ __u32 fin_seq;
+ __u32 urg_seq;
+ __u32 urg_data;
struct open_request *syn_wait_queue;
struct open_request **syn_wait_last;
int syn_backlog;
- struct tcp_func *af_specific;
};
@@ -347,73 +340,73 @@ struct sock
struct sock *sklist_next;
struct sock *sklist_prev;
- atomic_t wmem_alloc;
- atomic_t rmem_alloc;
- unsigned long allocation; /* Allocation mode */
+ /* Local port binding hash linkage. */
+ struct sock *bind_next;
+ struct sock **bind_pprev;
+
+ /* Main hash linkage for various protocol lookup tables. */
+ struct sock *next;
+ struct sock **pprev;
- /* The following stuff should probably move to the tcp private area */
- __u32 write_seq;
- __u32 copied_seq;
- __u32 syn_seq;
- __u32 urg_seq;
- __u32 urg_data;
- unsigned char delayed_acks;
- /* End of block to move */
+ /* Socket demultiplex comparisons on incoming packets. */
+ __u32 daddr; /* Foreign IPv4 addr */
+ __u32 rcv_saddr; /* Bound local IPv4 addr */
+ int bound_dev_if; /* Bound device index if != 0 */
+ unsigned short num; /* Local port */
+ volatile unsigned char state, /* Connection state */
+ zapped; /* In ax25 & ipx means not linked */
+ struct tcphdr dummy_th; /* TCP header template */
- int sock_readers; /* user count */
+ int sock_readers; /* user count */
+ int rcvbuf;
+
+ struct wait_queue **sleep;
+ struct dst_entry *dst_cache; /* Destination cache */
+ atomic_t rmem_alloc; /* Receive queue bytes committed */
+ struct sk_buff_head receive_queue; /* Incoming packets */
+ atomic_t wmem_alloc; /* Transmit queue bytes committed */
+ struct sk_buff_head write_queue; /* Packet sending queue */
+ atomic_t omem_alloc; /* "o" is "option" or "other" */
+ __u32 saddr; /* Sending source */
+ unsigned int allocation; /* Allocation mode */
+ int sndbuf;
+ struct sock *prev;
/*
* Not all are volatile, but some are, so we
* might as well say they all are.
*/
volatile char dead,
- urginline,
done,
+ urginline,
reuse,
keepopen,
linger,
destroy,
no_check,
- zapped, /* In ax25 & ipx means not linked */
broadcast,
nonagle,
bsdism;
- int bound_dev_if;
- unsigned long lingertime;
+ unsigned char debug;
int proc;
+ unsigned long lingertime;
- struct sock *next;
- struct sock **pprev;
- struct sock *bind_next;
- struct sock **bind_pprev;
- struct sock *prev;
int hashent;
struct sock *pair;
- struct sk_buff_head back_log;
-
- struct sk_buff_head write_queue,
- receive_queue,
- out_of_order_queue,
+ /* Error and backlog packet queues, rarely used. */
+ struct sk_buff_head back_log,
error_queue;
unsigned short family;
struct proto *prot;
- struct wait_queue **sleep;
-
- __u32 daddr;
- __u32 saddr; /* Sending source */
- __u32 rcv_saddr; /* Bound address */
- struct dst_entry *dst_cache;
/*
* mss is min(mtu, max_window)
*/
unsigned short mtu; /* mss negotiated in the syn's */
unsigned short mss; /* current eff. mss - can change */
unsigned short user_mss; /* mss requested by user in ioctl */
- unsigned short num;
-
unsigned short shutdown;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -436,16 +429,12 @@ struct sock
cause failure but are the cause
of a persistent failure not just
'timed out' */
- unsigned char protocol;
- volatile unsigned char state;
unsigned short ack_backlog;
unsigned short max_ack_backlog;
- unsigned char debug;
__u32 priority;
- int rcvbuf;
- int sndbuf;
unsigned short type;
unsigned char localroute; /* Route locally only */
+ unsigned char protocol;
struct ucred peercred;
#ifdef CONFIG_FILTER
@@ -472,11 +461,6 @@ struct sock
#if defined (CONFIG_PACKET) || defined(CONFIG_PACKET_MODULE)
struct packet_opt *af_packet;
#endif
-#ifdef CONFIG_INET
-#ifdef CONFIG_NUTCP
- struct tcp_opt af_tcp;
-#endif
-#endif
#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
x25_cb *x25;
#endif
@@ -503,7 +487,6 @@ struct sock
int ip_ttl; /* TTL setting */
int ip_tos; /* TOS */
unsigned ip_cmsg_flags;
- struct tcphdr dummy_th;
struct ip_options *opt;
unsigned char ip_hdrincl; /* Include headers ? */
__u8 ip_mc_ttl; /* Multicasting TTL */
@@ -731,7 +714,7 @@ here:
}
/*
- * This might not be the most apropriate place for this two
+ * This might not be the most appropriate place for this two
* but since they are used by a lot of the net related code
* at least they get declared on a include that is common to all
*/
@@ -750,7 +733,7 @@ static __inline__ int max(unsigned int a, unsigned int b)
return a;
}
-extern struct sock * sk_alloc(int family, int priority);
+extern struct sock * sk_alloc(int family, int priority, int zero_it);
extern void sk_free(struct sock *sk);
extern void destroy_sock(struct sock *sk);
@@ -884,7 +867,6 @@ extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
*/
if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
return -ENOMEM;
- skb_set_owner_r(skb, sk);
#ifdef CONFIG_FILTER
if (sk->filter)
@@ -894,7 +876,8 @@ extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
#endif /* CONFIG_FILTER */
- skb_queue_tail(&sk->receive_queue,skb);
+ skb_set_owner_r(skb, sk);
+ skb_queue_tail(&sk->receive_queue, skb);
if (!sk->dead)
sk->data_ready(sk,skb->len);
return 0;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 4c445ca1a..cec01dfe6 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -27,13 +27,13 @@
* New scheme, half the table is for TIME_WAIT, the other half is
* for the rest. I'll experiment with dynamic table growth later.
*/
-#define TCP_HTABLE_SIZE 1024
+#define TCP_HTABLE_SIZE 512
/* This is for listening sockets, thus all sockets which possess wildcards. */
#define TCP_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */
/* This is for all sockets, to keep track of the local port allocations. */
-#define TCP_BHTABLE_SIZE 64
+#define TCP_BHTABLE_SIZE 512
/* tcp_ipv4.c: These need to be shared by v4 and v6 because the lookup
* and hashing code needs to work with different AF's yet
@@ -41,47 +41,153 @@
*/
extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
-extern struct sock *tcp_bound_hash[TCP_BHTABLE_SIZE];
-/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
- * because the v6 tcp code to intialize a connection needs to interoperate
- * with the v4 code using the same variables.
- * FIXME: It would be better to rewrite the connection code to be
- * address family independent and just leave one copy in the ipv4 section.
- * This would also clean up some code duplication. -- erics
+/* There are a few simple rules, which allow for local port reuse by
+ * an application. In essence:
+ *
+ * 1) Sockets bound to different interfaces may share a local port.
+ * Failing that, goto test 2.
+ * 2) If all sockets have sk->reuse set, and none of them are in
+ * TCP_LISTEN state, the port may be shared.
+ * Failing that, goto test 3.
+ * 3) If all sockets are bound to a specific sk->rcv_saddr local
+ * address, and none of them are the same, the port may be
+ * shared.
+ * Failing this, the port cannot be shared.
+ *
+ * The interesting point, is test #2. This is what an FTP server does
+ * all day. To optimize this case we use a specific flag bit defined
+ * below. As we add sockets to a bind bucket list, we perform a
+ * check of: (newsk->reuse && (newsk->state != TCP_LISTEN))
+ * As long as all sockets added to a bind bucket pass this test,
+ * the flag bit will be set.
+ * The resulting situation is that tcp_v[46]_verify_bind() can just check
+ * for this flag bit, if it is set and the socket trying to bind has
+ * sk->reuse set, we don't even have to walk the owners list at all,
+ * we return that it is ok to bind this socket to the requested local port.
+ *
+ * Sounds like a lot of work, but it is worth it. In a more naive
+ * implementation (ie. current FreeBSD etc.) the entire list of ports
+ * must be walked for each data port opened by an ftp server. Needless
+ * to say, this does not scale at all. With a couple thousand FTP
+ * users logged onto your box, isn't it nice to know that new data
+ * ports are created in O(1) time? I thought so. ;-) -DaveM
*/
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_timestamps;
-extern int sysctl_tcp_window_scaling;
+struct tcp_bind_bucket {
+ unsigned short port;
+ unsigned short flags;
+#define TCPB_FLAG_LOCKED 0x0001
+#define TCPB_FLAG_FASTREUSE 0x0002
+
+ struct tcp_bind_bucket *next;
+ struct sock *owners;
+ struct tcp_bind_bucket **pprev;
+};
-/* These are AF independent. */
-static __inline__ int tcp_bhashfn(__u16 lport)
+extern struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+extern kmem_cache_t *tcp_bucket_cachep;
+extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum);
+extern void tcp_bucket_unlock(struct sock *sk);
+extern int tcp_port_rover;
+
+/* Level-1 socket-demux cache. */
+#define TCP_NUM_REGS 32
+extern struct sock *tcp_regs[TCP_NUM_REGS];
+
+#define TCP_RHASH_FN(__fport) \
+ ((((__fport) >> 7) ^ (__fport)) & (TCP_NUM_REGS - 1))
+#define TCP_RHASH(__fport) tcp_regs[TCP_RHASH_FN((__fport))]
+#define TCP_SK_RHASH_FN(__sock) TCP_RHASH_FN((__sock)->dummy_th.dest)
+#define TCP_SK_RHASH(__sock) tcp_regs[TCP_SK_RHASH_FN((__sock))]
+
+static __inline__ void tcp_reg_zap(struct sock *sk)
{
- return (lport ^ (lport >> 7)) & (TCP_BHTABLE_SIZE - 1);
+ struct sock **rpp;
+
+ rpp = &(TCP_SK_RHASH(sk));
+ if(*rpp == sk)
+ *rpp = NULL;
}
-/* Find the next port that hashes h that is larger than lport.
- * If you change the hash, change this function to match, or you will
- * break TCP port selection. This function must also NOT wrap around
- * when the next number exceeds the largest possible port (2^16-1).
- */
-static __inline__ int tcp_bhashnext(__u16 lport, __u16 h)
+/* These are AF independent. */
+static __inline__ int tcp_bhashfn(__u16 lport)
{
- __u32 s; /* don't change this to a smaller type! */
-
- s = (lport ^ (h ^ tcp_bhashfn(lport)));
- if (s > lport)
- return s;
- s = lport + TCP_BHTABLE_SIZE;
- return (s ^ (h ^ tcp_bhashfn(s)));
+ return (lport & (TCP_BHTABLE_SIZE - 1));
}
-static __inline__ int tcp_sk_bhashfn(struct sock *sk)
+static __inline__ void tcp_sk_bindify(struct sock *sk)
{
- __u16 lport = sk->num;
- return tcp_bhashfn(lport);
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
+
+ for(tb = tcp_bound_hash[tcp_bhashfn(snum)]; tb->port != snum; tb = tb->next)
+ ;
+ /* Update bucket flags. */
+ if(tb->owners == NULL) {
+ /* We're the first. */
+ if(sk->reuse && sk->state != TCP_LISTEN)
+ tb->flags = TCPB_FLAG_FASTREUSE;
+ else
+ tb->flags = 0;
+ } else {
+ if((tb->flags & TCPB_FLAG_FASTREUSE) &&
+ ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+ tb->flags &= ~TCPB_FLAG_FASTREUSE;
+ }
+ if((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
}
+/* This is a TIME_WAIT bucket. It works around the memory consumption
+ * problems of sockets in such a state on heavily loaded servers, but
+ * without violating the protocol specification.
+ */
+struct tcp_tw_bucket {
+ /* These _must_ match the beginning of struct sock precisely.
+ * XXX Yes I know this is gross, but I'd have to edit every single
+ * XXX networking file if I created a "struct sock_header". -DaveM
+ */
+ struct sock *sklist_next;
+ struct sock *sklist_prev;
+ struct sock *bind_next;
+ struct sock **bind_pprev;
+ struct sock *next;
+ struct sock **pprev;
+ __u32 daddr;
+ __u32 rcv_saddr;
+ int bound_dev_if;
+ unsigned short num;
+ unsigned char state,
+ family; /* sk->zapped */
+ __u16 source; /* sk->dummy_th.source */
+ __u16 dest; /* sk->dummy_th.dest */
+
+ /* And these are ours. */
+ __u32 rcv_nxt;
+ struct tcp_func *af_specific;
+ struct tcp_bind_bucket *tb;
+ struct timer_list timer;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct in6_addr v6_daddr;
+ struct in6_addr v6_rcv_saddr;
+#endif
+};
+
+extern kmem_cache_t *tcp_timewait_cachep;
+
+/* tcp_ipv4.c: These sysctl variables need to be shared between v4 and v6
+ * because the v6 tcp code to intialize a connection needs to interoperate
+ * with the v4 code using the same variables.
+ * FIXME: It would be better to rewrite the connection code to be
+ * address family independent and just leave one copy in the ipv4 section.
+ * This would also clean up some code duplication. -- erics
+ */
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+
/* These can have wildcards, don't try too hard. */
static __inline__ int tcp_lhashfn(unsigned short num)
{
@@ -93,28 +199,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
return tcp_lhashfn(sk->num);
}
-/* Only those holding the sockhash lock call these two things here.
- * Note the slightly gross overloading of sk->prev, AF_UNIX is the
- * only other main benefactor of that member of SK, so who cares.
- */
-static __inline__ void tcp_sk_bindify(struct sock *sk)
-{
- int hashent = tcp_sk_bhashfn(sk);
- struct sock **htable = &tcp_bound_hash[hashent];
-
- if((sk->bind_next = *htable) != NULL)
- (*htable)->bind_pprev = &sk->bind_next;
- *htable = sk;
- sk->bind_pprev = htable;
-}
-
-static __inline__ void tcp_sk_unbindify(struct sock *sk)
-{
- if(sk->bind_next)
- sk->bind_next->bind_pprev = sk->bind_pprev;
- *(sk->bind_pprev) = sk->bind_next;
-}
-
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#define NETHDR_SIZE sizeof(struct ipv6hdr)
#else
@@ -186,6 +270,8 @@ static __inline__ void tcp_sk_unbindify(struct sock *sk)
* we tell the LL layer that it is something
* wrong (e.g. that it can expire redirects) */
+#define TCP_BUCKETGC_PERIOD (HZ)
+
/*
* TCP option
*/
@@ -193,9 +279,6 @@ static __inline__ void tcp_sk_unbindify(struct sock *sk)
#define TCPOPT_NOP 1 /* Padding */
#define TCPOPT_EOL 0 /* End of options */
#define TCPOPT_MSS 2 /* Segment size negotiating */
-/*
- * We don't use these yet, but they are for PAWS and big windows
- */
#define TCPOPT_WINDOW 3 /* Window scaling */
#define TCPOPT_SACK_PERM 4 /* SACK Permitted */
#define TCPOPT_SACK 5 /* SACK Block */
@@ -210,6 +293,10 @@ static __inline__ void tcp_sk_unbindify(struct sock *sk)
#define TCPOLEN_SACK_PERM 2
#define TCPOLEN_TIMESTAMP 10
+/* But this is what stacks really send out. */
+#define TCPOLEN_TSTAMP_ALIGNED 12
+#define TCPOLEN_WSCALE_ALIGNED 4
+
/*
* TCP option flags for parsed options.
*/
@@ -259,7 +346,6 @@ struct open_request {
__u8 __pad;
unsigned snd_wscale : 4,
rcv_wscale : 4,
- sack_ok : 1,
tstamp_ok : 1,
wscale_ok : 1;
/* The following two fields can be easily recomputed I think -AK */
@@ -355,7 +441,7 @@ extern __inline int after(__u32 seq1, __u32 seq2)
/* is s2<=s1<=s3 ? */
extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
{
- return (after(seq1+1, seq2) && before(seq1, seq3+1));
+ return seq3 - seq2 >= seq1 - seq2;
}
@@ -390,6 +476,11 @@ extern int tcp_rcv_established(struct sock *sk,
struct tcphdr *th,
__u16 len);
+extern int tcp_timewait_state_process(struct tcp_tw_bucket *tw,
+ struct sk_buff *skb,
+ struct tcphdr *th,
+ void *opt, __u16 len);
+
extern void tcp_close(struct sock *sk,
unsigned long timeout);
extern struct sock * tcp_accept(struct sock *sk, int flags);
@@ -427,6 +518,10 @@ extern int tcp_v4_conn_request(struct sock *sk,
struct sk_buff *skb,
void *ptr, __u32 isn);
+extern struct sock * tcp_create_openreq_child(struct sock *sk,
+ struct open_request *req,
+ struct sk_buff *skb);
+
extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk,
struct sk_buff *skb,
struct open_request *req,
@@ -457,10 +552,11 @@ extern void tcp_send_probe0(struct sock *);
extern void tcp_send_partial(struct sock *);
extern void tcp_write_wakeup(struct sock *);
extern void tcp_send_fin(struct sock *sk);
+extern void tcp_send_active_reset(struct sock *sk);
extern int tcp_send_synack(struct sock *);
-extern void tcp_send_skb(struct sock *, struct sk_buff *);
+extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue);
extern void tcp_send_ack(struct sock *sk);
-extern void tcp_send_delayed_ack(struct sock *sk, int max_timeout);
+extern void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout);
/* CONFIG_IP_TRANSPARENT_PROXY */
extern int tcp_chkaddr(struct sk_buff *);
@@ -492,40 +588,94 @@ struct tcp_sl_timer {
#define TCP_SLT_SYNACK 0
#define TCP_SLT_KEEPALIVE 1
-#define TCP_SLT_MAX 2
+#define TCP_SLT_BUCKETGC 2
+#define TCP_SLT_MAX 3
extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX];
-/*
- * FIXME: this method of choosing when to send a window update
- * does not seem correct to me. -- erics
+/* Compute the actual receive window we are currently advertising. */
+static __inline__ u32 tcp_receive_window(struct tcp_opt *tp)
+{
+ return tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+}
+
+/* Choose a new window, without checks for shrinking, and without
+ * scaling applied to the result. The caller does these things
+ * if necessary. This is a "raw" window selection.
*/
-static __inline__ unsigned short tcp_raise_window(struct sock *sk)
+extern u32 __tcp_select_window(struct sock *sk);
+
+/* Chose a new window to advertise, update state in tcp_opt for the
+ * socket, and return result with RFC1323 scaling applied. The return
+ * value can be stuffed directly into th->window for an outgoing
+ * frame.
+ */
+extern __inline__ u16 tcp_select_window(struct sock *sk)
{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- long cur_win;
- int res = 0;
-
- /*
- * compute the actual window i.e.
- * old_window - received_bytes_on_that_win
- */
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 new_win = __tcp_select_window(sk);
+ u32 cur_win = tcp_receive_window(tp);
- cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+ /* Never shrink the offered window */
+ if(new_win < cur_win)
+ new_win = cur_win;
+ tp->rcv_wnd = new_win;
+ tp->rcv_wup = tp->rcv_nxt;
+ /* RFC1323 scaling applied */
+ return new_win >> tp->rcv_wscale;
+}
- /*
- * We need to send an ack right away if
- * our rcv window is blocking the sender and
- * we have more free space to offer.
- */
+/* See if we can advertise non-zero, and if so how much we
+ * can increase our advertisement. If it becomes more than
+ * twice what we are talking about right now, return true.
+ */
+extern __inline__ int tcp_raise_window(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 new_win = __tcp_select_window(sk);
+ u32 cur_win = tcp_receive_window(tp);
- if (cur_win < (sk->mss << 1))
- res = 1;
- return res;
+ return (new_win && (new_win > (cur_win << 1)));
}
-extern unsigned short tcp_select_window(struct sock *sk);
+/* This checks if the data bearing packet SKB (usually tp->send_head)
+ * should be put on the wire right now.
+ */
+static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int nagle_check = 1;
+ int len;
+
+ /* RFC 1122 - section 4.2.3.4
+ *
+ * We must queue if
+ *
+ * a) The right edge of this frame exceeds the window
+ * b) There are packets in flight and we have a small segment
+ * [SWS avoidance and Nagle algorithm]
+ * (part of SWS is done on packetization)
+ * c) We are retransmiting [Nagle]
+ * d) We have too many packets 'in flight'
+ *
+ * Don't use the nagle rule for urgent data.
+ */
+ len = skb->end_seq - skb->seq;
+ if (!sk->nonagle && len < (sk->mss >> 1) && tp->packets_out &&
+ !skb->h.th->urg)
+ nagle_check = 0;
+
+ return (nagle_check && tp->packets_out < tp->snd_cwnd &&
+ !after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
+ tp->retransmits == 0);
+}
+
+/* This tells the input processing path that an ACK should go out
+ * right now.
+ */
+#define tcp_enter_quickack_mode(__tp) ((__tp)->ato = (HZ/100))
+#define tcp_in_quickack_mode(__tp) ((__tp)->ato == (HZ/100))
/*
* List all states of a TCP socket that can be viewed as a "connected"
@@ -581,41 +731,49 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
case TCP_CLOSE:
/* Should be about 2 rtt's */
net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
+ sk->prot->unhash(sk);
/* fall through */
default:
if (oldstate==TCP_ESTABLISHED)
tcp_statistics.TcpCurrEstab--;
- if (state == TCP_TIME_WAIT || state == TCP_CLOSE)
- sk->prot->rehash(sk);
}
}
static __inline__ void tcp_build_options(__u32 *ptr, struct tcp_opt *tp)
{
- /* FIXME: We will still need to do SACK here. */
if (tp->tstamp_ok) {
- *ptr = ntohl((TCPOPT_NOP << 24)
- | (TCPOPT_NOP << 16)
- | (TCPOPT_TIMESTAMP << 8)
- | TCPOLEN_TIMESTAMP);
+ *ptr = __constant_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
/* rest filled in by tcp_update_options */
}
}
static __inline__ void tcp_update_options(__u32 *ptr, struct tcp_opt *tp)
{
- /* FIXME: We will still need to do SACK here. */
if (tp->tstamp_ok) {
*++ptr = htonl(jiffies);
*++ptr = htonl(tp->ts_recent);
}
}
+static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp)
+{
+ if (tp->tstamp_ok) {
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(jiffies);
+ *ptr = htonl(tp->ts_recent);
+ }
+}
+
/*
* This routines builds a generic TCP header.
* They also build the RFC1323 Timestamp, but don't fill the
* actual timestamp in (you need to call tcp_update_options for this).
- * It can't (unfortunately) do SACK as well.
* XXX: pass tp instead of sk here.
*/
@@ -624,23 +782,12 @@ static inline void tcp_build_header_data(struct tcphdr *th, struct sock *sk, int
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
- th->seq = htonl(sk->write_seq);
+ th->seq = htonl(tp->write_seq);
if (!push)
th->psh = 1;
tcp_build_options((__u32*)(th+1), tp);
}
-static inline void tcp_build_header(struct tcphdr *th, struct sock *sk)
-{
- struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-
- memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
- th->seq = htonl(sk->write_seq);
- th->ack_seq = htonl(tp->last_ack_sent = tp->rcv_nxt);
- th->window = htons(tcp_select_window(sk));
- tcp_build_options((__u32 *)(th+1), tp);
-}
-
/*
* Construct a tcp options header for a SYN or SYN_ACK packet.
* If this is every changed make sure to change the definition of
@@ -651,31 +798,32 @@ static inline void tcp_build_header(struct tcphdr *th, struct sock *sk)
* It would be especially magical to compute the checksum for this
* stuff on the fly here.
*/
-extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int sack, int ts, int offer_wscale, int wscale)
+extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int ts, int offer_wscale, int wscale)
{
- int count = 4 + (offer_wscale ? 4 : 0) + ((ts || sack) ? 4 : 0) + (ts ? 8 : 0);
+ int count = 4 + (offer_wscale ? TCPOLEN_WSCALE_ALIGNED : 0) +
+ ((ts) ? TCPOLEN_TSTAMP_ALIGNED : 0);
unsigned char *optr = skb_put(skb,count);
__u32 *ptr = (__u32 *)optr;
- /*
- * We always get an MSS option.
+ /* We always get an MSS option.
+ * The option bytes which will be seen in normal data
+ * packets should timestamps be used, must be in the MSS
+ * advertised. But we subtract them from sk->mss so
+ * that calculations in tcp_sendmsg are simpler etc.
+ * So account for this fact here if necessary. If we
+ * don't do this correctly, as a receiver we won't
+ * recognize data packets as being full sized when we
+ * should, and thus we won't abide by the delayed ACK
+ * rules correctly.
*/
+ if(ts)
+ mss += TCPOLEN_TSTAMP_ALIGNED;
*ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
if (ts) {
- if (sack) {
- *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
- | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
- *ptr++ = htonl(jiffies); /* TSVAL */
- *ptr++ = htonl(0); /* TSECR */
- } else {
- *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
- | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
- *ptr++ = htonl(jiffies); /* TSVAL */
- *ptr++ = htonl(0); /* TSECR */
- }
- } else if (sack) {
- *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16)
- | (TCPOPT_NOP << 8) | TCPOPT_NOP);
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(jiffies); /* TSVAL */
+ *ptr++ = __constant_htonl(0); /* TSECR */
}
if (offer_wscale)
*ptr++ = htonl((TCPOPT_WINDOW << 24) | (TCPOLEN_WINDOW << 16) | (wscale << 8));
@@ -724,33 +872,15 @@ extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
(*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
}
-#define SYNQ_DEBUG 1
-
extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev)
{
-#ifdef SYNQ_DEBUG
- if (prev->dl_next != req) {
- printk(KERN_DEBUG "synq_unlink: bad prev ptr: %p\n",prev);
- return;
- }
-#endif
- if(!req->dl_next) {
-#ifdef SYNQ_DEBUG
- if (tp->syn_wait_last != (void*) req)
- printk(KERN_DEBUG "synq_unlink: bad last ptr %p,%p\n",
- req,tp->syn_wait_last);
-#endif
+ if(!req->dl_next)
tp->syn_wait_last = (struct open_request **)prev;
- }
prev->dl_next = req->dl_next;
}
extern __inline__ void tcp_synq_queue(struct tcp_opt *tp, struct open_request *req)
{
-#ifdef SYNQ_DEBUG
- if (*tp->syn_wait_last != NULL)
- printk("synq_queue: last ptr doesn't point to last req.\n");
-#endif
req->dl_next = NULL;
*tp->syn_wait_last = req;
tp->syn_wait_last = &req->dl_next;
@@ -765,14 +895,11 @@ extern __inline__ void tcp_synq_init(struct tcp_opt *tp)
extern __inline__ struct open_request *tcp_synq_unlink_tail(struct tcp_opt *tp)
{
struct open_request *head = tp->syn_wait_queue;
-#ifdef SYNQ_DEBUG
- if (!head) {
- printk(KERN_DEBUG "tail drop on empty queue? - bug\n");
- return NULL;
- }
-#endif
+#if 0
+ /* Should be a net-ratelimit'd thing, not all the time. */
printk(KERN_DEBUG "synq tail drop with expire=%ld\n",
head->expires-jiffies);
+#endif
if (head->dl_next == NULL)
tp->syn_wait_last = &tp->syn_wait_queue;
tp->syn_wait_queue = head->dl_next;
@@ -799,6 +926,17 @@ extern __inline__ void tcp_dec_slow_timer(int timer)
atomic_dec(&slt->count);
}
+/* This needs to use a slow timer, so it is here. */
+static __inline__ void tcp_sk_unbindify(struct sock *sk)
+{
+ struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *) sk->prev;
+ if(sk->bind_next)
+ sk->bind_next->bind_pprev = sk->bind_pprev;
+ *sk->bind_pprev = sk->bind_next;
+ if(tb->owners == NULL)
+ tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
+}
+
extern const char timer_bug_msg[];
static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
@@ -820,7 +958,8 @@ static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
printk(timer_bug_msg);
return;
};
- del_timer(timer);
+ if(timer->prev != NULL)
+ del_timer(timer);
}
static inline int tcp_timer_is_set(struct sock *sk, int what)
@@ -829,13 +968,13 @@ static inline int tcp_timer_is_set(struct sock *sk, int what)
switch (what) {
case TIME_RETRANS:
- return tp->retransmit_timer.next != NULL;
+ return tp->retransmit_timer.prev != NULL;
break;
case TIME_DACK:
- return tp->delack_timer.next != NULL;
+ return tp->delack_timer.prev != NULL;
break;
case TIME_PROBE0:
- return tp->probe_timer.next != NULL;
+ return tp->probe_timer.prev != NULL;
break;
default:
printk(timer_bug_msg);
diff --git a/init/main.c b/init/main.c
index 85f56fda6..cc6657bbc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -82,8 +82,6 @@ extern void dquot_init(void);
extern void smp_setup(char *str, int *ints);
extern void ioapic_pirq_setup(char *str, int *ints);
extern void no_scroll(char *str, int *ints);
-extern void swap_setup(char *str, int *ints);
-extern void buff_setup(char *str, int *ints);
extern void panic_setup(char *str, int *ints);
extern void bmouse_setup(char *str, int *ints);
extern void msmouse_setup(char *str, int *ints);
@@ -282,7 +280,7 @@ extern void nfs_root_setup(char *str, int *ints);
extern void ftape_setup(char *str, int *ints);
#endif
-#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
+#if defined(CONFIG_SYSVIPC)
extern void ipc_init(void);
#endif
#ifdef CONFIG_MIPS_JAZZ
@@ -502,8 +500,6 @@ static struct kernel_param cooked_params[] __initdata = {
#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
{ "video=", video_setup },
#endif
- { "swap=", swap_setup },
- { "buff=", buff_setup },
{ "panic=", panic_setup },
{ "console=", console_setup },
#ifdef CONFIG_VT
@@ -1083,7 +1079,7 @@ __initfunc(asmlinkage void start_kernel(void))
inode_init();
file_table_init();
sock_init();
-#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
+#if defined(CONFIG_SYSVIPC)
ipc_init();
#endif
dquot_init();
@@ -1205,6 +1201,13 @@ static int init(void * unused)
}
#endif
+#ifdef CONFIG_KMOD
+ {
+ extern int kmod_init(void);
+ kmod_init();
+ }
+#endif
+
setup(1);
if (open("/dev/console", O_RDWR, 0) < 0)
diff --git a/ipc/Makefile b/ipc/Makefile
index 424052017..4e947582b 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -10,10 +10,6 @@
O_TARGET := ipc.o
O_OBJS := util.o
-ifdef CONFIG_KERNELD
-CONFIG_SYSVIPC=1
-endif
-
ifdef CONFIG_SYSVIPC
O_OBJS += msg.o sem.o shm.o
endif
diff --git a/ipc/msg.c b/ipc/msg.c
index 6ff658b02..30fe31239 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -1,19 +1,13 @@
/*
* linux/ipc/msg.c
* Copyright (C) 1992 Krishna Balasubramanian
- *
- * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995, and May 1996
- *
- * See <linux/kerneld.h> for the (optional) new kerneld protocol
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/msg.h>
#include <linux/stat.h>
#include <linux/malloc.h>
-#include <linux/kerneld.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -34,11 +28,6 @@ static unsigned short msg_seq = 0;
static int used_queues = 0;
static int max_msqid = 0;
static struct wait_queue *msg_lock = NULL;
-static int kerneld_msqid = -1;
-
-#define MAX_KERNELDS 20
-static int kerneld_arr[MAX_KERNELDS];
-static int n_kernelds = 0;
__initfunc(void msg_init (void))
{
@@ -51,39 +40,6 @@ __initfunc(void msg_init (void))
return;
}
-/*
- * If the send queue is full, try to free any old messages.
- * These are most probably unwanted, since no one has picked them up...
- */
-#define MSG_FLUSH_TIME 10 /* seconds */
-static void flush_msg(struct msqid_ds *msq)
-{
- struct msg *nmsg;
- unsigned long flags;
- int flushed = 0;
-
- save_flags(flags);
- cli();
-
- /* messages were put on the queue in time order */
- while ( (nmsg = msq->msg_first) &&
- ((CURRENT_TIME - nmsg->msg_stime) > MSG_FLUSH_TIME)) {
- msgbytes -= nmsg->msg_ts;
- msghdrs--;
- msq->msg_cbytes -= nmsg->msg_ts;
- msq->msg_qnum--;
- msq->msg_first = nmsg->msg_next;
- ++flushed;
- kfree(nmsg);
- }
-
- if (msq->msg_qnum == 0)
- msq->msg_first = msq->msg_last = NULL;
- restore_flags(flags);
- if (flushed)
- printk(KERN_WARNING "flushed %d old SYSVIPC messages", flushed);
-}
-
static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
{
int id, err;
@@ -97,20 +53,12 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return -EINVAL;
if (!msgp)
return -EFAULT;
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * have the message somewhere in kernel space already!
- */
- if ((msgflg & IPC_KERNELD))
- mtype = msgp->mtype;
- else {
- err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
- if (err)
- return err;
- get_user(mtype, &msgp->mtype);
- if (mtype < 1)
- return -EINVAL;
- }
+ err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
+ if (err)
+ return err;
+ get_user(mtype, &msgp->mtype);
+ if (mtype < 1)
+ return -EINVAL;
id = (unsigned int) msqid % MSGMNI;
msq = msgque [id];
if (msq == IPC_UNUSED || msq == IPC_NOID)
@@ -120,29 +68,17 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
slept:
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
return -EIDRM;
- /*
- * Non-root kernel level processes may send to kerneld!
- * i.e. no permission check if called from the kernel
- * otoh we don't want user level non-root snoopers...
- */
- if ((msgflg & IPC_KERNELD) == 0)
- if (ipcperms(ipcp, S_IWUGO))
- return -EACCES;
+
+ if (ipcperms(ipcp, S_IWUGO))
+ return -EACCES;
if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
- if ((kerneld_msqid != -1) && (kerneld_msqid == msqid))
- flush_msg(msq); /* flush the kerneld channel only */
if (msgsz + msq->msg_cbytes > msq->msg_qbytes) {
/* still no space in queue */
if (msgflg & IPC_NOWAIT)
return -EAGAIN;
if (signal_pending(current))
return -EINTR;
- if (in_interrupt()) {
- /* Very unlikely, but better safe than sorry */
- printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n");
- return -EINTR;
- }
interruptible_sleep_on (&msq->wwait);
goto slept;
}
@@ -154,22 +90,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return -ENOMEM;
msgh->msg_spot = (char *) (msgh + 1);
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * have the message somewhere in kernel space already!
- */
- if (msgflg & IPC_KERNELD) {
- struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
-
- /*
- * Note that the kernel supplies a pointer
- * but the user-level kerneld uses a char array...
- */
- memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), KDHDR);
- memcpy(msgh->msg_spot + KDHDR, kdmp->text, msgsz - KDHDR);
- }
- else
- copy_from_user (msgh->msg_spot, msgp->mtext, msgsz);
+ copy_from_user (msgh->msg_spot, msgp->mtext, msgsz);
if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
|| msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
@@ -201,42 +122,8 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
return 0;
}
-/*
- * Take care of missing kerneld, especially in case of multiple daemons
- */
-#define KERNELD_TIMEOUT 1 * (HZ)
-#define DROP_TIMER del_timer(&kd_timer)
-/*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/
-
-static void kd_timeout(unsigned long msgid)
-{
- struct msqid_ds *msq;
- struct msg *tmsg;
- unsigned long flags;
-
- msq = msgque [ (unsigned int) kerneld_msqid % MSGMNI ];
- if (msq == IPC_NOID || msq == IPC_UNUSED)
- return;
-
- save_flags(flags);
- cli();
- for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next)
- if (*(long *)(tmsg->msg_spot) == msgid)
- break;
- restore_flags(flags);
- if (tmsg) { /* still there! */
- struct kerneld_msg kmsp = { msgid, NULL_KDHDR, "" };
-
- printk(KERN_ALERT "Ouch, no kerneld for message %ld\n", msgid);
- kmsp.id = -ENODEV;
- real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, KDHDR,
- S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR);
- }
-}
-
static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
{
- struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
struct msqid_ds *msq;
struct ipc_perm *ipcp;
struct msg *tmsg, *leastp = NULL;
@@ -248,15 +135,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
return -EINVAL;
if (!msgp || !msgp->mtext)
return -EFAULT;
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * wants the message put in kernel space!
- */
- if ((msgflg & IPC_KERNELD) == 0) {
- err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
- if (err)
- return err;
- }
+
+ err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
+ if (err)
+ return err;
id = (unsigned int) msqid % MSGMNI;
msq = msgque [id];
@@ -264,16 +146,6 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
return -EINVAL;
ipcp = &msq->msg_perm;
- /*
- * Start timer for missing kerneld
- */
- if (msgflg & IPC_KERNELD) {
- kd_timer.data = (unsigned long)msgtyp;
- kd_timer.expires = jiffies + KERNELD_TIMEOUT;
- kd_timer.function = kd_timeout;
- add_timer(&kd_timer);
- }
-
/*
* find message of correct type.
* msgtyp = 0 => get first.
@@ -282,19 +154,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
*/
while (!nmsg) {
if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
- DROP_TIMER;
return -EIDRM;
}
- if ((msgflg & IPC_KERNELD) == 0) {
- /*
- * All kernel level processes may receive from kerneld!
- * i.e. no permission check if called from the kernel
- * otoh we don't want user level non-root snoopers...
- */
- if (ipcperms (ipcp, S_IRUGO)) {
- DROP_TIMER; /* Not needed, but doesn't hurt */
- return -EACCES;
- }
+ if (ipcperms (ipcp, S_IRUGO)) {
+ return -EACCES;
}
save_flags(flags);
@@ -326,7 +189,6 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
restore_flags(flags);
if (nmsg) { /* done finding a message */
- DROP_TIMER;
if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
return -E2BIG;
}
@@ -354,43 +216,20 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
msq->msg_cbytes -= nmsg->msg_ts;
restore_flags(flags);
wake_up (&msq->wwait);
- /*
- * Calls from kernel level (IPC_KERNELD set)
- * wants the message copied to kernel space!
- */
- if (msgflg & IPC_KERNELD) {
- struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
-
- memcpy((char *)(&(kdmp->id)),
- nmsg->msg_spot, KDHDR);
- /*
- * Note that kdmp->text is a pointer
- * when called from kernel space!
- */
- if ((msgsz > KDHDR) && kdmp->text)
- memcpy(kdmp->text,
- nmsg->msg_spot + KDHDR,
- msgsz - KDHDR);
- }
- else {
- put_user (nmsg->msg_type, &msgp->mtype);
- copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz);
- }
+ put_user (nmsg->msg_type, &msgp->mtype);
+ copy_to_user (msgp->mtext, nmsg->msg_spot, msgsz);
kfree(nmsg);
return msgsz;
} else { /* did not find a message */
if (msgflg & IPC_NOWAIT) {
- DROP_TIMER;
return -ENOMSG;
}
if (signal_pending(current)) {
- DROP_TIMER;
return -EINTR;
}
interruptible_sleep_on (&msq->rwait);
}
} /* end while */
- DROP_TIMER;
return -1;
}
@@ -398,9 +237,8 @@ asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msg
{
int ret;
- /* IPC_KERNELD is used as a marker for kernel level calls */
lock_kernel();
- ret = real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
+ ret = real_msgsnd(msqid, msgp, msgsz, msgflg);
unlock_kernel();
return ret;
}
@@ -410,9 +248,8 @@ asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
{
int ret;
- /* IPC_KERNELD is used as a marker for kernel level calls */
lock_kernel();
- ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
+ ret = real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg);
unlock_kernel();
return ret;
}
@@ -479,36 +316,7 @@ asmlinkage int sys_msgget (key_t key, int msgflg)
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())
- goto out;
-#ifdef NEW_KERNELD_PROTOCOL
- if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) {
- printk(KERN_ALERT "Please recompile your kerneld daemons!\n");
- goto out;
- }
-#endif
- ret = -ENOSPC;
- if ((kerneld_msqid == -1) && (kerneld_msqid =
- newque(IPC_PRIVATE, msgflg & S_IRWXU)) < 0)
- goto out;
- for (i = 0; i < MAX_KERNELDS; ++i) {
- if (kerneld_arr[i] == 0) {
- kerneld_arr[i] = current->pid;
- ++n_kernelds;
- ret = kerneld_msqid;
- goto out;
- }
- }
- goto out;
- }
- /* else it is a "normal" request */
if (key == IPC_PRIVATE)
ret = newque(key, msgflg);
else if ((id = findkey (key)) == -1) { /* key not used */
@@ -527,7 +335,6 @@ asmlinkage int sys_msgget (key_t key, int msgflg)
else
ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
}
-out:
unlock_kernel();
return ret;
}
@@ -687,12 +494,7 @@ asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !suser())
goto out;
- /*
- * There is only one kerneld message queue,
- * mark it as non-existent
- */
- if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
- kerneld_msqid = -1;
+
freeque (id);
err = 0;
goto out;
@@ -705,104 +507,3 @@ out:
return err;
}
-/*
- * We do perhaps need a "flush" for waiting processes,
- * so that if they are terminated, a call from do_exit
- * will minimize the possibility of orphaned received
- * messages in the queue. For now we just make sure
- * that the queue is shut down whenever all kernelds have died.
- */
-void kerneld_exit(void)
-{
- int i;
-
- if (kerneld_msqid == -1)
- return;
- for (i = 0; i < MAX_KERNELDS; ++i) {
- if (kerneld_arr[i] == current->pid) {
- kerneld_arr[i] = 0;
- --n_kernelds;
- if (n_kernelds == 0)
- sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
- break;
- }
- }
-}
-
-/*
- * Kerneld internal message format/syntax:
- *
- * The message type from the kernel to kerneld is used to specify _what_
- * function we want kerneld to perform.
- *
- * The "normal" message area is divided into a header, followed by a char array.
- * The header is used to hold the sequence number of the request, which will
- * be used as the return message type from kerneld back to the kernel.
- * In the return message, the header will be used to store the exit status
- * of the kerneld "job", or task.
- * The character array is used to pass parameters to kerneld and (optional)
- * return information from kerneld back to the kernel.
- * It is the responsibility of kerneld and the kernel level caller
- * to set usable sizes on the parameter/return value array, since
- * that information is _not_ included in the message format
- */
-
-/*
- * The basic kernel level entry point to kerneld.
- * msgtype should correspond to a task type for (a) kerneld
- * ret_size is the size of the (optional) return _value,
- * OR-ed with KERNELD_WAIT if we want an answer
- * msgsize is the size (in bytes) of the message, not including
- * the header that is always sent first in a kerneld message
- * text is the parameter for the kerneld specific task
- * ret_val is NULL or the kernel address where an expected answer
- * from kerneld should be placed.
- *
- * See <linux/kerneld.h> for usage (inline convenience functions)
- *
- */
-int kerneld_send(int msgtype, int ret_size, int msgsz,
- const char *text, const char *ret_val)
-{
- int status = -ENOSYS;
-#ifdef CONFIG_KERNELD
- static int id = KERNELD_MINSEQ;
- struct kerneld_msg kmsp = { msgtype, NULL_KDHDR, (char *)text };
- int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
- unsigned long flags;
-
- if (kerneld_msqid == -1)
- return -ENODEV;
-
- /* Do not wait for an answer at interrupt-time! */
- if (in_interrupt())
- ret_size &= ~KERNELD_WAIT;
-#ifdef NEW_KERNELD_PROTOCOL
- else
- kmsp.pid = current->pid;
-#endif
-
- msgsz += KDHDR;
- if (ret_size & KERNELD_WAIT) {
- save_flags(flags);
- cli();
- if (++id <= 0) /* overflow */
- id = KERNELD_MINSEQ;
- kmsp.id = id;
- restore_flags(flags);
- }
-
- status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
- if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
- ret_size &= ~KERNELD_WAIT;
- kmsp.text = (char *)ret_val;
- status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
- KDHDR + ((ret_val)?ret_size:0),
- kmsp.id, msgflg);
- if (status > 0) /* a valid answer contains at least a long */
- status = kmsp.id;
- }
-
-#endif /* CONFIG_KERNELD */
- return status;
-}
diff --git a/ipc/util.c b/ipc/util.c
index f0ba7fedd..eacea2b62 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -20,7 +20,7 @@
#include <asm/uaccess.h>
-#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
+#if defined(CONFIG_SYSVIPC)
extern void sem_init (void), msg_init (void), shm_init (void);
@@ -123,7 +123,4 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
return -ENOSYS;
}
-void kerneld_exit(void)
-{
-}
#endif /* CONFIG_SYSVIPC */
diff --git a/kernel/Makefile b/kernel/Makefile
index ff908f68a..4e0a1d87d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -17,6 +17,10 @@ O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
OX_OBJS += signal.o
+ifeq ($(CONFIG_KMOD),y)
+O_OBJS += kmod.o
+endif
+
ifeq ($(CONFIG_MODULES),y)
OX_OBJS += ksyms.o
endif
diff --git a/kernel/exit.c b/kernel/exit.c
index 9824f5806..2d5835ac8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -27,7 +27,6 @@
#include <asm/mmu_context.h>
extern void sem_exit (void);
-extern void kerneld_exit(void);
int getrusage(struct task_struct *, int, struct rusage *);
@@ -44,8 +43,14 @@ void release(struct task_struct * p)
charge_uid(p, -1);
nr_tasks--;
add_free_taskslot(p->tarray_ptr);
- unhash_pid(p);
- REMOVE_LINKS(p);
+ {
+ unsigned long flags;
+
+ write_lock_irqsave(&tasklist_lock, flags);
+ unhash_pid(p);
+ REMOVE_LINKS(p);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ }
release_thread(p);
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
@@ -157,7 +162,7 @@ static inline void close_files(struct files_struct * files)
unsigned long set = files->open_fds.fds_bits[j];
i = j * __NFDBITS;
j++;
- if (i >= NR_OPEN)
+ if (i >= files->max_fds)
break;
while (set) {
if (set & 1) {
@@ -183,6 +188,13 @@ static inline void __exit_files(struct task_struct *tsk)
tsk->files = NULL;
if (!--files->count) {
close_files(files);
+ /*
+ * Free the fd array as appropriate ...
+ */
+ if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE)
+ free_page((unsigned long) files->fd);
+ else
+ kfree(files->fd);
kmem_cache_free(files_cachep, files);
}
}
@@ -328,7 +340,6 @@ fake_volatile:
acct_process(code);
del_timer(&current->real_timer);
sem_exit();
- kerneld_exit();
__exit_mm(current);
#if CONFIG_AP1000
exit_msc(current);
diff --git a/kernel/fork.c b/kernel/fork.c
index 38c98b0a8..a08aa2c64 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -41,7 +41,6 @@ kmem_cache_t *mm_cachep;
kmem_cache_t *files_cachep;
struct task_struct *pidhash[PIDHASH_SZ];
-spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED;
struct task_struct **tarray_freelist = NULL;
spinlock_t taskslot_lock = SPIN_LOCK_UNLOCKED;
@@ -263,6 +262,9 @@ fail_nomem:
/*
* Allocate and initialize an mm_struct.
+ *
+ * NOTE! The mm mutex will be locked until the
+ * caller decides that all systems are go..
*/
struct mm_struct * mm_alloc(void)
{
@@ -275,7 +277,7 @@ struct mm_struct * mm_alloc(void)
mm->count = 1;
mm->map_count = 0;
mm->def_flags = 0;
- mm->mmap_sem = MUTEX;
+ mm->mmap_sem = MUTEX_LOCKED;
/*
* Leave mm->pgd set to the parent's pgd
* so that pgd_offset() is always valid.
@@ -328,6 +330,7 @@ static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
retval = dup_mmap(mm);
if (retval)
goto free_pt;
+ up(&mm->mmap_sem);
return 0;
free_mm:
@@ -375,44 +378,66 @@ static inline int copy_fdset(fd_set *dst, fd_set *src)
return __copy_fdset(dst->fds_bits, src->fds_bits);
}
-static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk)
+static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
{
- int i;
struct files_struct *oldf, *newf;
struct file **old_fds, **new_fds;
+ int size, i, error = 0;
/*
* A background process may not have any files ...
*/
oldf = current->files;
if (!oldf)
- return 0;
+ goto out;
if (clone_flags & CLONE_FILES) {
oldf->count++;
- return 0;
+ goto out;
}
+ tsk->files = NULL;
+ error = -ENOMEM;
newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
- tsk->files = newf;
if (!newf)
- return -1;
+ goto out;
+
+ /*
+ * Allocate the fd array, using get_free_page() if possible.
+ * Eventually we want to make the array size variable ...
+ */
+ size = NR_OPEN * sizeof(struct file *);
+ if (size == PAGE_SIZE)
+ new_fds = (struct file **) __get_free_page(GFP_KERNEL);
+ else
+ new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
+ if (!new_fds)
+ goto out_release;
+ memset((void *) new_fds, 0, size);
newf->count = 1;
+ newf->max_fds = NR_OPEN;
+ newf->fd = new_fds;
newf->close_on_exec = oldf->close_on_exec;
- i = copy_fdset(&newf->open_fds,&oldf->open_fds);
+ i = copy_fdset(&newf->open_fds, &oldf->open_fds);
old_fds = oldf->fd;
- new_fds = newf->fd;
for (; i != 0; i--) {
struct file * f = *old_fds;
old_fds++;
*new_fds = f;
- new_fds++;
if (f)
f->f_count++;
+ new_fds++;
}
- return 0;
+ tsk->files = newf;
+ error = 0;
+out:
+ return error;
+
+out_release:
+ kmem_cache_free(files_cachep, newf);
+ goto out;
}
static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
@@ -495,8 +520,15 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
p->start_time = jiffies;
p->tarray_ptr = &task[nr];
*p->tarray_ptr = p;
- SET_LINKS(p);
- hash_pid(p);
+
+ {
+ unsigned long flags;
+ write_lock_irqsave(&tasklist_lock, flags);
+ SET_LINKS(p);
+ hash_pid(p);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ }
+
nr_tasks++;
error = -ENOMEM;
@@ -553,8 +585,15 @@ bad_fork_cleanup:
if (p->binfmt && p->binfmt->module)
__MOD_DEC_USE_COUNT(p->binfmt->module);
add_free_taskslot(p->tarray_ptr);
- unhash_pid(p);
- REMOVE_LINKS(p);
+
+ {
+ unsigned long flags;
+ write_lock_irqsave(&tasklist_lock, flags);
+ unhash_pid(p);
+ REMOVE_LINKS(p);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ }
+
nr_tasks--;
bad_fork_free:
free_task_struct(p);
diff --git a/kernel/kmod.c b/kernel/kmod.c
new file mode 100644
index 000000000..a0f58d485
--- /dev/null
+++ b/kernel/kmod.c
@@ -0,0 +1,149 @@
+/*
+ kmod, the new module loader (replaces kerneld)
+ Kirk Petersen
+*/
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+static inline _syscall1(int,delete_module,const char *,name_user)
+
+/*
+ kmod_unload_delay and modprobe_path are set via /proc/sys.
+*/
+int kmod_unload_delay = 60;
+char modprobe_path[256] = "/sbin/modprobe";
+char module_name[64] = "";
+char * argv[] = { "modprobe", "-k", NULL, NULL, };
+char * envp[] = { "HOME=/", "TERM=linux", NULL, };
+
+/*
+ kmod_queue synchronizes the kmod thread and the rest of the system
+ kmod_unload_timer is what we use to unload modules
+ after kmod_unload_delay seconds
+*/
+struct wait_queue * kmod_queue = NULL;
+struct timer_list kmod_unload_timer;
+
+/*
+ kmod_thread is the thread that does most of the work. kmod_unload and
+ request_module tell it to wake up and do work.
+*/
+int kmod_thread(void * data)
+{
+ int pid;
+
+ /*
+ Initialize basic thread information
+ */
+ current->session = 1;
+ current->pgrp = 1;
+ sprintf(current->comm, "kmod");
+ sigfillset(&current->blocked);
+
+ /*
+ This is the main kmod_thread loop. It first sleeps, then
+ handles requests from request_module or kmod_unload.
+ */
+
+ while (1) {
+ interruptible_sleep_on(&kmod_queue);
+
+ /*
+ If request_module woke us up, we should try to
+ load module_name. If not, kmod_unload woke us up,
+ do call delete_module.
+ (if somehow both want us to do something, ignore the
+ delete_module request)
+ */
+ if (module_name[0] == '\0') {
+ delete_module(NULL);
+ } else {
+ pid = fork();
+ if (pid > 0) {
+ waitpid(pid, NULL, 0);
+ module_name[0] = '\0';
+ wake_up(&kmod_queue);
+ } else
+ if (pid == 0) {
+
+ /*
+ Call modprobe with module_name. If execve returns,
+ print out an error.
+ */
+ argv[2] = module_name;
+ execve(modprobe_path, argv, envp);
+
+ printk("kmod: failed to load module %s\n", module_name);
+ _exit(0);
+ } else {
+ printk("error, fork failed in kmod\n");
+ }
+ }
+ }
+
+ return 0; /* Never reached. */
+}
+
+/*
+ kmod_unload is the function that the kernel calls when
+ the kmod_unload_timer expires
+*/
+void kmod_unload(unsigned long x)
+{
+ /*
+ wake up the kmod thread, which does the work
+ (we can't call delete_module, as it locks the kernel and
+ we are in the bottom half of the kernel (right?))
+ once it is awake, reset the timer
+ */
+ wake_up(&kmod_queue);
+ kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
+ add_timer(&kmod_unload_timer);
+}
+
+int kmod_init(void)
+{
+ printk ("Starting kmod\n");
+
+ kernel_thread(kmod_thread, NULL, 0);
+
+ kmod_unload_timer.next = NULL;
+ kmod_unload_timer.prev = NULL;
+ kmod_unload_timer.expires = jiffies + (5 * 60 * HZ);
+ kmod_unload_timer.data = 0L;
+ kmod_unload_timer.function = kmod_unload;
+ add_timer(&kmod_unload_timer);
+
+ return 0;
+}
+
+/*
+ request_module, the function that everyone calls when they need a
+ module to be loaded
+*/
+int request_module(const char * name)
+{
+ /* first, copy the name of the module into module_name */
+ /* then wake_up() the kmod daemon */
+ /* wait for the kmod daemon to finish (it will wake us up) */
+
+ /*
+ kmod_thread is sleeping, so start by copying the name of
+ the module into module_name. Once that is done, wake up
+ kmod_thread.
+ */
+ strcpy(module_name, name);
+ wake_up(&kmod_queue);
+
+ /*
+ Now that we have told kmod_thread what to do, we want to
+ go to sleep and let it do its work. It will wake us up,
+ at which point we will be done (the module will be loaded).
+ */
+ interruptible_sleep_on(&kmod_queue);
+ return 0;
+}
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 869e5e5bb..7ff40d7bd 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -61,8 +61,8 @@ extern unsigned char aux_device_present, kbd_read_mask;
#if defined(CONFIG_PROC_FS)
#include <linux/proc_fs.h>
#endif
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <asm/irq.h>
#ifdef __SMP__
@@ -91,12 +91,13 @@ __attribute__((section("__ksymtab"))) = {
#endif
+#ifdef CONFIG_KMOD
+EXPORT_SYMBOL(request_module);
+#endif
+
#ifdef CONFIG_MODULES
EXPORT_SYMBOL(get_module_symbol);
#endif
-#ifdef CONFIG_KERNELD
-EXPORT_SYMBOL(kerneld_send);
-#endif
EXPORT_SYMBOL(get_options);
#ifdef CONFIG_PCI
diff --git a/kernel/module.c b/kernel/module.c
index efee5902e..90f0bf1a2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -324,7 +324,7 @@ sys_init_module(const char *name_user, struct module *mod_user)
dep->next_ref = d->refs;
d->refs = dep;
/* Being referenced by a dependant module counts as a
- use as far as kerneld is concerned. */
+ use as far as kmod is concerned. */
d->flags |= MOD_USED_ONCE;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index f48f520ff..a86cb0413 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -155,9 +155,9 @@ static inline void move_last_runqueue(struct task_struct * p)
* The run-queue lock locks the parts that actually access
* and change the run-queues, and have to be interrupt-safe.
*/
-rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;
-spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED; /* should be aquired first */
+spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; /* second */
+rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; /* third */
/*
* Wake up a process. Put it on the run-queue if it's not
@@ -201,14 +201,20 @@ static void process_timeout(unsigned long __data)
*/
static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu)
{
+ int policy = p->policy;
int weight;
+ if (policy & SCHED_YIELD) {
+ p->policy = policy & ~SCHED_YIELD;
+ return 0;
+ }
+
/*
* Realtime process, select the first one on the
* runqueue (taking priorities within processes
* into account).
*/
- if (p->policy != SCHED_OTHER)
+ if (policy != SCHED_OTHER)
return 1000 + p->rt_priority;
/*
@@ -228,9 +234,10 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
weight += PROC_CHANGE_PENALTY;
#endif
- /* .. and a slight advantage to the current process */
- if (p == prev)
+ /* .. and a slight advantage to the current thread */
+ if (p->mm == prev->mm)
weight += 1;
+ weight += p->priority;
}
return weight;
@@ -1253,10 +1260,11 @@ asmlinkage int sys_nice(int increment)
static inline struct task_struct *find_process_by_pid(pid_t pid)
{
+ struct task_struct *tsk = current;
+
if (pid)
- return find_task_by_pid(pid);
- else
- return current;
+ tsk = find_task_by_pid(pid);
+ return tsk;
}
static int setscheduler(pid_t pid, int policy,
@@ -1264,48 +1272,70 @@ static int setscheduler(pid_t pid, int policy,
{
struct sched_param lp;
struct task_struct *p;
+ int retval;
+ retval = -EINVAL;
if (!param || pid < 0)
- return -EINVAL;
+ goto out_nounlock;
+ retval = -EFAULT;
if (copy_from_user(&lp, param, sizeof(struct sched_param)))
- return -EFAULT;
+ goto out_nounlock;
+
+ /*
+ * We play safe to avoid deadlocks.
+ */
+ spin_lock_irq(&scheduler_lock);
+ spin_lock(&runqueue_lock);
+ read_lock(&tasklist_lock);
p = find_process_by_pid(pid);
+
+ retval = -ESRCH;
if (!p)
- return -ESRCH;
+ goto out_unlock;
if (policy < 0)
policy = p->policy;
- else if (policy != SCHED_FIFO && policy != SCHED_RR &&
- policy != SCHED_OTHER)
- return -EINVAL;
+ else {
+ retval = -EINVAL;
+ if (policy != SCHED_FIFO && policy != SCHED_RR &&
+ policy != SCHED_OTHER)
+ goto out_unlock;
+ }
/*
* Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid
* priority for SCHED_OTHER is 0.
*/
+ retval = -EINVAL;
if (lp.sched_priority < 0 || lp.sched_priority > 99)
- return -EINVAL;
+ goto out_unlock;
if ((policy == SCHED_OTHER) != (lp.sched_priority == 0))
- return -EINVAL;
+ goto out_unlock;
+ retval = -EPERM;
if ((policy == SCHED_FIFO || policy == SCHED_RR) && !suser())
- return -EPERM;
+ goto out_unlock;
if ((current->euid != p->euid) && (current->euid != p->uid) &&
!suser())
- return -EPERM;
+ goto out_unlock;
+ retval = 0;
p->policy = policy;
p->rt_priority = lp.sched_priority;
- spin_lock(&scheduler_lock);
- spin_lock_irq(&runqueue_lock);
if (p->next_run)
move_last_runqueue(p);
- spin_unlock_irq(&runqueue_lock);
- spin_unlock(&scheduler_lock);
+
need_resched = 1;
- return 0;
+
+out_unlock:
+ read_unlock(&tasklist_lock);
+ spin_unlock(&runqueue_lock);
+ spin_unlock_irq(&scheduler_lock);
+
+out_nounlock:
+ return retval;
}
asmlinkage int sys_sched_setscheduler(pid_t pid, int policy,
@@ -1322,42 +1352,64 @@ asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param)
asmlinkage int sys_sched_getscheduler(pid_t pid)
{
struct task_struct *p;
+ int retval;
+ retval = -EINVAL;
if (pid < 0)
- return -EINVAL;
+ goto out_nounlock;
+ read_lock(&tasklist_lock);
+
+ retval = -ESRCH;
p = find_process_by_pid(pid);
if (!p)
- return -ESRCH;
+ goto out_unlock;
- return p->policy;
+ retval = p->policy;
+
+out_unlock:
+ read_unlock(&tasklist_lock);
+
+out_nounlock:
+ return retval;
}
asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param)
{
struct task_struct *p;
struct sched_param lp;
+ int retval;
+ retval = -EINVAL;
if (!param || pid < 0)
- return -EINVAL;
+ goto out_nounlock;
+ read_lock(&tasklist_lock);
p = find_process_by_pid(pid);
+ retval = -ESRCH;
if (!p)
- return -ESRCH;
-
+ goto out_unlock;
lp.sched_priority = p->rt_priority;
- return copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0;
+ read_unlock(&tasklist_lock);
+
+ /*
+ * This one might sleep, we cannot do it with a spinlock held ...
+ */
+ retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
+
+out_nounlock:
+ return retval;
+
+out_unlock:
+ read_unlock(&tasklist_lock);
+ return retval;
}
asmlinkage int sys_sched_yield(void)
{
- /*
- * This is not really right. We'd like to reschedule
- * just _once_ with this process having a zero count.
- */
- current->counter = 0;
spin_lock(&scheduler_lock);
spin_lock_irq(&runqueue_lock);
+ current->policy |= SCHED_YIELD;
move_last_runqueue(current);
spin_unlock_irq(&runqueue_lock);
spin_unlock(&scheduler_lock);
diff --git a/kernel/signal.c b/kernel/signal.c
index 53228eb31..c313b0a11 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -438,8 +438,16 @@ kill_sl_info(int sig, struct siginfo *info, pid_t sess)
inline int
kill_proc_info(int sig, struct siginfo *info, pid_t pid)
{
- struct task_struct *p = find_task_by_pid(pid);
- return p ? send_sig_info(sig, info, p) : -ESRCH;
+ int error;
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ error = -ESRCH;
+ if (p)
+ error = send_sig_info(sig, info, p);
+ read_unlock(&tasklist_lock);
+ return error;
}
/*
diff --git a/kernel/sys.c b/kernel/sys.c
index 1d8356de0..e86d18c09 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -578,14 +578,16 @@ asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
if (pgid < 0)
return -EINVAL;
- if((p = find_task_by_pid(pid)) == NULL)
- return -ESRCH;
-
/* From this point forward we keep holding onto the tasklist lock
* so that our parent does not change from under us. -DaveM
*/
read_lock(&tasklist_lock);
+
err = -ESRCH;
+ p = find_task_by_pid(pid);
+ if (!p)
+ goto out;
+
if (p->p_pptr == current || p->p_opptr == current) {
err = -EPERM;
if (p->session != current->session)
@@ -622,12 +624,17 @@ asmlinkage int sys_getpgid(pid_t pid)
if (!pid) {
return current->pgrp;
} else {
- struct task_struct *p = find_task_by_pid(pid);
+ int retval;
+ struct task_struct *p;
- if(p)
- return p->pgrp;
- else
- return -ESRCH;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+
+ retval = -ESRCH;
+ if (p)
+ retval = p->pgrp;
+ read_unlock(&tasklist_lock);
+ return retval;
}
}
@@ -642,12 +649,17 @@ asmlinkage int sys_getsid(pid_t pid)
if (!pid) {
return current->session;
} else {
- struct task_struct *p = find_task_by_pid(pid);
+ int retval;
+ struct task_struct *p;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+
+ retval = -ESRCH;
if(p)
- return p->session;
- else
- return -ESRCH;
+ retval = p->session;
+ read_unlock(&tasklist_lock);
+ return retval;
}
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1b93ad7bd..e6864541f 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -41,6 +41,10 @@ extern int console_loglevel, C_A_D, swapout_interval;
extern int bdf_prm[], bdflush_min[], bdflush_max[];
extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
extern int sysctl_overcommit_memory;
+#ifdef CONFIG_KMOD
+extern char modprobe_path[];
+extern int kmod_unload_delay;
+#endif
#ifdef __sparc__
extern char reboot_command [];
@@ -174,6 +178,12 @@ static ctl_table kern_table[] = {
0644, NULL, &proc_dointvec},
{KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
0644, NULL, &proc_dointvec},
+#ifdef CONFIG_KMOD
+ {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
+ 0644, NULL, &proc_dostring, &sysctl_string },
+ {KERN_KMOD_UNLOAD_DELAY, "kmod_unload_delay", &kmod_unload_delay,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
{0}
};
@@ -183,12 +193,14 @@ static ctl_table vm_table[] = {
{VM_SWAPOUT, "swapout_interval",
&swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
{VM_FREEPG, "freepages",
- &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
+ &freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec},
{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL,
&bdflush_min, &bdflush_max},
{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
+ {VM_BUFFERMEM, "buffermem",
+ &buffer_mem, sizeof(buffer_mem_t), 0600, NULL, &proc_dointvec},
{0}
};
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ed748bbfb..a3b1c0e8c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -331,9 +331,9 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e
i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
if (i < 48)
i = 48;
- min_free_pages = i;
- free_pages_low = i + (i>>1);
- free_pages_high = i + i;
+ freepages.min = i;
+ freepages.low = i + (i>>1);
+ freepages.high = i + i;
mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
p = mem_map + MAP_NR(end_mem);
start_mem = LONG_ALIGN((unsigned long) p);
diff --git a/mm/slab.c b/mm/slab.c
index d0b4214f9..a2ed8c1c5 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1824,7 +1824,9 @@ next:
}
spin_lock_irq(&best_cachep->c_spinlock);
- if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) {
+ while (!best_cachep->c_growing &&
+ !(slabp = best_cachep->c_lastp)->s_inuse &&
+ slabp != kmem_slab_end(best_cachep)) {
if (gfp_mask & GFP_DMA) {
do {
if (slabp->s_dma)
@@ -1848,7 +1850,7 @@ good_dma:
*/
spin_unlock_irq(&best_cachep->c_spinlock);
kmem_slab_destroy(best_cachep, slabp);
- return;
+ spin_lock_irq(&best_cachep->c_spinlock);
}
dma_fail:
spin_unlock_irq(&best_cachep->c_spinlock);
diff --git a/mm/swap.c b/mm/swap.c
index 80817ecf1..0ccf96dc8 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -5,10 +5,12 @@
*/
/*
- * This file should contain most things doing the swapping from/to disk.
+ * This file contains the default values for the opereation of the
+ * Linux VM subsystem. Finetuning documentation can be found in
+ * linux/Documentation/sysctl/vm.txt.
* Started 18.12.91
- *
* Swap aging added 23.2.95, Stephen Tweedie.
+ * Buffermem limits added 12.3.98, Rik van Riel.
*/
#include <linux/mm.h>
@@ -33,15 +35,18 @@
/*
* We identify three levels of free memory. We never let free mem
- * fall below the min_free_pages except for atomic allocations. We
- * start background swapping if we fall below free_pages_high free
- * pages, and we begin intensive swapping below free_pages_low.
+ * fall below the freepages.min except for atomic allocations. We
+ * start background swapping if we fall below freepages.high free
+ * pages, and we begin intensive swapping below freepages.low.
*
- * Keep these three variables contiguous for sysctl(2).
+ * These values are there to keep GCC from complaining. Actual
+ * initialization is done in mm/page_alloc.c or arch/sparc(64)/mm/init.c.
*/
-int min_free_pages = 48;
-int free_pages_low = 72;
-int free_pages_high = 96;
+freepages_t freepages = {
+ 48, /* freepages.min */
+ 72, /* freepages.low */
+ 96 /* freepages.high */
+};
/* We track the number of pages currently being asynchronously swapped
out, so that we don't try to swap TOO many pages out at once */
@@ -55,53 +60,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0);
swap_control_t swap_control = {
20, 3, 1, 3, /* Page aging */
- 10, 2, 2, 4, /* Buffer aging */
32, 4, /* Aging cluster */
8192, 8192, /* Pageout and bufferout weights */
- -200, /* Buffer grace */
- 1, 1, /* Buffs/pages to free */
- RCL_ROUND_ROBIN /* Balancing policy */
};
swapstat_t swapstats = {0};
-/* General swap control */
-
-/* Parse the kernel command line "swap=" option at load time: */
-__initfunc(void swap_setup(char *str, int *ints))
-{
- int * swap_vars[8] = {
- &MAX_PAGE_AGE,
- &PAGE_ADVANCE,
- &PAGE_DECLINE,
- &PAGE_INITIAL_AGE,
- &AGE_CLUSTER_FRACT,
- &AGE_CLUSTER_MIN,
- &PAGEOUT_WEIGHT,
- &BUFFEROUT_WEIGHT
- };
- int i;
- for (i=0; i < ints[0] && i < 8; i++) {
- if (ints[i+1])
- *(swap_vars[i]) = ints[i+1];
- }
-}
-
-/* Parse the kernel command line "buff=" option at load time: */
-__initfunc(void buff_setup(char *str, int *ints))
-{
- int * buff_vars[6] = {
- &MAX_BUFF_AGE,
- &BUFF_ADVANCE,
- &BUFF_DECLINE,
- &BUFF_INITIAL_AGE,
- &BUFFEROUT_WEIGHT,
- &BUFFERMEM_GRACE
- };
- int i;
- for (i=0; i < ints[0] && i < 6; i++) {
- if (ints[i+1])
- *(buff_vars[i]) = ints[i+1];
- }
-}
+buffer_mem_t buffer_mem = {
+ 6, /* minimum percent buffer + cache memory */
+ 20, /* borrow percent buffer + cache memory */
+ 90 /* maximum percent buffer + cache memory */
+};
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4ebc5c05f..b575877ff 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -64,13 +64,13 @@ int add_to_swap_cache(struct page *page, unsigned long entry)
#endif
if (PageTestandSetSwapCache(page)) {
printk("swap_cache: replacing non-empty entry %08lx "
- "on page %08lx",
+ "on page %08lx\n",
page->offset, page_address(page));
return 0;
}
if (page->inode) {
printk("swap_cache: replacing page-cached entry "
- "on page %08lx", page_address(page));
+ "on page %08lx\n", page_address(page));
return 0;
}
atomic_inc(&page->count);
@@ -138,18 +138,18 @@ void remove_from_swap_cache(struct page *page)
{
if (!page->inode) {
printk ("VM: Removing swap cache page with zero inode hash "
- "on page %08lx", page_address(page));
+ "on page %08lx\n", page_address(page));
return;
}
if (page->inode != &swapper_inode) {
printk ("VM: Removing swap cache page with wrong inode hash "
- "on page %08lx", page_address(page));
+ "on page %08lx\n", page_address(page));
}
/*
* This will be a legal case once we have a more mature swap cache.
*/
if (atomic_read(&page->count) == 1) {
- printk ("VM: Removing page cache on unshared page %08lx",
+ printk ("VM: Removing page cache on unshared page %08lx\n",
page_address(page));
return;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index ebef7a362..5d4188ae5 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6,7 +6,7 @@
* Swap reorganised 29.12.95, Stephen Tweedie.
* kswapd added: 7.1.96 sct
* Removed kswapd_ctl limits, and swap out as many pages as needed
- * to bring the system back to free_pages_high: 2.4.97, Rik van Riel.
+ * to bring the system back to freepages.high: 2.4.97, Rik van Riel.
* Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $
*/
@@ -22,6 +22,8 @@
#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -454,11 +456,14 @@ static inline int do_try_to_free_page(int gfp_mask)
stop = 3;
if (gfp_mask & __GFP_WAIT)
stop = 0;
+ if (BUFFER_MEM > buffer_mem.borrow_percent * num_physpages / 100)
+ state = 0;
switch (state) {
do {
case 0:
- if (shrink_mmap(i, gfp_mask))
+ if (BUFFER_MEM > (buffer_mem.min_percent * num_physpages /100) &&
+ shrink_mmap(i, gfp_mask))
return 1;
state = 1;
case 1:
@@ -511,7 +516,6 @@ void kswapd_setup(void)
printk ("Starting kswapd v%.*s\n", i, s);
}
-#define MAX_SWAP_FAIL 3
/*
* The background pageout daemon.
* Started as a kernel thread from the init process.
@@ -542,32 +546,25 @@ int kswapd(void *unused)
while (1) {
int tries;
+ current->state = TASK_INTERRUPTIBLE;
kswapd_awake = 0;
flush_signals(current);
run_task_queue(&tq_disk);
schedule();
- current->state = TASK_INTERRUPTIBLE;
kswapd_awake = 1;
swapstats.wakeups++;
/* Do the background pageout:
* When we've got loads of memory, we try
- * (free_pages_high - nr_free_pages) times to
+ * (freepages.high - nr_free_pages) times to
* free memory. As memory gets tighter, kswapd
* gets more and more agressive. -- Rik.
*/
- tries = free_pages_high - nr_free_pages;
- if (tries < min_free_pages) {
- tries = min_free_pages;
+ tries = freepages.high - nr_free_pages;
+ if (tries < freepages.min) {
+ tries = freepages.min;
}
- else if (nr_free_pages < (free_pages_high + free_pages_low) / 2) {
+ if (nr_free_pages < freepages.high + freepages.low)
tries <<= 1;
- if (nr_free_pages < free_pages_low) {
- tries <<= 1;
- if (nr_free_pages <= min_free_pages) {
- tries <<= 1;
- }
- }
- }
while (tries--) {
int gfp_mask;
@@ -583,14 +580,6 @@ int kswapd(void *unused)
run_task_queue(&tq_disk);
}
-#if 0
- /*
- * Report failure if we couldn't even reach min_free_pages.
- */
- if (nr_free_pages < min_free_pages)
- printk("kswapd: failed, got %d of %d\n",
- nr_free_pages, min_free_pages);
-#endif
}
/* As if we could ever get here - maybe we want to make this killable */
remove_wait_queue(&kswapd_wait, &wait);
@@ -606,9 +595,10 @@ void swap_tick(void)
int want_wakeup = 0, memory_low = 0;
int pages = nr_free_pages + atomic_read(&nr_async_pages);
- if (pages < free_pages_low)
+ if (pages < freepages.low)
memory_low = want_wakeup = 1;
- else if (pages < free_pages_high && jiffies >= next_swap_jiffies)
+ else if ((pages < freepages.high || BUFFER_MEM > (num_physpages * buffer_mem.max_percent / 100))
+ && jiffies >= next_swap_jiffies)
want_wakeup = 1;
if (want_wakeup) {
diff --git a/net/802/sysctl_net_802.c b/net/802/sysctl_net_802.c
index f97141d3c..19cd47af5 100644
--- a/net/802/sysctl_net_802.c
+++ b/net/802/sysctl_net_802.c
@@ -23,5 +23,6 @@ extern int sysctl_tr_rif_timeout;
ctl_table tr_table[] = {
{NET_TR_RIF_TIMEOUT, "rif_timeout", &sysctl_tr_rif_timeout, sizeof(int),
0644, NULL, &proc_dointvec},
+ {0}
};
#endif
diff --git a/net/802/tr.c b/net/802/tr.c
index bf6cd83d7..3550b81ed 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -510,10 +510,18 @@ int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy)
* Called during bootup. We don't actually have to initialise
* too much for this.
*/
-
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry tr_rif_proc = {
+ PROC_NET_TR_RIF, 6, "tr_rif",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rif_get_info
+};
+#endif
+
__initfunc(void rif_init(struct net_proto *unused))
{
-
rif_timer.expires = RIF_TIMEOUT;
rif_timer.data = 0L;
rif_timer.function = rif_check_expire;
@@ -521,11 +529,6 @@ __initfunc(void rif_init(struct net_proto *unused))
add_timer(&rif_timer);
#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_TR_RIF, 6, "tr_rif",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rif_get_info
- });
+ proc_net_register(&tr_rif_proc);
#endif
}
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 8b724361d..c56adc148 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -990,7 +990,7 @@ static int atalk_create(struct socket *sock, int protocol)
{
struct sock *sk;
- sk = sk_alloc(AF_APPLETALK, GFP_KERNEL);
+ sk = sk_alloc(AF_APPLETALK, GFP_KERNEL, 1);
if(sk == NULL)
return (-ENOMEM);
@@ -1404,6 +1404,31 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
return (0);
}
+#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
+ /*
+ * Check if IP-over-DDP
+ */
+ if(skb->data[12] == 22)
+ {
+ struct device *dev;
+
+ /* This needs to be able to handle ipddp"N" devices */
+ if((dev = dev_get("ipddp0")) == NULL)
+ return (-ENODEV);
+
+ skb->protocol = htons(ETH_P_IP);
+ skb_pull(skb, 13);
+ skb->dev = dev;
+ skb->h.raw = skb->data;
+
+ ((struct net_device_stats *)dev->priv)->rx_packets++;
+ ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len+13;
+ netif_rx(skb); /* Send the SKB up to a higher place. */
+
+ return (0);
+ }
+#endif
+
/*
* Which socket - atalk_search_socket() looks for a *full match*
* of the <net,node,port> tuple.
@@ -1420,38 +1445,6 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
return (0);
}
-#ifdef CONFIG_IPDDP
- /*
- * Check if IP-over-DDP
- */
- if(skb->data[12] == 22)
- {
- struct device *dev;
- struct net_device_stats *estats;
-
- if((dev = dev_get("ipddp0")) == NULL)
- return (-ENODEV);
-
- estats = (struct net_device_stats *) dev->priv;
- skb->protocol = htons(ETH_P_IP);
- skb_pull(skb, 13);
- skb->dev = dev;
- skb->h.raw = skb->data;
- skb->nh.raw = skb->data;
-
- /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]);
- * printk("tot_len %d, skb->len %d\n",
- * ntohs(skb->h.iph->tot_len),skb->len);
- */
-
- estats->rx_packets++;
- estats->rx_bytes += skb->len + 13;
- netif_rx(skb); /* Send the SKB up to a higher place. */
-
- return (0);
- }
-#endif /* CONFIG_IPDDP */
-
/*
* Queue packet (standard)
*/
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 3a4196b3f..107f481d6 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -828,7 +828,7 @@ int ax25_create(struct socket *sock, int protocol)
return -ESOCKTNOSUPPORT;
}
- if ((sk = sk_alloc(AF_AX25, GFP_ATOMIC)) == NULL)
+ if ((sk = sk_alloc(AF_AX25, GFP_ATOMIC, 1)) == NULL)
return -ENOMEM;
if ((ax25 = ax25_create_cb()) == NULL) {
@@ -854,7 +854,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
struct sock *sk;
ax25_cb *ax25;
- if ((sk = sk_alloc(AF_AX25, GFP_ATOMIC)) == NULL)
+ if ((sk = sk_alloc(AF_AX25, GFP_ATOMIC, 1)) == NULL)
return NULL;
if ((ax25 = ax25_create_cb()) == NULL) {
@@ -1237,6 +1237,8 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
newsk = skb->sk;
newsk->pair = NULL;
+ newsk->socket = newsock;
+ newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */
diff --git a/net/core/dev.c b/net/core/dev.c
index b06d0053e..36efa363b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -50,6 +50,7 @@
* is no device open function.
* Andi Kleen : Fix error reporting for SIOCGIFCONF
* Michael Chastain : Fix signed/unsigned for SIOCGIFCONF
+ * Cyrus Durgin : Cleaned for KMOD
*
*/
@@ -81,7 +82,7 @@
#include <net/pkt_sched.h>
#include <net/profile.h>
#include <linux/init.h>
-#include <linux/kerneld.h>
+#include <linux/kmod.h>
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
#endif /* CONFIG_NET_RADIO */
@@ -316,7 +317,7 @@ struct device *dev_alloc(const char *name, int *err)
* Find and possibly load an interface.
*/
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
void dev_load(const char *name)
{
@@ -398,20 +399,24 @@ int dev_open(struct device *dev)
}
#ifdef CONFIG_NET_FASTROUTE
-void dev_clear_fastroute(struct device *dev)
+
+static __inline__ void dev_do_clear_fastroute(struct device *dev)
{
- int i;
+ if (dev->accept_fastpath) {
+ int i;
- if (dev) {
for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++)
dst_release(xchg(dev->fastpath+i, NULL));
+ }
+}
+
+void dev_clear_fastroute(struct device *dev)
+{
+ if (dev) {
+ dev_do_clear_fastroute(dev);
} else {
- for (dev = dev_base; dev; dev = dev->next) {
- if (dev->accept_fastpath) {
- for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++)
- dst_release(xchg(dev->fastpath+i, NULL));
- }
- }
+ for (dev = dev_base; dev; dev = dev->next)
+ dev_do_clear_fastroute(dev);
}
}
#endif
@@ -643,7 +648,7 @@ int netdev_register_fc(struct device *dev, void (*stimul)(struct device *dev))
set_bit(bit, &netdev_fc_mask);
clear_bit(bit, &netdev_fc_xoff);
}
- sti();
+ restore_flags(flags);
return bit;
}
@@ -659,7 +664,7 @@ void netdev_unregister_fc(int bit)
clear_bit(bit, &netdev_fc_mask);
clear_bit(bit, &netdev_fc_xoff);
}
- sti();
+ restore_flags(flags);
}
static void netdev_wakeup(void)
@@ -978,39 +983,6 @@ int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
/*
- This ioctl is wrong by design. It really existed in some
- old SYSV systems, only was named SIOCGIFNUM.
- In multiprotocol environment it is just useless.
- Well, SIOCGIFCONF is wrong too, but we have to preserve
- it by compatibility reasons.
-
- If someone wants to achieve the same effect, please, use undocumented
- feature of SIOCGIFCONF: it returns buffer length, if buffer
- is not supplied.
-
- Let's remove it, until someone started to use it. --ANK
-
- In any case, if someone cannot live without it, it should
- be renamed to SIOCGIFNUM.
- */
-
-
-/*
- * Count the installed interfaces (SIOCGIFCOUNT)
- */
-
-static int dev_ifcount(unsigned int *arg)
-{
- struct device *dev;
- unsigned int count = 0;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- count++;
-
- return put_user(count, arg);
-}
-
-/*
* Map an interface index to its name (SIOCGIFNAME)
*/
@@ -1022,6 +994,11 @@ static int dev_ifcount(unsigned int *arg)
* Besides that, it is pretty silly to put "drawing" facility
* to kernel, it is useful only to print ifindices
* in readable form, is not it? --ANK
+ *
+ * We need this ioctl for efficient implementation of the
+ * if_indextoname() function required by the IPv6 API. Without
+ * it, we would have to search all the interfaces to find a
+ * match. --pb
*/
static int dev_ifname(struct ifreq *arg)
@@ -1120,20 +1097,21 @@ static int sprintf_stats(char *buffer, struct device *dev)
int size;
if (stats)
- size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %4lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu %4lu\n",
- dev->name,
+ size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu %4lu\n",
+ dev->name,
stats->rx_bytes,
stats->rx_packets, stats->rx_errors,
stats->rx_dropped + stats->rx_missed_errors,
stats->rx_fifo_errors,
stats->rx_length_errors + stats->rx_over_errors
+ stats->rx_crc_errors + stats->rx_frame_errors,
+ stats->rx_compressed, stats->multicast,
stats->tx_bytes,
stats->tx_packets, stats->tx_errors, stats->tx_dropped,
stats->tx_fifo_errors, stats->collisions,
stats->tx_carrier_errors + stats->tx_aborted_errors
+ stats->tx_window_errors + stats->tx_heartbeat_errors,
- stats->multicast);
+ stats->tx_compressed);
else
size = sprintf(buffer, "%6s: No statistics available.\n", dev->name);
@@ -1156,8 +1134,8 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy
size = sprintf(buffer,
- "Inter-| Receive | Transmit\n"
- " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier multicast\n");
+ "Inter-| Receive | Transmit\n"
+ " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n");
pos+=size;
len+=size;
@@ -1555,9 +1533,6 @@ int dev_ioctl(unsigned int cmd, void *arg)
rtnl_shunlock();
return ret;
}
- if (cmd == SIOCGIFCOUNT) {
- return dev_ifcount((unsigned int*)arg);
- }
if (cmd == SIOCGIFNAME) {
return dev_ifname((struct ifreq *)arg);
}
diff --git a/net/core/dst.c b/net/core/dst.c
index e94ef2967..4cad680c2 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -101,7 +101,7 @@ void * dst_alloc(int size, struct dst_ops * ops)
void __dst_free(struct dst_entry * dst)
{
start_bh_atomic();
- dst->obsolete = 1;
+ dst->obsolete = 2;
dst->next = dst_garbage_list;
dst_garbage_list = dst;
if (dst_gc_timer_inc > DST_GC_INC) {
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 18a9a3b5b..9e8873646 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -80,18 +80,21 @@ out_free:
/*
* Copy kernel to iovec.
+ *
+ * Note: this modifies the original iovec.
*/
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
{
- int err = -EFAULT;
+ int err;
while(len>0)
{
if(iov->iov_len)
{
int copy = min(iov->iov_len, len);
- if (copy_to_user(iov->iov_base, kdata, copy))
+ err = copy_to_user(iov->iov_base, kdata, copy);
+ if (err)
goto out;
kdata+=copy;
len-=copy;
@@ -107,6 +110,8 @@ out:
/*
* Copy iovec to kernel.
+ *
+ * Note: this modifies the original iovec.
*/
int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
@@ -187,9 +192,8 @@ out:
* call to this function will be unaligned also.
*/
-int csum_partial_copy_fromiovecend(unsigned char *kdata,
- struct iovec *iov, int offset,
- unsigned int len, int *csump)
+int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, unsigned int len, int *csump)
{
int partial_cnt = 0;
int err = 0;
@@ -246,9 +250,9 @@ int csum_partial_copy_fromiovecend(unsigned char *kdata,
if (copy_from_user(kdata, base, copy))
goto out_fault;
kdata += copy;
- base += copy;
+ base += copy;
partial_cnt += copy;
- len -= copy;
+ len -= copy;
iov++;
if (len)
continue;
@@ -260,9 +264,9 @@ int csum_partial_copy_fromiovecend(unsigned char *kdata,
goto out_fault;
csum = csum_partial(kdata - partial_cnt, 4, csum);
kdata += par_len;
- base += par_len;
- copy -= par_len;
- len -= par_len;
+ base += par_len;
+ copy -= par_len;
+ len -= par_len;
partial_cnt = 0;
}
@@ -278,16 +282,12 @@ int csum_partial_copy_fromiovecend(unsigned char *kdata,
}
}
- /* Why do we want to break?? There may be more to copy ... */
- if (copy == 0) {
-if (len > partial_cnt)
-printk("csum_iovec: early break? len=%d, partial=%d\n", len, partial_cnt);
- break;
+ if (copy) {
+ csum = csum_and_copy_from_user(base, kdata, copy,
+ csum, &err);
+ if (err)
+ goto out;
}
-
- csum = csum_and_copy_from_user(base, kdata, copy, csum, &err);
- if (err)
- goto out;
len -= copy + partial_cnt;
kdata += copy + partial_cnt;
iov++;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 3de3743e0..a8d72604d 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -153,12 +153,14 @@ int neigh_ifdown(struct neigh_table *tbl, struct device *dev)
static struct neighbour *neigh_alloc(struct neigh_table *tbl, int creat)
{
struct neighbour *n;
+ unsigned long now = jiffies;
if (tbl->entries > tbl->gc_thresh1) {
if (creat < 0)
return NULL;
- if (tbl->entries > tbl->gc_thresh2 ||
- jiffies - tbl->last_flush > 5*HZ) {
+ if (tbl->entries > tbl->gc_thresh3 ||
+ (tbl->entries > tbl->gc_thresh2 &&
+ now - tbl->last_flush > 5*HZ)) {
if (neigh_forced_gc(tbl) == 0 &&
tbl->entries > tbl->gc_thresh3)
return NULL;
@@ -172,7 +174,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, int creat)
memset(n, 0, tbl->entry_size);
skb_queue_head_init(&n->arp_queue);
- n->updated = n->used = jiffies;
+ n->updated = n->used = now;
n->nud_state = NUD_NONE;
n->output = neigh_blackhole;
n->parms = &tbl->parms;
@@ -666,8 +668,18 @@ int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int
neigh_suspect(neigh);
if (!(old&NUD_VALID)) {
struct sk_buff *skb;
- while ((skb=__skb_dequeue(&neigh->arp_queue)) != NULL)
- neigh->output(skb);
+
+ /* Again: avoid dead loop if something went wrong */
+
+ while (neigh->nud_state&NUD_VALID &&
+ (skb=__skb_dequeue(&neigh->arp_queue)) != NULL) {
+ struct neighbour *n1 = neigh;
+ /* On shaper/eql skb->dst->neighbour != neigh :( */
+ if (skb->dst && skb->dst->neighbour)
+ n1 = skb->dst->neighbour;
+ n1->output(skb);
+ }
+ skb_queue_purge(&neigh->arp_queue);
}
return 0;
}
@@ -1228,7 +1240,7 @@ struct neigh_sysctl_table
&proc_dointvec},
{0}},
- {{1, "default", NULL, 0, 0555, NULL},{0}},
+ {{NET_PROTO_CONF_DEFAULT, "default", NULL, 0, 0555, NULL},{0}},
{{0, "neigh", NULL, 0, 0555, NULL},{0}},
{{0, NULL, NULL, 0, 0555, NULL},{0}},
{{CTL_NET, "net", NULL, 0, 0555, NULL},{0}}
@@ -1243,10 +1255,11 @@ int neigh_sysctl_register(struct device *dev, struct neigh_parms *p,
if (t == NULL)
return -ENOBUFS;
memcpy(t, &neigh_sysctl_template, sizeof(*t));
+ t->neigh_vars[0].data = &p->mcast_probes;
t->neigh_vars[1].data = &p->ucast_probes;
t->neigh_vars[2].data = &p->app_probes;
t->neigh_vars[3].data = &p->retrans_time;
- t->neigh_vars[4].data = &p->reachable_time;
+ t->neigh_vars[4].data = &p->base_reachable_time;
t->neigh_vars[5].data = &p->delay_probe_time;
t->neigh_vars[6].data = &p->gc_staletime;
t->neigh_vars[7].data = &p->queue_len;
@@ -1256,7 +1269,7 @@ int neigh_sysctl_register(struct device *dev, struct neigh_parms *p,
t->neigh_vars[11].data = &p->locktime;
if (dev) {
t->neigh_dev[0].procname = dev->name;
- t->neigh_dev[0].ctl_name = dev->ifindex+1;
+ t->neigh_dev[0].ctl_name = dev->ifindex;
memset(&t->neigh_vars[12], 0, sizeof(ctl_table));
} else {
t->neigh_vars[12].data = (&p->locktime) + 1;
diff --git a/net/core/sock.c b/net/core/sock.c
index 6da5f5a0d..f940e5a80 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -137,6 +137,8 @@ __u32 sysctl_wmem_default = SK_WMEM_MAX;
__u32 sysctl_rmem_default = SK_RMEM_MAX;
int sysctl_core_destroy_delay = SOCK_DESTROY_TIME;
+/* Maximal space eaten by iovec (still not made (2.1.88)!) plus some space */
+int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
/*
* This is meant for all protocols to use and covers goings on
@@ -472,11 +474,11 @@ static kmem_cache_t *sk_cachep;
* usage.
*/
-struct sock *sk_alloc(int family, int priority)
+struct sock *sk_alloc(int family, int priority, int zero_it)
{
struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
- if(sk) {
+ if(sk && zero_it) {
memset(sk, 0, sizeof(struct sock));
sk->family = family;
}
@@ -561,34 +563,22 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
void *sock_kmalloc(struct sock *sk, int size, int priority)
{
void *mem = NULL;
- /* Always use wmem.. */
- if (atomic_read(&sk->wmem_alloc)+size < sk->sndbuf) {
+ if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
/* First do the add, to avoid the race if kmalloc
* might sleep.
*/
- atomic_add(size, &sk->wmem_alloc);
+ atomic_add(size, &sk->omem_alloc);
mem = kmalloc(size, priority);
- if (mem)
- return mem;
- atomic_sub(size, &sk->wmem_alloc);
}
return mem;
}
void sock_kfree_s(struct sock *sk, void *mem, int size)
{
-#if 1 /* Debug */
- if (atomic_read(&sk->wmem_alloc) < size) {
- printk(KERN_DEBUG "sock_kfree_s: mem not accounted.\n");
- return;
- }
-#endif
kfree_s(mem, size);
- atomic_sub(size, &sk->wmem_alloc);
- sk->write_space(sk);
+ atomic_sub(size, &sk->omem_alloc);
}
-
/* FIXME: this is insane. We are trying suppose to be controlling how
* how much space we have for data bytes, not packet headers.
* This really points out that we need a better system for doing the
@@ -633,6 +623,30 @@ unsigned long sock_wspace(struct sock *sk)
return(0);
}
+/* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
+ I think, these locks should be removed for datagram sockets.
+ */
+static void sock_wait_for_wmem(struct sock * sk)
+{
+ struct wait_queue wait = { current, NULL };
+
+ sk->socket->flags &= ~SO_NOSPACE;
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ if (signal_pending(current))
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)
+ break;
+ if (sk->shutdown & SEND_SHUTDOWN)
+ break;
+ if (sk->err)
+ break;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+}
/*
@@ -641,94 +655,78 @@ unsigned long sock_wspace(struct sock *sk)
struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode)
{
+ int err;
struct sk_buff *skb;
- do
- {
- if(sk->err!=0)
- {
- *errcode=xchg(&sk->err,0);
- return NULL;
- }
-
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- /*
- * FIXME: Check 1003.1g should we deliver
- * a signal here ???
- */
- *errcode=-EPIPE;
- return NULL;
- }
-
- if(!fallback)
+ do {
+ if ((err = xchg(&sk->err,0)) != 0)
+ goto failure;
+
+ /*
+ * FIXME: Check 1003.1g should we deliver
+ * a signal here ???
+ *
+ * Alan, could we solve this question once and forever?
+ *
+ * I believe, datagram sockets should never
+ * generate SIGPIPE. Moreover, I DO think that
+ * TCP is allowed to generate it only on write()
+ * call, but never on send/sendto/sendmsg.
+ * (btw, Solaris generates it even on read() :-))
+ *
+ * The reason is that SIGPIPE is global flag,
+ * so that library function using sockets (f.e. syslog()),
+ * must save/disable it on entry and restore on exit.
+ * As result, signal arriving for another thread will
+ * be lost. Generation it on write() is still necessary
+ * because a lot of stupid programs never check write()
+ * return value.
+ *
+ * Seems, SIGPIPE is very bad idea, sort of gets().
+ * At least, we could have an option disabling
+ * this behaviour on per-socket and/or per-message base.
+ * BTW it is very easy - MSG_SIGPIPE flag, which
+ * always set by read/write and checked here.
+ * --ANK
+ */
+
+ err = -EPIPE;
+ if (sk->shutdown&SEND_SHUTDOWN)
+ goto failure;
+
+ if (!fallback)
skb = sock_wmalloc(sk, size, 0, sk->allocation);
- else
- {
+ else {
/* The buffer get won't block, or use the atomic queue. It does
produce annoying no free page messages still.... */
skb = sock_wmalloc(sk, size, 0 , GFP_BUFFER);
- if(!skb)
+ if (!skb)
skb=sock_wmalloc(sk, fallback, 0, sk->allocation);
}
-
+
/*
* This means we have too many buffers for this socket already.
*/
-
- if(skb==NULL)
- {
- unsigned long tmp;
+ /* The following code is stolen "as is" from tcp.c */
+
+ if (skb==NULL) {
sk->socket->flags |= SO_NOSPACE;
- if(noblock)
- {
- *errcode=-EAGAIN;
- return NULL;
- }
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- *errcode=-EPIPE;
- return NULL;
- }
- tmp = atomic_read(&sk->wmem_alloc);
- cli();
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- sti();
- *errcode=-EPIPE;
- return NULL;
- }
-
-#if 1
- if( tmp <= atomic_read(&sk->wmem_alloc))
-#else
- /* ANK: Line above seems either incorrect
- * or useless. sk->wmem_alloc has a tiny chance to change
- * between tmp = sk->w... and cli(),
- * but it might(?) change earlier. In real life
- * it does not (I never seen the message).
- * In any case I'd delete this check at all, or
- * change it to:
- */
- if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf)
-#endif
- {
- sk->socket->flags &= ~SO_NOSPACE;
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current))
- {
- sti();
- *errcode = -ERESTARTSYS;
- return NULL;
- }
- }
- sti();
+ err = -EAGAIN;
+ if (noblock)
+ goto failure;
+ err = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto failure;
+ sock_wait_for_wmem(sk);
}
- }
- while(skb==NULL);
-
+ } while (skb==NULL);
+
return skb;
+
+failure:
+ *errcode = err;
+ return NULL;
}
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 1da2cc152..47c85d006 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -22,6 +22,7 @@ extern __u32 sysctl_wmem_default;
extern __u32 sysctl_rmem_default;
extern int sysctl_core_destroy_delay;
+extern int sysctl_optmem_max;
ctl_table core_table[] = {
{NET_CORE_WMEM_MAX, "wmem_max",
@@ -53,6 +54,9 @@ ctl_table core_table[] = {
{NET_CORE_MSG_BURST, "message_burst",
&net_msg_burst, sizeof(int), 0644, NULL,
&proc_dointvec_jiffies},
+ {NET_CORE_OPTMEM_MAX, "optmem_max",
+ &sysctl_optmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
{ 0 }
};
#endif
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 584ad8c7a..ef1c44620 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -5,7 +5,7 @@
*
* AF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.5 1997/12/16 05:37:33 ralf Exp $
+ * Version: $Id: af_inet.c,v 1.6 1998/03/17 22:18:20 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -52,6 +52,7 @@
* Willy Konynenberg : Transparent proxying support.
* David S. Miller : New socket lookup architecture.
* Some other random speedups.
+ * Cyrus Durgin : Cleaned up file for kmod hacks.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -107,8 +108,8 @@
#ifdef CONFIG_BRIDGE
#include <net/br.h>
#endif
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
@@ -327,7 +328,7 @@ static int inet_create(struct socket *sock, int protocol)
static int warned;
if (net_families[AF_PACKET]==NULL)
{
-#if defined(CONFIG_KERNELD) && defined(CONFIG_PACKET_MODULE)
+#if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE)
char module_name[30];
sprintf(module_name,"net-pf-%d", AF_PACKET);
request_module(module_name);
@@ -341,7 +342,7 @@ static int inet_create(struct socket *sock, int protocol)
}
sock->state = SS_UNCONNECTED;
- sk = sk_alloc(AF_INET, GFP_KERNEL);
+ sk = sk_alloc(AF_INET, GFP_KERNEL, 1);
if (sk == NULL)
goto do_oom;
@@ -894,7 +895,7 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCDRARP:
case SIOCGRARP:
case SIOCSRARP:
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (rarp_ioctl_hook == NULL)
request_module("rarp");
#endif
@@ -928,7 +929,7 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_DLCI_MODULE
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
if (dlci_ioctl_hook == NULL)
request_module("dlci");
#endif
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 94ae4263e..dd7ce9e0f 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1,6 +1,6 @@
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.4 1998/03/03 01:23:36 ralf Exp $
+ * Version: $Id: arp.c,v 1.5 1998/03/17 22:18:21 ralf Exp $
*
* Copyright (C) 1994 by Florian La Roche
*
@@ -189,7 +189,7 @@ struct neigh_table arp_tbl =
NULL,
parp_redo,
{ NULL, NULL, &arp_tbl, 0, NULL, NULL,
- 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 1*HZ, 64 },
+ 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ },
30*HZ, 128, 512, 1024,
};
@@ -954,6 +954,10 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy
struct device *dev = n->dev;
int hatype = dev->type;
+ /* Do not confuse users "arp -a" with magic entries */
+ if (!(n->nud_state&~NUD_NOARP))
+ continue;
+
/* I'd get great pleasure deleting
this ugly code. Let's output it in hexadecimal format.
"arp" utility will eventually repaired --ANK
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 7d5f0021f..87394f906 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1,7 +1,7 @@
/*
* NET3 IP device support routines.
*
- * Version: $Id: devinet.c,v 1.3 1997/12/16 05:37:35 ralf Exp $
+ * Version: $Id: devinet.c,v 1.4 1998/03/17 22:18:21 ralf Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,6 +19,7 @@
*
* Changes:
* Alexey Kuznetsov: pa_* fields are replaced with ifaddr lists.
+ Cyrus Durgin: updated for kmod
*/
#include <linux/config.h>
@@ -49,8 +50,8 @@
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
#include <net/ip.h>
@@ -157,28 +158,32 @@ static void
inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
{
struct in_ifaddr *ifa1 = *ifap;
- struct in_ifaddr *ifa;
-
- /* 1. Unlink it */
- *ifap = ifa1->ifa_next;
-
- /* 2. Deleting primary ifaddr forces deletion all secondaries */
+ /* 1. Deleting primary ifaddr forces deletion all secondaries */
if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) {
- while ((ifa=*ifap) != NULL) {
- if (ifa1->ifa_mask != ifa->ifa_mask ||
+ struct in_ifaddr *ifa;
+ struct in_ifaddr **ifap1 = &ifa1->ifa_next;
+
+ while ((ifa=*ifap1) != NULL) {
+ if (!(ifa->ifa_flags&IFA_F_SECONDARY) ||
+ ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa)) {
- ifap = &ifa->ifa_next;
+ ifap1 = &ifa->ifa_next;
continue;
}
- *ifap = ifa->ifa_next;
+ *ifap1 = ifa->ifa_next;
rtmsg_ifa(RTM_DELADDR, ifa);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
inet_free_ifa(ifa);
}
}
+ /* 2. Unlink it */
+
+ *ifap = ifa1->ifa_next;
+
+
/* 3. Announce address deletion */
/* Send message first, then call notifier.
@@ -232,10 +237,9 @@ inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa)
ifap = last_primary;
}
- cli();
ifa->ifa_next = *ifap;
+ /* ATOMIC_SET */
*ifap = ifa;
- sti();
/* Send message first, then call notifier.
Notifier will trigger FIB update, so that
@@ -413,7 +417,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
*colon = 0;
#endif
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
dev_load(ifr.ifr_name);
#endif
@@ -960,6 +964,8 @@ static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devcon
t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
if (t->sysctl_header == NULL)
kfree(t);
+ else
+ p->sysctl = t;
}
static void devinet_sysctl_unregister(struct ipv4_devconf *p)
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 409db8209..6350a6366 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -5,7 +5,7 @@
*
* IPv4 Forwarding Information Base: FIB frontend.
*
- * Version: $Id: fib_frontend.c,v 1.6 1997/12/13 21:52:48 kuznet Exp $
+ * Version: $Id: fib_frontend.c,v 1.9 1998/03/08 20:52:36 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
@@ -151,7 +151,6 @@ struct device * ip_dev_find(u32 addr)
memset(&key, 0, sizeof(key));
key.dst = addr;
- key.scope = RT_SCOPE_UNIVERSE;
if (!local_table || local_table->tb_lookup(local_table, &key, &res)
|| res.type != RTN_LOCAL)
@@ -344,6 +343,10 @@ int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
int s_t;
struct fib_table *tb;
+ if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
+ ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
+ return ip_rt_dump(skb, cb);
+
s_t = cb->args[0];
if (s_t == 0)
s_t = cb->args[0] = RT_TABLE_MIN;
@@ -423,8 +426,13 @@ static void fib_add_ifaddr(struct in_ifaddr *ifa)
u32 addr = ifa->ifa_local;
u32 prefix = ifa->ifa_address&mask;
- if (ifa->ifa_flags&IFA_F_SECONDARY)
+ if (ifa->ifa_flags&IFA_F_SECONDARY) {
prim = inet_ifa_byprefix(in_dev, prefix, mask);
+ if (prim == NULL) {
+ printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
+ return;
+ }
+ }
fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
@@ -435,7 +443,8 @@ static void fib_add_ifaddr(struct in_ifaddr *ifa)
if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
- if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY)) {
+ if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+ (prefix != addr || ifa->ifa_prefixlen < 32)) {
fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
@@ -464,8 +473,13 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
if (!(ifa->ifa_flags&IFA_F_SECONDARY))
fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
- else
+ else {
prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
+ if (prim == NULL) {
+ printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
+ return;
+ }
+ }
/* Deletion is more complicated than add.
We should take care of not to delete too much :-)
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 33bcf0321..4b89ab676 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -5,7 +5,7 @@
*
* IPv4 FIB: lookup engine and maintenance routines.
*
- * Version: $Id: fib_hash.c,v 1.1 1997/11/09 19:53:13 kuznet Exp $
+ * Version: $Id: fib_hash.c,v 1.3 1998/03/08 05:56:16 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 3ffb404b5..7ec60a5be 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -5,7 +5,7 @@
*
* IPv4 Forwarding Information Base: policy rules.
*
- * Version: $Id: fib_rules.c,v 1.2 1997/10/10 22:40:49 davem Exp $
+ * Version: $Id: fib_rules.c,v 1.3 1998/03/08 05:56:17 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 3883fcba0..d2d37e11e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -5,7 +5,7 @@
*
* IPv4 Forwarding Information Base: semantics.
*
- * Version: $Id: fib_semantics.c,v 1.6 1997/12/13 21:52:49 kuznet Exp $
+ * Version: $Id: fib_semantics.c,v 1.7 1998/03/08 05:56:18 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index b2c7151d1..e8f636e21 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@cymru.net>
*
- * Version: $Id: icmp.c,v 1.4 1998/03/03 01:23:37 ralf Exp $
+ * Version: $Id: icmp.c,v 1.5 1998/03/17 22:18:23 ralf Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -928,10 +928,8 @@ int icmp_chkaddr(struct sk_buff *skb)
struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
- if (!sk) return 0;
- if (sk->saddr != iph->saddr) return 0;
- if (sk->daddr != iph->daddr) return 0;
- if (sk->dummy_th.dest != th->dest) return 0;
+ if (!sk || (sk->state == TCP_LISTEN))
+ return 0;
/*
* This packet came from us.
*/
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 166b68b42..d3414a0fe 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -8,7 +8,7 @@
* the older version didn't come out right using gcc 2.5.8, the newer one
* seems to fall out with gcc 2.6.2.
*
- * Version: $Id: igmp.c,v 1.3 1997/12/16 05:37:36 ralf Exp $
+ * Version: $Id: igmp.c,v 1.4 1998/03/17 22:18:24 ralf Exp $
*
* Authors:
* Alan Cox <Alan.Cox@linux.org>
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 45a2ed588..8df8414cd 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -5,7 +5,7 @@
*
* The IP forwarding functionality.
*
- * Version: $Id: ip_forward.c,v 1.3 1998/03/03 01:23:37 ralf Exp $
+ * Version: $Id: ip_forward.c,v 1.4 1998/03/17 22:18:25 ralf Exp $
*
* Authors: see ip.c
*
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 9dccb5324..e6831adb8 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,7 +5,7 @@
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.30 1997/12/29 19:52:32 kuznet Exp $
+ * Version: $Id: ip_fragment.c,v 1.32 1998/03/08 05:56:21 davem Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c
index d78aa0f66..4eb41c325 100644
--- a/net/ipv4/ip_fw.c
+++ b/net/ipv4/ip_fw.c
@@ -6,7 +6,7 @@
* license in recognition of the original copyright.
* -- Alan Cox.
*
- * $Id: ip_fw.c,v 1.3 1997/12/16 05:37:37 ralf Exp $
+ * $Id: ip_fw.c,v 1.4 1998/03/17 22:18:25 ralf Exp $
*
* Ported from BSD to Linux,
* Alan Cox 22/Nov/1994.
@@ -392,6 +392,39 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_
continue; /* Mismatch */
}
+ /* This looks stupid, because we scan almost static
+ list, searching for static key. However, this way seems
+ to be only reasonable way of handling fw_via rules
+ (btw bsd makes the same thing).
+
+ It will not affect performance if you will follow
+ the following simple rules:
+
+ - if inteface is aliased, ALWAYS specify fw_viadev,
+ so that previous check will guarantee, that we will
+ not waste time when packet arrive on another interface.
+
+ - avoid using fw_via.s_addr if fw_via.s_addr is owned
+ by an aliased interface.
+
+ --ANK
+ */
+ if (f->fw_via.s_addr && rif) {
+ struct in_ifaddr *ifa;
+
+ if (rif->ip_ptr == NULL)
+ continue; /* Mismatch */
+
+ for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list;
+ ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_local == f->fw_via.s_addr)
+ goto ifa_ok;
+ }
+ continue; /* Mismatch */
+
+ ifa_ok:
+ }
+
/*
* Ok the chain addresses match.
*/
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 61c364542..fa8208959 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.2 1997/12/16 05:37:38 ralf Exp $
+ * Version: $Id: ip_input.c,v 1.3 1998/03/17 22:18:26 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff --git a/net/ipv4/ip_masq_mod.c b/net/ipv4/ip_masq_mod.c
index 797f9112f..2265161f3 100644
--- a/net/ipv4/ip_masq_mod.c
+++ b/net/ipv4/ip_masq_mod.c
@@ -12,6 +12,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Changes:
+ * Cyrus Durgin: fixed kerneld stuff for kmod.
*/
#include <linux/config.h>
@@ -21,8 +23,8 @@
#include <linux/errno.h>
#include <net/ip_masq.h>
#include <net/ip_masq_mod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
#endif
EXPORT_SYMBOL(register_ip_masq_mod);
@@ -290,7 +292,7 @@ struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
{
struct ip_masq_mod * mmod;
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
char kmod_name[IP_MASQ_MOD_NMAX+8];
#endif
/* tappo */
@@ -299,7 +301,7 @@ int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
if (mmod)
return mmod->mmod_ctl(optname, mctl, optlen);
-#ifdef CONFIG_KERNELD
+#ifdef CONFIG_KMOD
sprintf(kmod_name,"ip_masq_%s", mctl->u.mod.name);
IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
diff --git a/net/ipv4/ip_masq_raudio.c b/net/ipv4/ip_masq_raudio.c
index f7e28f21a..377b8223e 100644
--- a/net/ipv4/ip_masq_raudio.c
+++ b/net/ipv4/ip_masq_raudio.c
@@ -2,7 +2,7 @@
* IP_MASQ_RAUDIO - Real Audio masquerading module
*
*
- * Version: @(#)$Id: ip_masq_raudio.c,v 1.8 1997/11/28 15:32:32 alan Exp $
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.9 1998/02/23 02:50:19 davem Exp $
*
* Author: Nigel Metheringham
* Real Time Streaming code by Progressive Networks
diff --git a/net/ipv4/ip_nat_dumb.c b/net/ipv4/ip_nat_dumb.c
index 06e9be8fb..def66858c 100644
--- a/net/ipv4/ip_nat_dumb.c
+++ b/net/ipv4/ip_nat_dumb.c
@@ -5,7 +5,7 @@
*
* Dumb Network Address Translation.
*
- * Version: $Id: ip_nat_dumb.c,v 1.2 1997/10/10 22:41:05 davem Exp $
+ * Version: $Id: ip_nat_dumb.c,v 1.2 1997/12/16 05:37:40 ralf Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
@@ -14,6 +14,9 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Fixes:
+ * Rani Assaf : A zero checksum is a special case
+ * only in UDP
*
* NOTE: It is just working model of real NAT.
*/
@@ -49,7 +52,6 @@ ip_do_nat(struct sk_buff *skb)
u32 odaddr = iph->daddr;
u32 osaddr = iph->saddr;
u16 check;
- u16 *cksum = NULL;
IPCB(skb)->flags |= IPSKB_TRANSLATED;
@@ -62,17 +64,23 @@ ip_do_nat(struct sk_buff *skb)
/* If it is the first fragment, rewrite protocol headers */
if (!(iph->frag_off & htons(IP_OFFSET))) {
- /* Only plain TCP/UDP headers rewriting is implemented :-( */
- if (iph->protocol == IPPROTO_TCP)
- cksum = (u16*)&((struct tcphdr*)(((char*)iph) + iph->ihl*4))->check;
- else if (iph->protocol == IPPROTO_UDP)
- cksum = (u16*)&((struct udphdr*)(((char*)iph) + iph->ihl*4))->check;
- if (cksum && (check = *cksum) != 0) {
- check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
- check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
- if (!check)
- check = 0xFFFF;
- *cksum = check;
+ u16 *cksum;
+
+ switch(iph->protocol) {
+ case IPPROTO_TCP:
+ cksum = (u16*)&((struct tcphdr*)(((char*)iph) + iph->ihl*4))->check;
+ check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum));
+ *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+ break;
+ case IPPROTO_UDP:
+ cksum = (u16*)&((struct udphdr*)(((char*)iph) + iph->ihl*4))->check;
+ if ((check = *cksum) != 0) {
+ check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
+ check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+ *cksum = check ? : 0xFFFF;
+ }
+ default:
+ break;
}
}
return 0;
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 53c680eed..d78cc1ff0 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -5,7 +5,7 @@
*
* The options processing module for ip.c
*
- * Version: $Id: ip_options.c,v 1.2 1997/12/16 05:37:40 ralf Exp $
+ * Version: $Id: ip_options.c,v 1.3 1998/03/17 22:18:28 ralf Exp $
*
* Authors: A.N.Kuznetsov
*
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index ac4ac22ae..63fbbfe1e 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.4 1998/03/03 01:23:41 ralf Exp $
+ * Version: $Id: ip_output.c,v 1.5 1998/03/17 22:18:29 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index a500a72e5..1b7f44e8f 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -5,7 +5,7 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.4 1998/03/03 01:23:41 ralf Exp $
+ * Version: $Id: ip_sockglue.c,v 1.5 1998/03/17 22:18:29 ralf Exp $
*
* Authors: see ip.c
*
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 20521e643..1e44ae8aa 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1,5 +1,5 @@
/*
- * $Id: ipconfig.c,v 1.6 1998/01/09 17:19:46 mj Exp $
+ * $Id: ipconfig.c,v 1.11 1998/02/12 07:43:16 davem Exp $
*
* Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
* information to configure own IP address and routes.
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 949661f41..ce071d406 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,7 +1,7 @@
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.4 1997/12/16 05:37:42 ralf Exp $
+ * Version: $Id: ipip.c,v 1.5 1998/03/17 22:18:30 ralf Exp $
*
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index d3c07dca3..1177f33ac 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -9,7 +9,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.29 1997/12/13 21:52:55 kuznet Exp $
+ * Version: $Id: ipmr.c,v 1.4 1998/03/17 22:18:31 ralf Exp $
*
* Fixes:
* Michael Chastain : Incorrect size of copying.
@@ -1351,6 +1351,7 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
int ct;
struct rtnexthop *nhp;
struct device *dev = vif_table[c->mfc_parent].dev;
+ u8 *b = skb->tail;
#ifdef CONFIG_RTNL_OLD_IFINFO
if (dev) {
@@ -1389,10 +1390,11 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
return 1;
rtattr_failure:
+ skb_trim(skb, b - skb->data);
return -EMSGSIZE;
}
-int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm)
+int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
{
struct mfc_cache *cache;
struct rtable *rt = (struct rtable*)skb->dst;
@@ -1400,10 +1402,16 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm)
start_bh_atomic();
cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) {
- struct device *dev = skb->dev;
+ struct device *dev;
int vif;
int err;
+ if (nowait) {
+ end_bh_atomic();
+ return -EAGAIN;
+ }
+
+ dev = skb->dev;
if (dev == NULL || (vif = ipmr_find_vif(dev)) == ALL_VIFS) {
end_bh_atomic();
return -ENODEV;
@@ -1422,7 +1430,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm)
*/
end_bh_atomic();
- if (rtm->rtm_flags & RTM_F_NOTIFY)
+ if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
cache->mfc_flags |= MFC_NOTIFY;
return ipmr_fill_mroute(skb, cache, rtm);
}
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 7f3b5f9bb..221207205 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: $Id: proc.c,v 1.23 1997/10/30 23:52:20 davem Exp $
+ * Version: $Id: proc.c,v 1.4 1997/12/16 05:37:43 ralf Exp $
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -77,11 +77,12 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
unsigned long dest, src;
unsigned short destp, srcp;
int timer_active, timer_active1, timer_active2;
+ int tw_bucket = 0;
unsigned long timer_expires;
struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
dest = sp->daddr;
- src = sp->saddr;
+ src = sp->rcv_saddr;
destp = sp->dummy_th.dest;
srcp = sp->dummy_th.source;
@@ -96,30 +97,47 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
destp = ntohs(destp);
srcp = ntohs(srcp);
- timer_active1 = del_timer(&tp->retransmit_timer);
- timer_active2 = del_timer(&sp->timer);
- if (!timer_active1) tp->retransmit_timer.expires=0;
- if (!timer_active2) sp->timer.expires=0;
- timer_active=0;
- timer_expires=(unsigned)-1;
+ if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
+
+ tw_bucket = 1;
+ timer_active1 = timer_active2 = 0;
+ timer_active = 3;
+ timer_expires = tw->timer.expires;
+ } else {
+ timer_active1 = del_timer(&tp->retransmit_timer);
+ timer_active2 = del_timer(&sp->timer);
+ if (!timer_active1) tp->retransmit_timer.expires=0;
+ if (!timer_active2) sp->timer.expires=0;
+ timer_active = 0;
+ timer_expires = (unsigned) -1;
+ }
if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
- timer_active=timer_active1;
- timer_expires=tp->retransmit_timer.expires;
+ timer_active = 1;
+ timer_expires = tp->retransmit_timer.expires;
}
if (timer_active2 && sp->timer.expires < timer_expires) {
- timer_active=timer_active2;
- timer_expires=sp->timer.expires;
- }
+ timer_active = 2;
+ timer_expires = sp->timer.expires;
+ }
+ if(timer_active == 0)
+ timer_expires = jiffies;
sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
i, src, srcp, dest, destp, sp->state,
- format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc),
- format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc),
- timer_active, timer_expires-jiffies,
- tp->retransmits,
- sp->socket ? sp->socket->inode->i_uid:0,
- timer_active?sp->timeout:0,
- sp->socket ? sp->socket->inode->i_ino:0);
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
+ timer_active, timer_expires-jiffies,
+ (tw_bucket ? 0 : tp->retransmits),
+ (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
+ (!tw_bucket && timer_active) ? sp->timeout : 0,
+ (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
if (timer_active1) add_timer(&tp->retransmit_timer);
if (timer_active2) add_timer(&sp->timer);
diff --git a/net/ipv4/rarp.c b/net/ipv4/rarp.c
index 9e944495f..e1eba43c5 100644
--- a/net/ipv4/rarp.c
+++ b/net/ipv4/rarp.c
@@ -3,7 +3,7 @@
* Copyright (C) 1994 by Ross Martin
* Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
*
- * $Id: rarp.c,v 1.3 1997/12/16 05:37:44 ralf Exp $
+ * $Id: rarp.c,v 1.4 1998/03/17 22:18:31 ralf Exp $
*
* This module implements the Reverse Address Resolution Protocol
* (RARP, RFC 903), which is used to convert low level addresses such
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index b3644f10d..baebab777 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -5,7 +5,7 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.3 1997/12/16 05:37:44 ralf Exp $
+ * Version: $Id: raw.c,v 1.4 1998/03/17 22:18:32 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index b73c3ed11..8ce4a95f4 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -5,7 +5,7 @@
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.4 1998/03/03 01:23:42 ralf Exp $
+ * Version: $Id: route.c,v 1.5 1998/03/17 22:18:32 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -167,7 +167,7 @@ __u8 ip_tos2prio[16] = {
static struct rtable *rt_hash_table[RT_HASH_DIVISOR];
-static struct rtable * rt_intern_hash(unsigned hash, struct rtable * rth, u16 protocol);
+static struct rtable * rt_intern_hash(unsigned hash, struct rtable * rth);
static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
{
@@ -301,6 +301,8 @@ static void rt_run_flush(unsigned long dummy)
int i;
struct rtable * rth, * next;
+ rt_deadline = 0;
+
for (i=0; i<RT_HASH_DIVISOR; i++) {
int nr=0;
@@ -322,37 +324,41 @@ static void rt_run_flush(unsigned long dummy)
void rt_cache_flush(int delay)
{
+ unsigned long now = jiffies;
+ int user_mode = !in_interrupt();
+
if (delay < 0)
delay = ip_rt_min_delay;
start_bh_atomic();
if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
- long tmo = (long)(rt_deadline - rt_flush_timer.expires);
+ long tmo = (long)(rt_deadline - now);
/* If flush timer is already running
and flush request is not immediate (delay > 0):
- if deadline is not achieved, prolongate timer to "dealy",
+ if deadline is not achieved, prolongate timer to "delay",
otherwise fire it at deadline time.
*/
+ if (user_mode && (long)(rt_deadline-now) < ip_rt_max_delay-ip_rt_min_delay)
+ tmo = 0;
+
if (delay > tmo)
delay = tmo;
}
if (delay <= 0) {
- rt_deadline = 0;
end_bh_atomic();
-
rt_run_flush(0);
return;
}
if (rt_deadline == 0)
- rt_deadline = jiffies + ip_rt_max_delay;
+ rt_deadline = now + ip_rt_max_delay;
- rt_flush_timer.expires = jiffies + delay;
+ rt_flush_timer.expires = now + delay;
add_timer(&rt_flush_timer);
end_bh_atomic();
}
@@ -400,7 +406,7 @@ out:
return (atomic_read(&ipv4_dst_ops.entries) > ip_rt_max_size);
}
-static struct rtable *rt_intern_hash(unsigned hash, struct rtable * rt, u16 protocol)
+static struct rtable *rt_intern_hash(unsigned hash, struct rtable * rt)
{
struct rtable *rth, **rthp;
unsigned long now = jiffies;
@@ -472,7 +478,9 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
goto reject_redirect;
if (!IN_DEV_SHARED_MEDIA(in_dev)) {
- if (ip_fib_check_default(new_gw, dev))
+ if (!inet_addr_onlink(in_dev, new_gw, old_gw))
+ goto reject_redirect;
+ if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
goto reject_redirect;
} else {
if (inet_addr_type(new_gw) != RTN_UNICAST)
@@ -504,9 +512,13 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
rth->u.dst.dev != dev)
break;
+ dst_clone(&rth->u.dst);
+
rt = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
- if (rt == NULL)
+ if (rt == NULL) {
+ ip_rt_put(rth);
return;
+ }
/*
* Copy all the information.
@@ -531,14 +543,16 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
if (rt->u.dst.neighbour)
neigh_event_send(rt->u.dst.neighbour, NULL);
ip_rt_put(rt);
+ ip_rt_put(rth);
rt_free(rt);
break;
}
*rthp = rth->u.rt_next;
- rt_free(rth);
- rt = rt_intern_hash(hash, rt, ETH_P_IP);
+ rt = rt_intern_hash(hash, rt);
ip_rt_put(rt);
+ ip_rt_put(rth);
+ rt_free(rth);
break;
}
}
@@ -762,19 +776,45 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
u32 src;
struct fib_result res;
- if (rt->key.iif == 0) {
- memcpy(addr, &rt->rt_src, 4);
- return;
- }
- if (fib_lookup(&rt->key, &res) == 0) {
+ if (rt->key.iif == 0)
+ src = rt->rt_src;
+ else if (fib_lookup(&rt->key, &res) == 0)
src = FIB_RES_PREFSRC(res);
- memcpy(addr, &src, 4);
- return;
- }
- src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+ else
+ src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
memcpy(addr, &src, 4);
}
+static void rt_set_nexthop(struct rtable *rt, struct fib_result *res)
+{
+ struct fib_info *fi = res->fi;
+
+ if (fi) {
+ if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
+ rt->rt_gateway = FIB_RES_GW(*res);
+#ifndef CONFIG_RTNL_OLD_IFINFO
+ rt->u.dst.mxlock = fi->fib_metrics[RTAX_LOCK-1];
+ rt->u.dst.pmtu = fi->fib_mtu;
+ if (fi->fib_mtu == 0) {
+ rt->u.dst.pmtu = rt->u.dst.dev->mtu;
+ if (rt->u.dst.mxlock&(1<<RTAX_MTU) &&
+ rt->rt_gateway != rt->rt_dst &&
+ rt->u.dst.pmtu > 576)
+ rt->u.dst.pmtu = 576;
+ }
+#else
+ rt->u.dst.pmtu = fi->fib_mtu ? : rt->u.dst.dev->mtu;
+#endif
+ rt->u.dst.window= fi->fib_window ? : 0;
+ rt->u.dst.rtt = fi->fib_rtt ? : TCP_TIMEOUT_INIT;
+ } else {
+ rt->u.dst.pmtu = rt->u.dst.dev->mtu;
+ rt->u.dst.window= 0;
+ rt->u.dst.rtt = TCP_TIMEOUT_INIT;
+ }
+ rt->rt_type = res->type;
+}
+
static int
ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
u8 tos, struct device *dev, int our)
@@ -832,7 +872,7 @@ ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
#endif
hash = rt_hash_code(daddr, saddr^(dev->ifindex<<5), tos);
- skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth, 0);
+ skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
return 0;
}
@@ -990,18 +1030,9 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
rth->u.dst.input = ip_forward;
rth->u.dst.output = ip_output;
- rth->u.dst.pmtu = res.fi->fib_mtu ? : out_dev->dev->mtu;
- rth->u.dst.window=res.fi->fib_window ? : 0;
- rth->u.dst.rtt = res.fi->fib_rtt ? : TCP_TIMEOUT_INIT;
-#ifndef CONFIG_RTNL_OLD_IFINFO
- rth->u.dst.mxlock = res.fi->fib_metrics[RTAX_LOCK-1];
-#endif
-
- if (FIB_RES_GW(res) && FIB_RES_NH(res).nh_scope == RT_SCOPE_LINK)
- rth->rt_gateway = FIB_RES_GW(res);
+ rt_set_nexthop(rth, &res);
rth->rt_flags = flags;
- rth->rt_type = res.type;
#ifdef CONFIG_NET_FASTROUTE
if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
@@ -1014,7 +1045,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
}
#endif
- skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth, ntohs(skb->protocol));
+ skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
return 0;
brd_input:
@@ -1062,7 +1093,7 @@ local_input:
}
rth->rt_flags = flags|RTCF_LOCAL;
rth->rt_type = res.type;
- skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth, 0);
+ skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
return 0;
no_route:
@@ -1362,7 +1393,7 @@ make_route:
rth->rt_dst_map = key.dst;
rth->rt_src_map = key.src;
#endif
- rth->rt_iif = dev_out->ifindex;
+ rth->rt_iif = oif ? : dev_out->ifindex;
rth->u.dst.dev = dev_out;
rth->rt_gateway = key.dst;
rth->rt_spec_dst= key.src;
@@ -1388,24 +1419,12 @@ make_route:
#endif
}
- if (res.fi) {
- if (FIB_RES_GW(res) && FIB_RES_NH(res).nh_scope == RT_SCOPE_LINK)
- rth->rt_gateway = FIB_RES_GW(res);
- rth->u.dst.pmtu = res.fi->fib_mtu ? : dev_out->mtu;
- rth->u.dst.window=res.fi->fib_window ? : 0;
- rth->u.dst.rtt = res.fi->fib_rtt ? : TCP_TIMEOUT_INIT;
-#ifndef CONFIG_RTNL_OLD_IFINFO
- rth->u.dst.mxlock = res.fi->fib_metrics[RTAX_LOCK-1];
-#endif
- } else {
- rth->u.dst.pmtu = dev_out->mtu;
- rth->u.dst.window=0;
- rth->u.dst.rtt = TCP_TIMEOUT_INIT;
- }
+ rt_set_nexthop(rth, &res);
+
rth->rt_flags = flags;
- rth->rt_type = res.type;
+
hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
- *rp = rt_intern_hash(hash, rth, ETH_P_IP);
+ *rp = rt_intern_hash(hash, rth);
return 0;
}
@@ -1444,6 +1463,113 @@ int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
#ifdef CONFIG_RTNETLINK
+static int rt_fill_info(struct sk_buff *skb, pid_t pid, u32 seq, int event, int nowait)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtmsg *r;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+ struct rta_cacheinfo ci;
+#ifdef CONFIG_IP_MROUTE
+ struct rtattr *eptr;
+#endif
+#ifdef CONFIG_RTNL_OLD_IFINFO
+ unsigned char *o;
+#else
+ struct rtattr *mx;
+#endif
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r));
+ r = NLMSG_DATA(nlh);
+ nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;
+ r->rtm_family = AF_INET;
+ r->rtm_dst_len = 32;
+ r->rtm_src_len = 32;
+ r->rtm_tos = rt->key.tos;
+ r->rtm_table = RT_TABLE_MAIN;
+ r->rtm_type = rt->rt_type;
+ r->rtm_scope = RT_SCOPE_UNIVERSE;
+ r->rtm_protocol = RTPROT_UNSPEC;
+ r->rtm_flags = (rt->rt_flags&~0xFFFF) | RTM_F_CLONED;
+#ifdef CONFIG_RTNL_OLD_IFINFO
+ r->rtm_nhs = 0;
+
+ o = skb->tail;
+#endif
+ RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
+ RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src);
+ if (rt->u.dst.dev)
+ RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+ if (rt->rt_dst != rt->rt_gateway)
+ RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
+#ifdef CONFIG_RTNL_OLD_IFINFO
+ RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
+ RTA_PUT(skb, RTA_WINDOW, sizeof(unsigned), &rt->u.dst.window);
+ RTA_PUT(skb, RTA_RTT, sizeof(unsigned), &rt->u.dst.rtt);
+#else
+ mx = (struct rtattr*)skb->tail;
+ RTA_PUT(skb, RTA_METRICS, 0, NULL);
+ if (rt->u.dst.mxlock)
+ RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock);
+ if (rt->u.dst.pmtu)
+ RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
+ if (rt->u.dst.window)
+ RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window);
+ if (rt->u.dst.rtt)
+ RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);
+ mx->rta_len = skb->tail - (u8*)mx;
+ if (mx->rta_len == RTA_LENGTH(0))
+ skb_trim(skb, (u8*)mx - skb->data);
+#endif
+ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
+ ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
+ ci.rta_used = atomic_read(&rt->u.dst.refcnt);
+ ci.rta_clntref = atomic_read(&rt->u.dst.use);
+ ci.rta_expires = 0;
+ ci.rta_error = rt->u.dst.error;
+#ifdef CONFIG_IP_MROUTE
+ eptr = (struct rtattr*)skb->tail;
+#endif
+ RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+#ifdef CONFIG_RTNL_OLD_IFINFO
+ r->rtm_optlen = skb->tail - o;
+#endif
+ if (rt->key.iif) {
+#ifdef CONFIG_IP_MROUTE
+ u32 dst = rt->rt_dst;
+
+ if (MULTICAST(dst) && !LOCAL_MCAST(dst) && ipv4_devconf.mc_forwarding) {
+ int err = ipmr_get_route(skb, r, nowait);
+ if (err <= 0) {
+ if (!nowait) {
+ if (err == 0)
+ return 0;
+ goto nlmsg_failure;
+ } else {
+ if (err == -EMSGSIZE)
+ goto nlmsg_failure;
+ ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err;
+ }
+ }
+ } else
+#endif
+ {
+ RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif);
+#ifdef CONFIG_RTNL_OLD_IFINFO
+ r->rtm_optlen = skb->tail - o;
+#endif
+ }
+ }
+
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{
struct rtattr **rta = arg;
@@ -1454,12 +1580,6 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
int iif = 0;
int err;
struct sk_buff *skb;
- struct rta_cacheinfo ci;
-#ifdef CONFIG_RTNL_OLD_IFINFO
- unsigned char *o;
-#else
- struct rtattr *mx;
-#endif
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
@@ -1506,83 +1626,53 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY;
- nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
- RTM_NEWROUTE, sizeof(*rtm));
- rtm = NLMSG_DATA(nlh);
- nlh->nlmsg_flags = 0;
- rtm->rtm_family = AF_INET;
- rtm->rtm_dst_len = 32;
- rtm->rtm_src_len = 32;
- rtm->rtm_tos = rt->key.tos;
- rtm->rtm_table = RT_TABLE_MAIN;
- rtm->rtm_type = rt->rt_type;
- rtm->rtm_scope = RT_SCOPE_UNIVERSE;
- rtm->rtm_protocol = RTPROT_UNSPEC;
- rtm->rtm_flags = (rt->rt_flags&~0xFFFF) | RTM_F_CLONED;
-#ifdef CONFIG_RTNL_OLD_IFINFO
- rtm->rtm_nhs = 0;
+ NETLINK_CB(skb).pid = NETLINK_CB(in_skb).pid;
+
+ err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0);
+ if (err == 0)
+ return 0;
+ if (err < 0)
+ return -EMSGSIZE;
- o = skb->tail;
-#endif
- RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
- RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src);
- if (rt->u.dst.dev)
- RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
- if (rt->rt_dst != rt->rt_gateway)
- RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
-#ifdef CONFIG_RTNL_OLD_IFINFO
- RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
- RTA_PUT(skb, RTA_WINDOW, sizeof(unsigned), &rt->u.dst.window);
- RTA_PUT(skb, RTA_RTT, sizeof(unsigned), &rt->u.dst.rtt);
-#else
- mx = (struct rtattr*)skb->tail;
- RTA_PUT(skb, RTA_METRICS, 0, NULL);
- if (rt->u.dst.mxlock)
- RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock);
- if (rt->u.dst.pmtu)
- RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
- if (rt->u.dst.window)
- RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window);
- if (rt->u.dst.rtt)
- RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);
- mx->rta_len = skb->tail - (u8*)mx;
-#endif
- RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
- ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
- ci.rta_used = atomic_read(&rt->u.dst.refcnt);
- ci.rta_clntref = atomic_read(&rt->u.dst.use);
- ci.rta_expires = 0;
- ci.rta_error = rt->u.dst.error;
- RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
-#ifdef CONFIG_RTNL_OLD_IFINFO
- rtm->rtm_optlen = skb->tail - o;
-#endif
- if (iif) {
-#ifdef CONFIG_IP_MROUTE
- if (MULTICAST(dst) && !LOCAL_MCAST(dst) && ipv4_devconf.mc_forwarding) {
- NETLINK_CB(skb).pid = NETLINK_CB(in_skb).pid;
- err = ipmr_get_route(skb, rtm);
- if (err <= 0)
- return err;
- } else
-#endif
- {
- RTA_PUT(skb, RTA_IIF, sizeof(int), &iif);
-#ifdef CONFIG_RTNL_OLD_IFINFO
- rtm->rtm_optlen = skb->tail - o;
-#endif
- }
- }
- nlh->nlmsg_len = skb->tail - (u8*)nlh;
err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
if (err < 0)
return err;
return 0;
+}
-nlmsg_failure:
-rtattr_failure:
- kfree_skb(skb);
- return -EMSGSIZE;
+
+int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct rtable *rt;
+ int h, s_h;
+ int idx, s_idx;
+
+ s_h = cb->args[0];
+ s_idx = idx = cb->args[1];
+ for (h=0; h < RT_HASH_DIVISOR; h++) {
+ if (h < s_h) continue;
+ if (h > s_h)
+ memset(&cb->args[1], 0, sizeof(cb->args) - sizeof(int));
+ start_bh_atomic();
+ for (rt = rt_hash_table[h], idx = 0; rt; rt = rt->u.rt_next, idx++) {
+ if (idx < s_idx)
+ continue;
+ skb->dst = dst_clone(&rt->u.dst);
+ if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {
+ dst_release(xchg(&skb->dst, NULL));
+ end_bh_atomic();
+ goto done;
+ }
+ dst_release(xchg(&skb->dst, NULL));
+ }
+ end_bh_atomic();
+ }
+
+done:
+ cb->args[0] = h;
+ cb->args[1] = idx;
+ return skb->len;
}
#endif /* CONFIG_RTNETLINK */
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 7d119716e..00dd0a8ef 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -9,7 +9,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: syncookies.c,v 1.3 1997/09/16 17:16:21 freitag Exp $
+ * $Id: syncookies.c,v 1.4 1998/03/08 05:56:34 davem Exp $
*
* Missing: IPv6 support.
* Some counter so that the Administrator can see when the machine
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 3a8a7efb4..767c5d00b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1,7 +1,7 @@
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.6 1998/03/03 01:23:42 ralf Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.7 1998/03/17 22:18:33 ralf Exp $
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -45,8 +45,6 @@ extern int sysctl_ip_masq_debug;
extern int sysctl_tcp_cong_avoidance;
extern int sysctl_tcp_hoe_retransmits;
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_keepalive_time;
@@ -57,7 +55,8 @@ extern int sysctl_tcp_retries2;
extern int sysctl_tcp_fin_timeout;
extern int sysctl_tcp_syncookies;
extern int sysctl_tcp_syn_retries;
-extern int sysctl_tcp_stdurg;
+extern int sysctl_tcp_stdurg;
+extern int sysctl_tcp_rfc1337;
extern int sysctl_tcp_syn_taildrop;
extern int sysctl_max_syn_backlog;
@@ -99,12 +98,6 @@ ctl_table ipv4_table[] = {
{NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits",
&sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL,
&proc_dointvec},
- {NET_IPV4_TCP_SACK, "tcp_sack",
- &sysctl_tcp_sack, sizeof(int), 0644, NULL,
- &proc_dointvec},
- {NET_IPV4_TCP_TSACK, "tcp_tsack",
- &sysctl_tcp_tsack, sizeof(int), 0644, NULL,
- &proc_dointvec},
{NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
&sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
&proc_dointvec},
@@ -162,6 +155,8 @@ ctl_table ipv4_table[] = {
#endif
{NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg,
sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_TCP_RFC1337, "tcp_rfc1337", &sysctl_tcp_rfc1337,
+ sizeof(int), 0644, NULL, &proc_dointvec},
{NET_TCP_SYN_TAILDROP, "tcp_syn_taildrop", &sysctl_tcp_syn_taildrop,
sizeof(int), 0644, NULL, &proc_dointvec},
{NET_TCP_MAX_SYN_BACKLOG, "tcp_max_syn_backlog", &sysctl_max_syn_backlog,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 17ec6def9..b20df83d2 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.77 1998/01/15 22:40:18 freitag Exp $
+ * Version: $Id: tcp.c,v 1.96 1998/03/16 02:25:55 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -169,7 +169,7 @@
* Fixed tcp_write_timeout: stuck close,
* and TCP syn retries gets used now.
* Mark Yarvis : In tcp_read_wakeup(), don't send an
- * ack if stat is TCP_CLOSED.
+ * ack if state is TCP_CLOSED.
* Alan Cox : Look up device on a retransmit - routes may
* change. Doesn't yet cope with MSS shrink right
* but its a start!
@@ -425,6 +425,8 @@ int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
struct tcp_mib tcp_statistics;
kmem_cache_t *tcp_openreq_cachep;
+kmem_cache_t *tcp_bucket_cachep;
+kmem_cache_t *tcp_timewait_cachep;
/*
* Find someone to 'accept'. Must be called with
@@ -478,20 +480,6 @@ static void tcp_close_pending (struct sock *sk)
}
/*
- * Enter the time wait state.
- */
-
-void tcp_time_wait(struct sock *sk)
-{
- tcp_set_state(sk,TCP_TIME_WAIT);
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- sk->state_change(sk);
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-}
-
-
-/*
* Walk down the receive queue counting readable data.
*
* Must be called with the socket lock held.
@@ -512,7 +500,7 @@ static int tcp_readable(struct sock *sk)
return(0);
}
- counted = sk->copied_seq; /* Where we are at the moment */
+ counted = sk->tp_pinfo.af_tcp.copied_seq; /* Where we are at the moment */
amount = 0;
/* Do until a push or until we are out of data. */
@@ -606,10 +594,10 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
if (sk->shutdown & RCV_SHUTDOWN)
mask |= POLLHUP;
- if ((tp->rcv_nxt != sk->copied_seq) &&
- (sk->urg_seq != sk->copied_seq ||
- tp->rcv_nxt != sk->copied_seq+1 ||
- sk->urginline || !sk->urg_data))
+ if ((tp->rcv_nxt != tp->copied_seq) &&
+ (tp->urg_seq != tp->copied_seq ||
+ tp->rcv_nxt != tp->copied_seq+1 ||
+ sk->urginline || !tp->urg_data))
mask |= POLLIN | POLLRDNORM;
#if 1 /* This needs benchmarking and real world tests */
@@ -621,9 +609,9 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
space = atomic_read(&sk->wmem_alloc) / 2;
#endif
/* Always wake the user up when an error occured */
- if (sock_wspace(sk) >= space)
+ if (sock_wspace(sk) >= space || sk->err)
mask |= POLLOUT | POLLWRNORM;
- if (sk->urg_data)
+ if (tp->urg_data)
mask |= POLLPRI;
}
return mask;
@@ -649,7 +637,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
case SIOCATMARK:
{
- int answ = sk->urg_data && sk->urg_seq == sk->copied_seq;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
return put_user(answ,(int *) arg);
}
case TIOCOUTQ:
@@ -669,21 +658,38 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
/*
* Wait for a socket to get into the connected state
*/
-static void wait_for_tcp_connect(struct sock * sk)
+static int wait_for_tcp_connect(struct sock * sk, int flags)
{
struct task_struct *tsk = current;
struct wait_queue wait = { tsk, NULL };
- tsk->state = TASK_INTERRUPTIBLE;
- add_wait_queue(sk->sleep, &wait);
- release_sock(sk);
+ while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
+ if(sk->err)
+ return sock_error(sk);
+ if((1 << sk->state) &
+ ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
+ if(sk->keepopen)
+ send_sig(SIGPIPE, tsk, 0);
+ return -EPIPE;
+ }
+ if(flags & MSG_DONTWAIT)
+ return -EAGAIN;
+ if(signal_pending(tsk))
+ return -ERESTARTSYS;
- if (((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT)) && sk->err == 0)
- schedule();
+ tsk->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(sk->sleep, &wait);
+ release_sock(sk);
- tsk->state = TASK_RUNNING;
- remove_wait_queue(sk->sleep, &wait);
- lock_sock(sk);
+ if (((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT)) &&
+ sk->err == 0)
+ schedule();
+
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ lock_sock(sk);
+ }
+ return 0;
}
static inline int tcp_memory_free(struct sock *sk)
@@ -720,32 +726,6 @@ static void wait_for_tcp_memory(struct sock * sk)
lock_sock(sk);
}
-
-static int tcp_append_tail(struct sock *sk, struct sk_buff *skb, u8 *from,
- int tcp_size, int seglen)
-{
- int fault;
- int copy;
-
- /* Add more stuff to the end of the skb. */
- copy = min(sk->mss - tcp_size, skb_tailroom(skb));
- copy = min(copy, seglen);
-
- tcp_size += copy;
-
- fault = copy_from_user(skb->tail, from, copy);
- if (fault)
- return -1;
-
- skb_put(skb, copy);
- skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0);
-
- sk->write_seq += copy;
- skb->end_seq += copy;
-
- return copy;
-}
-
/*
* This routine copies from a user buffer into a socket,
* and starts the transmit system.
@@ -758,24 +738,9 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
/* Wait for a connection to finish. */
- while ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
- if (sk->err)
- return sock_error(sk);
-
- if ((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
- if (sk->keepopen)
- send_sig(SIGPIPE, current, 0);
- return -EPIPE;
- }
-
- if (flags&MSG_DONTWAIT)
- return -EAGAIN;
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- wait_for_tcp_connect(sk);
- }
+ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
+ if((err = wait_for_tcp_connect(sk, flags)) != 0)
+ return err;
/* Ok commence sending. */
while(--iovlen >= 0) {
@@ -785,41 +750,28 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
iov++;
while(seglen > 0) {
- unsigned int actual_win;
- int copy;
- int tmp;
+ int copy, tmp, queue_it;
struct sk_buff *skb;
if (err)
return -EFAULT;
/* Stop on errors. */
- if (sk->err) {
- if (copied)
- return copied;
- return sock_error(sk);
- }
+ if (sk->err)
+ goto do_sock_err;
/* Make sure that we are established. */
- if (sk->shutdown & SEND_SHUTDOWN) {
- if (copied)
- return copied;
- send_sig(SIGPIPE,current,0);
- return -EPIPE;
- }
+ if (sk->shutdown & SEND_SHUTDOWN)
+ goto do_shutdown;
- /* Now we need to check if we have a half built packet. */
-
- /* If we have queued packets.. */
+ /* Now we need to check if we have a half
+ * built packet we can tack some data onto.
+ */
if (tp->send_head && !(flags & MSG_OOB)) {
- int tcp_size;
-
- /* Tail */
-
skb = sk->write_queue.prev;
- tcp_size = skb->tail -
- ((unsigned char *)(skb->h.th) + tp->tcp_header_len);
-
+ copy = skb->tail -
+ ((unsigned char *)(skb->h.th) +
+ tp->tcp_header_len);
/* This window_seq test is somewhat dangerous
* If the remote does SWS avoidance we should
* queue the best we can if not we should in
@@ -827,79 +779,92 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
* a method for detecting this would be most
* welcome
*/
- if (skb->end > skb->tail &&
- sk->mss - tcp_size > 0 &&
+ if (skb_tailroom(skb) > 0 &&
+ (sk->mss - copy) > 0 &&
tp->snd_nxt < skb->end_seq) {
- int tcopy;
-
- tcopy = tcp_append_tail(sk, skb, from,
- tcp_size,
- seglen);
- if (tcopy == -1)
- return -EFAULT;
-
- from += tcopy;
- copied += tcopy;
- seglen -= tcopy;
-
- /* FIXME: if we're nagling we
- * should send here.
- */
+ int last_byte_was_odd = (copy & 1);
+
+ copy = sk->mss - copy;
+ if(copy > skb_tailroom(skb))
+ copy = skb_tailroom(skb);
+ if(copy > seglen)
+ copy = seglen;
+ if(last_byte_was_odd) {
+ if(copy_from_user(skb_put(skb, copy),
+ from, copy))
+ err = -EFAULT;
+ skb->csum = csum_partial(
+ (((unsigned char *)skb->h.th) +
+ tp->tcp_header_len),
+ (skb->tail -
+ (((unsigned char *)skb->h.th) +
+ tp->tcp_header_len)), 0);
+ } else {
+ skb->csum =
+ csum_and_copy_from_user(
+ from, skb_put(skb, copy),
+ copy, skb->csum, &err);
+ }
+ tp->write_seq += copy;
+ skb->end_seq += copy;
+ from += copy;
+ copied += copy;
+ seglen -= copy;
continue;
}
}
- /* We also need to worry about the window.
- * If window < 1/2 the maximum window we've seen from this
- * host, don't use it. This is sender side
- * silly window prevention, as specified in RFC1122.
- * (Note that this is different than earlier versions of
- * SWS prevention, e.g. RFC813.). What we actually do is
- * use the whole MSS. Since the results in the right
- * edge of the packet being outside the window, it will
- * be queued for later rather than sent.
+ /* We also need to worry about the window. If
+ * window < 1/2 the maximum window we've seen
+ * from this host, don't use it. This is
+ * sender side silly window prevention, as
+ * specified in RFC1122. (Note that this is
+ * different than earlier versions of SWS
+ * prevention, e.g. RFC813.). What we
+ * actually do is use the whole MSS. Since
+ * the results in the right edge of the packet
+ * being outside the window, it will be queued
+ * for later rather than sent.
*/
- copy = min(seglen, sk->mss);
- actual_win = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
-
- if (copy > actual_win &&
- (((int) actual_win) >= (tp->max_window >> 1)) &&
- actual_win)
- copy = actual_win;
-
- if (copy <= 0) {
- printk(KERN_DEBUG "sendmsg: copy < 0\n");
- return -EIO;
- }
+ copy = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
+ if(copy >= (tp->max_window >> 1))
+ copy = min(copy, sk->mss);
+ else
+ copy = sk->mss;
+ if(copy > seglen)
+ copy = seglen;
- /* If tp->packets_out > 0 segment will be nagled
- * else we kick it right away.
- */
- tmp = MAX_HEADER + sk->prot->max_header +
+ tmp = MAX_HEADER + sk->prot->max_header +
sizeof(struct sk_buff) + 15;
- if (copy < min(sk->mss, tp->max_window >> 1) &&
- !(flags & MSG_OOB) && tp->packets_out)
+ queue_it = 0;
+ if (copy < min(sk->mss, tp->max_window >> 1) &&
+ !(flags & MSG_OOB)) {
tmp += min(sk->mss, tp->max_window);
- else
- tmp += copy;
+ /* What is happening here is that we want to
+ * tack on later members of the users iovec
+ * if possible into a single frame. When we
+ * leave this loop our caller checks to see if
+ * we can send queued frames onto the wire.
+ * See tcp_v[46]_sendmsg() for this.
+ */
+ queue_it = 1;
+ } else {
+ tmp += copy;
+ }
skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
/* If we didn't get any memory, we need to sleep. */
if (skb == NULL) {
sk->socket->flags |= SO_NOSPACE;
if (flags&MSG_DONTWAIT) {
- if (copied)
- return copied;
- return -EAGAIN;
+ err = -EAGAIN;
+ goto do_interrupted;
}
-
if (signal_pending(current)) {
- if (copied)
- return copied;
- return -ERESTARTSYS;
+ err = -ERESTARTSYS;
+ goto do_interrupted;
}
-
wait_for_tcp_memory(sk);
continue;
}
@@ -910,9 +875,8 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
tmp = tp->af_specific->build_net_header(sk, skb);
if (tmp < 0) {
kfree_skb(skb);
- if (copied)
- return(copied);
- return(tmp);
+ err = tmp;
+ goto do_interrupted;
}
skb->h.th =(struct tcphdr *)
@@ -920,7 +884,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
seglen -= copy;
tcp_build_header_data(skb->h.th, sk, seglen || iovlen);
- /* FIXME: still need to think about SACK options here. */
if (flags & MSG_OOB) {
skb->h.th->urg = 1;
@@ -933,21 +896,29 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
from += copy;
copied += copy;
- sk->write_seq += copy;
+ tp->write_seq += copy;
- tcp_send_skb(sk, skb);
-
- release_sock(sk);
- lock_sock(sk);
+ tcp_send_skb(sk, skb, queue_it);
}
}
-
sk->err = 0;
-
if (err)
return -EFAULT;
-
return copied;
+
+do_sock_err:
+ if(copied)
+ return copied;
+ return sock_error(sk);
+do_shutdown:
+ if(copied)
+ return copied;
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
+do_interrupted:
+ if(copied)
+ return copied;
+ return err;
}
/*
@@ -980,7 +951,7 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
/* No URG data to read. */
- if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
+ if (sk->urginline || !tp->urg_data || tp->urg_data == URG_READ)
return -EINVAL; /* Yes this is right ! */
if (sk->err)
@@ -1000,18 +971,10 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
}
lock_sock(sk);
- if (sk->urg_data & URG_VALID) {
- char c = sk->urg_data;
+ if (tp->urg_data & URG_VALID) {
+ char c = tp->urg_data;
if (!(flags & MSG_PEEK))
- sk->urg_data = URG_READ;
-
- if(len>0)
- {
- err = memcpy_toiovec(msg->msg_iov, &c, 1);
- msg->msg_flags|=MSG_OOB;
- }
- else
- msg->msg_flags|=MSG_TRUNC;
+ tp->urg_data = URG_READ;
if(msg->msg_name)
tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
@@ -1023,6 +986,15 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
/* Read urgent data. */
msg->msg_flags|=MSG_OOB;
release_sock(sk);
+
+ if(len>0)
+ {
+ err = memcpy_toiovec(msg->msg_iov, &c, 1);
+ msg->msg_flags|=MSG_OOB;
+ }
+ else
+ msg->msg_flags|=MSG_TRUNC;
+
return err ? -EFAULT : 1;
}
release_sock(sk);
@@ -1044,45 +1016,37 @@ static int tcp_recv_urg(struct sock * sk, int nonblock,
static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
{
- sk->tp_pinfo.af_tcp.delayed_acks++;
-
__skb_unlink(skb, &sk->receive_queue);
kfree_skb(skb);
}
-
-static void cleanup_rbuf(struct sock *sk)
+/* Clean up the receive buffer for full frames taken by the user,
+ * then send an ACK if necessary. COPIED is the number of bytes
+ * tcp_recvmsg has given to the user so far, it speeds up the
+ * calculation of whether or not we must ACK for the sake of
+ * a window update.
+ */
+static void cleanup_rbuf(struct sock *sk, int copied)
{
struct sk_buff *skb;
- struct tcp_opt *tp;
/* NOTE! The socket must be locked, so that we don't get
* a messed-up receive queue.
*/
while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
- if (!skb->used || atomic_read(&skb->users)>1)
+ if (!skb->used || atomic_read(&skb->users) > 1)
break;
tcp_eat_skb(sk, skb);
}
SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
- tp = &(sk->tp_pinfo.af_tcp);
-
- /* We send a ACK if the sender is blocked
- * else let tcp_data deal with the acking policy.
+ /* We send an ACK if we can now advertise a non-zero window
+ * which has been raised "significantly".
*/
- if (tp->delayed_acks) {
- __u32 rcv_wnd;
-
- /* FIXME: double check this rule, then check against
- * other use of similar rules. Abtract if possible.
- */
- rcv_wnd = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
-
- if ((rcv_wnd < sk->mss) && (sock_rspace(sk) > rcv_wnd))
- tcp_read_wakeup(sk);
- }
+ if((copied > 0) &&
+ (copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp)))
+ tcp_read_wakeup(sk);
}
@@ -1100,7 +1064,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
volatile u32 *seq; /* So gcc doesn't overoptimise */
unsigned long used;
int err = 0;
- int target = 1; /* Read at least this may bytes */
+ int target = 1; /* Read at least this many bytes */
if (sk->state == TCP_LISTEN)
return -ENOTCONN;
@@ -1113,8 +1077,8 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
* the multi-reader case neatly (memcpy_to/fromfs might be
* inline and thus not flush cached variables otherwise).
*/
- peek_seq = sk->copied_seq;
- seq = &sk->copied_seq;
+ peek_seq = tp->copied_seq;
+ seq = &tp->copied_seq;
if (flags & MSG_PEEK)
seq = &peek_seq;
@@ -1129,7 +1093,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
u32 offset;
/* Are we at urgent data? Stop if we have read anything. */
- if (copied && sk->urg_data && sk->urg_seq == *seq)
+ if (copied && tp->urg_data && tp->urg_seq == *seq)
break;
/* We need to check signals first, to get correct SIGURG
@@ -1200,7 +1164,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
break;
}
- cleanup_rbuf(sk);
+ cleanup_rbuf(sk, copied);
release_sock(sk);
sk->socket->flags |= SO_WAITDATA;
schedule();
@@ -1222,8 +1186,8 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
used = len;
/* Do we have urgent data here? */
- if (sk->urg_data) {
- u32 urg_offset = sk->urg_seq - *seq;
+ if (tp->urg_data) {
+ u32 urg_offset = tp->urg_seq - *seq;
if (urg_offset < used) {
if (!urg_offset) {
if (!sk->urginline) {
@@ -1264,8 +1228,8 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
*/
atomic_dec(&skb->users);
- if (after(sk->copied_seq,sk->urg_seq))
- sk->urg_data = 0;
+ if (after(tp->copied_seq,tp->urg_seq))
+ tp->urg_data = 0;
if (used + offset < skb->len)
continue;
@@ -1303,7 +1267,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
current->state = TASK_RUNNING;
/* Clean up data we have read: This will do ACK frames. */
- cleanup_rbuf(sk);
+ cleanup_rbuf(sk, copied);
release_sock(sk);
return copied;
}
@@ -1356,8 +1320,7 @@ static int tcp_close_state(struct sock *sk, int dead)
* reset mistake.
*/
if(dead && ns==TCP_FIN_WAIT2) {
- int timer_active=del_timer(&sk->timer);
- if(timer_active)
+ if(sk->timer.prev && del_timer(&sk->timer))
add_timer(&sk->timer);
else
tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
@@ -1410,6 +1373,7 @@ static inline int closing(struct sock * sk)
void tcp_close(struct sock *sk, unsigned long timeout)
{
struct sk_buff *skb;
+ int data_was_unread = 0;
/* We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent.
@@ -1421,7 +1385,6 @@ void tcp_close(struct sock *sk, unsigned long timeout)
tcp_close_pending(sk);
release_sock(sk);
sk->dead = 1;
- sk->prot->unhash(sk);
return;
}
@@ -1435,14 +1398,30 @@ void tcp_close(struct sock *sk, unsigned long timeout)
* descriptor close, not protocol-sourced closes, because the
* reader process may not have drained the data yet!
*/
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+ while((skb=skb_dequeue(&sk->receive_queue))!=NULL) {
+ data_was_unread++;
kfree_skb(skb);
+ }
- /* Timeout is not the same thing - however the code likes
- * to send both the same way (sigh).
+ /* As outlined in draft-ietf-tcpimpl-prob-03.txt, section
+ * 3.10, we send a RST here because data was lost. To
+ * witness the awful effects of the old behavior of always
+ * doing a FIN, run an older 2.1.x kernel or 2.0.x, start
+ * a bulk GET in an FTP client, suspend the process, wait
+ * for the client to advertise a zero window, then kill -9
+ * the FTP client, wheee... Note: timeout is always zero
+ * in such a case.
*/
- if (tcp_close_state(sk,1)==1)
+ if(data_was_unread != 0) {
+ /* Unread data was tossed, zap the connection. */
+ tcp_set_state(sk, TCP_CLOSE);
+ tcp_send_active_reset(sk);
+ } else if (tcp_close_state(sk,1)) {
+ /* We FIN if the application ate all the data before
+ * zapping the connection.
+ */
tcp_send_fin(sk);
+ }
if (timeout) {
struct task_struct *tsk = current;
@@ -1470,8 +1449,7 @@ void tcp_close(struct sock *sk, unsigned long timeout)
* we may need to set up a timer.
*/
if (sk->state==TCP_FIN_WAIT2) {
- int timer_active=del_timer(&sk->timer);
- if(timer_active)
+ if(sk->timer.prev && del_timer(&sk->timer))
add_timer(&sk->timer);
else
tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
@@ -1479,9 +1457,6 @@ void tcp_close(struct sock *sk, unsigned long timeout)
sk->dead = 1;
release_sock(sk);
-
- if(sk->state == TCP_CLOSE)
- sk->prot->unhash(sk);
}
/*
@@ -1538,13 +1513,12 @@ struct sock *tcp_accept(struct sock *sk, int flags)
/* If this is a non blocking socket don't sleep */
error = EAGAIN;
if (flags & O_NONBLOCK)
- goto out;
+ goto out;
error = ERESTARTSYS;
req = wait_for_connect(sk, &prev);
if (!req)
- goto out;
- error = 0;
+ goto out;
}
tcp_synq_unlink(tp, req, prev);
@@ -1647,9 +1621,23 @@ void tcp_set_keepalive(struct sock *sk, int val)
__initfunc(void tcp_init(void))
{
tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
- sizeof(struct open_request),
+ sizeof(struct open_request),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if(!tcp_openreq_cachep)
panic("tcp_init: Cannot alloc open_request cache.");
+
+ tcp_bucket_cachep = kmem_cache_create("tcp_bind_bucket",
+ sizeof(struct tcp_bind_bucket),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!tcp_bucket_cachep)
+ panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
+
+ tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",
+ sizeof(struct tcp_tw_bucket),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!tcp_timewait_cachep)
+ panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 841359739..4b7dcc9e9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.66 1998/01/15 22:40:29 freitag Exp $
+ * Version: $Id: tcp_input.c,v 1.84 1998/03/15 03:23:20 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -67,57 +67,54 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
extern int sysctl_tcp_fin_timeout;
+/* These are on by default so the code paths get tested.
+ * For the final 2.2 this may be undone at our discretion. -DaveM
+ */
+int sysctl_tcp_timestamps = 1;
+int sysctl_tcp_window_scaling = 1;
+
int sysctl_tcp_cong_avoidance;
int sysctl_tcp_hoe_retransmits;
-int sysctl_tcp_sack;
-int sysctl_tcp_tsack;
-int sysctl_tcp_timestamps;
-int sysctl_tcp_window_scaling;
int sysctl_tcp_syncookies = SYNC_INIT;
int sysctl_tcp_stdurg;
+int sysctl_tcp_rfc1337;
static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj;
-/*
- * Called each time to estimate the delayed ack timeout. This is
- * how it should be done so a fast link isnt impacted by ack delay.
- *
- * I think we need a medium deviation here also...
- * The estimated value is changing to fast
+/* There is something which you must keep in mind when you analyze the
+ * behavior of the tp->ato delayed ack timeout interval. When a
+ * connection starts up, we want to ack as quickly as possible. The
+ * problem is that "good" TCP's do slow start at the beginning of data
+ * transmission. The means that until we send the first few ACK's the
+ * sender will sit on his end and only queue most of his data, because
+ * he can only send snd_cwnd unacked packets at any given time. For
+ * each ACK we send, he increments snd_cwnd and transmits more of his
+ * queue. -DaveM
*/
-
static void tcp_delack_estimator(struct tcp_opt *tp)
{
- int m;
-
- /* Delayed ACK time estimator. */
-
- m = jiffies - tp->lrcvtime;
-
- tp->lrcvtime = jiffies;
+ if(tp->ato == 0) {
+ tp->lrcvtime = jiffies;
- if (m < 0)
- return;
-
- /* if the mesured value is bigger than
- * twice the round trip time ignore it.
- */
- if ((m << 2) <= tp->srtt) {
- m -= (tp->iat >> 3);
- tp->iat += m;
-
- if (m <0)
- m = -m;
-
- m -= (tp->iat_mdev >> 2);
- tp->iat_mdev += m;
+ /* Help sender leave slow start quickly,
+ * this sets our initial ato value.
+ */
+ tcp_enter_quickack_mode(tp);
+ } else {
+ int m = jiffies - tp->lrcvtime;
- tp->ato = (tp->iat >> 3) + (tp->iat_mdev >> 2);
+ tp->lrcvtime = jiffies;
+ if(m <= 0)
+ m = 1;
+ if(m > tp->rto)
+ tp->ato = tp->rto;
+ else
+ tp->ato = (tp->ato >> 1) + m;
- if (tp->ato < HZ/50)
- tp->ato = HZ/50;
- } else
- tp->ato = 0;
+ /* We are not in "quick ack" mode. */
+ if(tp->ato <= (HZ/100))
+ tp->ato = ((HZ/100)*2);
+ }
}
/* Called to compute a smoothed rtt estimate. The data fed to this
@@ -132,9 +129,9 @@ static void tcp_delack_estimator(struct tcp_opt *tp)
static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
{
- long m;
- /*
- * The following amusing code comes from Jacobson's
+ long m = mrtt; /* RTT */
+
+ /* The following amusing code comes from Jacobson's
* article in SIGCOMM '88. Note that rtt and mdev
* are scaled versions of rtt and mean deviation.
* This is designed to be as fast as possible
@@ -143,12 +140,9 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
* On a 1990 paper the rto value is changed to:
* RTO = rtt + 4 * mdev
*/
-
- m = mrtt; /* RTT */
-
+ if(m == 0)
+ m = 1;
if (tp->srtt != 0) {
- if(m<=0)
- m=1; /* IS THIS RIGHT FOR <0 ??? */
m -= (tp->srtt >> 3); /* m is now error in rtt est */
tp->srtt += m; /* rtt = 7/8 rtt + 1/8 new */
if (m < 0)
@@ -202,19 +196,17 @@ extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
*/
if (!before(end_seq,tp->last_ack_sent)) {
tp->ts_recent = tp->rcv_tsval;
- /* FIXME: need a corse timestamp. Days uptime
- * would be good.
- */
tp->ts_recent_stamp = jiffies;
}
}
+#define PAWS_24DAYS (HZ * 60 * 60 * 24 * 24)
+
extern __inline__ int tcp_paws_discard(struct tcp_opt *tp)
{
- /* FIXME: must check that ts_recent is not
- * more than 24 days old here. Yuck.
- */
- return ((s32)(tp->rcv_tsval-tp->ts_recent) < 0);
+ /* ts_recent must be younger than 24 days */
+ return (((jiffies - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
+ ((s32)(tp->rcv_tsval-tp->ts_recent) < 0));
}
@@ -257,8 +249,6 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb)
/* We want the right error as BSD sees it (and indeed as we do). */
switch (sk->state) {
- case TCP_TIME_WAIT:
- break;
case TCP_SYN_SENT:
sk->err = ECONNREFUSED;
break;
@@ -268,23 +258,8 @@ static void tcp_reset(struct sock *sk, struct sk_buff *skb)
default:
sk->err = ECONNRESET;
};
-#ifdef CONFIG_TCP_RFC1337
- /*
- * Time wait assassination protection [RFC1337]
- *
- * This is a good idea, but causes more sockets to take time to close.
- *
- * Ian Heavens has since shown this is an inadequate fix for the protocol
- * bug in question.
- */
- if(sk->state!=TCP_TIME_WAIT) {
- tcp_set_state(sk,TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- }
-#else
tcp_set_state(sk,TCP_CLOSE);
sk->shutdown = SHUTDOWN_MASK;
-#endif
if (!sk->dead)
sk->state_change(sk);
}
@@ -302,7 +277,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
int length=(th->doff*4)-sizeof(struct tcphdr);
ptr = (unsigned char *)(th + 1);
- tp->sacks = 0;
tp->saw_tstamp = 0;
while(length>0) {
@@ -336,10 +310,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
tp->snd_wscale = *(__u8 *)ptr;
}
break;
- case TCPOPT_SACK_PERM:
- if(opsize==TCPOLEN_SACK_PERM && th->syn)
- if (sysctl_tcp_sack && !no_fancy)
- tp->sack_ok = 1;
case TCPOPT_TIMESTAMP:
if(opsize==TCPOLEN_TIMESTAMP) {
/* Cheaper to set again then to
@@ -353,18 +323,6 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
}
}
break;
- case TCPOPT_SACK:
- if (no_fancy || !sysctl_tcp_sack)
- break;
- tp->sacks = (opsize-2)>>3;
- if (tp->sacks<<3 == opsize-2) {
- int i;
- for (i = 0; i < tp->sacks; i++) {
- tp->left_sack[i] = ntohl(((__u32 *)ptr)[2*i]);
- tp->right_sack[i] = ntohl(((__u32 *)ptr)[2*i+1]);
- }
- } else
- tp->sacks = 0;
}
ptr+=opsize-2;
length-=opsize;
@@ -374,7 +332,7 @@ void tcp_parse_options(struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
/* Fast parse options. This hopes to only see timestamps.
* If it is wrong it falls back on tcp_parse_option().
- * This should probably get extended for timestamps + SACK as well.
+ * This should probably get extended for timestamps as well.
* Assembly code anyone? -- erics
*/
static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *tp)
@@ -384,14 +342,12 @@ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *
return 0;
if (th->doff == sizeof(struct tcphdr)>>2) {
tp->saw_tstamp = 0;
- tp->sacks = 0;
return 0;
- } else if (th->doff == (sizeof(struct tcphdr)>>2)+3) {
+ } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
__u32 *ptr = (__u32 *)(th + 1);
- if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
- | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+ if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
tp->saw_tstamp = 1;
- tp->sacks = 0;
tp->rcv_tsval = ntohl(*++ptr);
tp->rcv_tsecr = ntohl(*++ptr);
return 1;
@@ -401,89 +357,6 @@ static __inline__ int tcp_fast_parse_options(struct tcphdr *th, struct tcp_opt *
return 1;
}
-#if 0
-
-/*
- * This is the old fast retransmit code. It will go away eventually. -- erics
- */
-
-/*
- * See draft-stevens-tcpca-spec-01 for documentation.
- */
-
-static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
-{
- struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
-
- /* FIXME: if we are already retransmitting should this code
- * be skipped? [Floyd high_seq check sort of does this]
- * The case I'm worried about is falling into a fast
- * retransmit on a link with a congestion window of 1 or 2.
- * There was some evidence in 2.0.x that this was problem
- * on really slow links (1200 or 2400 baud). I need to
- * try this situation again and see what happens.
- */
-
- /*
- * An ACK is a duplicate if:
- * (1) it has the same sequence number as the largest number we've
- * seen,
- * (2) it has the same window as the last ACK,
- * (3) we have outstanding data that has not been ACKed
- * (4) The packet was not carrying any data.
- * (5) [From Floyds paper on fast retransmit wars]
- * The packet acked data after high_seq;
- */
-
- if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) {
- /* 1. When the third duplicate ack is received, set ssthresh
- * to one half the current congestion window, but no less
- * than two segments. Retransmit the missing segment.
- */
- if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
- tp->dup_acks++;
-
- if (tp->dup_acks == 3) {
- tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
- tp->snd_cwnd = tp->snd_ssthresh + 3;
- tcp_do_retransmit(sk, 0);
-
- /* Careful not to timeout just after fast
- * retransmit!
- */
- tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
- }
- }
-
- /* 2. Each time another duplicate ACK arrives, increment
- * cwnd by the segment size. [...] Transmit a packet...
- *
- * Packet transmission will be done on normal flow processing
- * since we're not in "retransmit mode".
- */
- if (tp->dup_acks >= 3) {
- tp->dup_acks++;
- tp->snd_cwnd++;
- }
- } else {
- /* 3. When the next ACK arrives that acknowledges new data,
- * set cwnd to ssthresh.
- */
- if (tp->dup_acks >= 3) {
- tp->retrans_head = NULL;
- tp->snd_cwnd = max(tp->snd_ssthresh, 1);
- tp->retransmits = 0;
- }
- tp->dup_acks = 0;
-
- /* FIXME: This is wrong if the new ack that arrives
- * is below the value for high_seq.
- */
- tp->high_seq = 0;
- }
-}
-#endif
-
#define FLAG_DATA 0x01
#define FLAG_WIN_UPDATE 0x02
#define FLAG_DATA_ACKED 0x04
@@ -579,9 +452,8 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
* not indicate a packet left the system.
* We can test this by just checking
* if ack changed from snd_una, since
- * the only way to get here without changing
- * advancing from snd_una is if this was a
- * window update.
+ * the only way to get here without advancing
+ * from snd_una is if this was a window update.
*/
if (ack != tp->snd_una && before(ack,tp->high_seq)) {
tcp_do_retransmit(sk, 0);
@@ -596,9 +468,6 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
clear_fast_retransmit(sk);
}
}
- } else {
- /* Clear any aborted fast retransmit starts. */
- tp->dup_acks = 0;
}
}
@@ -649,7 +518,6 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
expected = (tp->snd_nxt - tp->snd_una) * inv_basertt;
- /* XXX sk->mss should move into tcp_opt as well -DaveM */
inv_basebd = sk->mss * inv_basertt;
/* Slow Start */
@@ -731,13 +599,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
int acked = 0;
while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) {
-#ifdef TCP_DEBUG
- /* Check for a bug. */
- if (skb->next != (struct sk_buff*) &sk->write_queue &&
- after(skb->end_seq, skb->next->seq))
- printk(KERN_DEBUG "INET: tcp_input.c: *** "
- "bug send_list out of order.\n");
-#endif
/* If our packet is before the ack sequence we can
* discard it as it's confirmed to have arrived the
* other end.
@@ -745,12 +606,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
if (after(skb->end_seq, ack))
break;
-#if 0
- SOCK_DEBUG(sk, "removing seg %x-%x from retransmit queue\n",
- skb->seq, skb->end_seq);
-#endif
-
- acked = FLAG_DATA_ACKED;
+ /* Initial outgoing SYN's get put onto the write_queue
+ * just like anything else we transmit. It is not
+ * true data, and if we misinform our callers that
+ * this ACK acks real data, we will erroneously exit
+ * connection startup slow start one packet too
+ * quickly. This is severely frowned upon behavior.
+ */
+ if(!skb->h.th->syn)
+ acked = FLAG_DATA_ACKED;
/* FIXME: packet counting may break if we have to
* do packet "repackaging" for stacks that don't
@@ -766,11 +630,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
kfree_skb(skb);
}
- if (acked) {
+ if (acked)
tp->retrans_head = NULL;
- if (!sk->dead)
- sk->write_space(sk);
- }
+
return acked;
}
@@ -795,6 +657,66 @@ static void tcp_ack_probe(struct sock *sk, __u32 ack)
}
}
+/* Read draft-ietf-tcplw-high-performance before mucking
+ * with this code. (Superceeds RFC1323)
+ */
+static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
+ u32 seq, u32 ack, int flag)
+{
+ __u32 seq_rtt = (jiffies-tp->rcv_tsecr);
+ tcp_rtt_estimator(tp, seq_rtt);
+ if (tp->retransmits) {
+ if (tp->packets_out == 0) {
+ tp->retransmits = 0;
+ tp->backoff = 0;
+ tcp_set_rto(tp);
+ } else {
+ /* Still retransmitting, use backoff */
+ tcp_set_rto(tp);
+ tp->rto = tp->rto << tp->backoff;
+ }
+ } else {
+ tcp_set_rto(tp);
+ if (flag & FLAG_DATA_ACKED)
+ (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
+ }
+ /* NOTE: safe here so long as cong_ctl doesn't use rto */
+ tcp_bound_rto(tp);
+}
+
+static void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
+{
+ struct sk_buff *skb;
+ long when;
+
+ skb = skb_peek(&sk->write_queue);
+ when = tp->rto - (jiffies - skb->when);
+
+ /* FIXME: This assumes that when we are retransmitting
+ * we should only ever respond with one packet.
+ * This means congestion windows should not grow
+ * during recovery. In 2.0.X we allow the congestion
+ * window to grow. It is not clear to me which
+ * decision is correct. The RFCs should be double
+ * checked as should the behavior of other stacks.
+ * Also note that if we do want to allow the
+ * congestion window to grow during retransmits
+ * we have to fix the call to congestion window
+ * updates so that it works during retransmission.
+ */
+ if (tp->retransmits) {
+ tp->retrans_head = NULL;
+
+ /* This is tricky. We are retransmiting a
+ * segment of a window when congestion occured.
+ */
+ tcp_do_retransmit(sk, 0);
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ } else {
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
+ }
+}
+
/*
* This routine deals with incoming acks, but not outgoing ones.
*/
@@ -806,7 +728,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
int flag = 0;
u32 seq = 0;
u32 seq_rtt = 0;
- struct sk_buff *skb;
if(sk->zapped)
return(1); /* Dead, can't ack any more so why bother */
@@ -838,7 +759,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
*/
if (before(tp->snd_wl1, ack_seq) ||
(tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
- unsigned long nwin = ntohs(th->window) << tp->snd_wscale;
+ u32 nwin = ntohs(th->window) << tp->snd_wscale;
if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
flag |= FLAG_WIN_UPDATE;
@@ -869,28 +790,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
/* If we have a timestamp, we always do rtt estimates. */
if (tp->saw_tstamp) {
- /* Read draft-ietf-tcplw-high-performance before mucking
- * with this code. (Superceeds RFC1323)
- */
- seq_rtt = (jiffies-tp->rcv_tsecr);
- tcp_rtt_estimator(tp, seq_rtt);
- if (tp->retransmits) {
- if (tp->packets_out == 0) {
- tp->retransmits = 0;
- tp->backoff = 0;
- tcp_set_rto(tp);
- } else {
- /* Still retransmitting, use backoff */
- tcp_set_rto(tp);
- tp->rto = tp->rto << tp->backoff;
- }
- } else {
- tcp_set_rto(tp);
- if (flag & FLAG_DATA_ACKED)
- (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
- }
- /* NOTE: safe here so long as cong_ctl doesn't use rto */
- tcp_bound_rto(tp);
+ tcp_ack_saw_tstamp(sk, tp, seq, ack, flag);
} else {
/* If we were retransmiting don't count rtt estimate. */
if (tp->retransmits) {
@@ -916,51 +816,217 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
}
if (tp->packets_out) {
- if (flag & FLAG_DATA_ACKED) {
- long when;
-
- skb = skb_peek(&sk->write_queue);
- when = tp->rto - (jiffies - skb->when);
-
- /* FIXME: This assumes that when we are retransmitting
- * we should only ever respond with one packet.
- * This means congestion windows should not grow
- * during recovery. In 2.0.X we allow the congestion
- * window to grow. It is not clear to me which
- * decision is correct. The RFCs should be double
- * checked as should the behavior of other stacks.
- * Also note that if we do want to allow the
- * congestion window to grow during retransmits
- * we have to fix the call to congestion window
- * updates so that it works during retransmission.
- */
- if (tp->retransmits) {
- tp->retrans_head = NULL;
-
- /* This is tricky. We are retransmiting a
- * segment of a window when congestion occured.
- */
- tcp_do_retransmit(sk, 0);
- tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
- } else
- tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
- }
- } else
+ if (flag & FLAG_DATA_ACKED)
+ tcp_ack_packets_out(sk, tp);
+ } else {
tcp_clear_xmit_timer(sk, TIME_RETRANS);
+ }
- tcp_fast_retrans(sk, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
-
+ flag &= (FLAG_DATA | FLAG_WIN_UPDATE);
+ if ((ack == tp->snd_una && tp->packets_out && flag == 0) ||
+ (tp->high_seq != 0)) {
+ tcp_fast_retrans(sk, ack, flag);
+ } else {
+ /* Clear any aborted fast retransmit starts. */
+ tp->dup_acks = 0;
+ }
/* Remember the highest ack received. */
tp->snd_una = ack;
-
return 1;
uninteresting_ack:
-
SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
return 0;
}
+/* New-style handling of TIME_WAIT sockets. */
+static void tcp_timewait_kill(unsigned long __arg)
+{
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)__arg;
+
+ /* Zap the timer. */
+ del_timer(&tw->timer);
+
+ /* Unlink from various places. */
+ if(tw->bind_next)
+ tw->bind_next->bind_pprev = tw->bind_pprev;
+ *(tw->bind_pprev) = tw->bind_next;
+ if(tw->tb->owners == NULL)
+ tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
+
+ if(tw->next)
+ tw->next->pprev = tw->pprev;
+ *tw->pprev = tw->next;
+
+ /* We decremented the prot->inuse count when we entered TIME_WAIT
+ * and the sock from which this came was destroyed.
+ */
+ tw->sklist_next->sklist_prev = tw->sklist_prev;
+ tw->sklist_prev->sklist_next = tw->sklist_next;
+
+ /* Ok, now free it up. */
+ kmem_cache_free(tcp_timewait_cachep, tw);
+}
+
+/* We come here as a special case from the AF specific TCP input processing,
+ * and the SKB has no owner. Essentially handling this is very simple,
+ * we just keep silently eating rx'd packets until none show up for the
+ * entire timeout period. The only special cases are for BSD TIME_WAIT
+ * reconnects and SYN/RST bits being set in the TCP header.
+ */
+int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
+ struct tcphdr *th, void *opt, __u16 len)
+{
+ /* RFC 1122:
+ * "When a connection is [...] on TIME-WAIT state [...]
+ * [a TCP] MAY accept a new SYN from the remote TCP to
+ * reopen the connection directly, if it:
+ *
+ * (1) assigns its initial sequence number for the new
+ * connection to be larger than the largest sequence
+ * number it used on the previous connection incarnation,
+ * and
+ *
+ * (2) returns to TIME-WAIT state if the SYN turns out
+ * to be an old duplicate".
+ */
+ if(th->syn && !th->rst && after(skb->seq, tw->rcv_nxt)) {
+ struct sock *sk;
+ struct tcp_func *af_specific = tw->af_specific;
+ __u32 isn;
+
+ isn = tw->rcv_nxt + 128000;
+ if(isn == 0)
+ isn++;
+ tcp_timewait_kill((unsigned long)tw);
+ sk = af_specific->get_sock(skb, th);
+ if(sk == NULL || !ipsec_sk_policy(sk,skb))
+ return 0;
+ skb_set_owner_r(skb, sk);
+ af_specific = sk->tp_pinfo.af_tcp.af_specific;
+ if(af_specific->conn_request(sk, skb, opt, isn) < 0)
+ return 1; /* Toss a reset back. */
+ return 0; /* Discard the frame. */
+ }
+
+ /* Check RST or SYN */
+ if(th->rst || th->syn) {
+ /* This is TIME_WAIT assasination, in two flavors.
+ * Oh well... nobody has a sufficient solution to this
+ * protocol bug yet.
+ */
+ if(sysctl_tcp_rfc1337 == 0)
+ tcp_timewait_kill((unsigned long)tw);
+
+ if(!th->rst)
+ return 1; /* toss a reset back */
+ } else {
+ if(th->ack) {
+ /* In this case we must reset the TIMEWAIT timer. */
+ del_timer(&tw->timer);
+ tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN;
+ add_timer(&tw->timer);
+ }
+ }
+ return 0; /* Discard the frame. */
+}
+
+/* Enter the time wait state. This is always called from BH
+ * context. Essentially we whip up a timewait bucket, copy the
+ * relevant info into it from the SK, and mess with hash chains
+ * and list linkage.
+ */
+static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+{
+ struct sock **head, *sktw;
+
+ /* Step 1: Remove SK from established hash. */
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_reg_zap(sk);
+
+ /* Step 2: Put TW into bind hash where SK was. */
+ tw->tb = (struct tcp_bind_bucket *)sk->prev;
+ if((tw->bind_next = sk->bind_next) != NULL)
+ sk->bind_next->bind_pprev = &tw->bind_next;
+ tw->bind_pprev = sk->bind_pprev;
+ *sk->bind_pprev = (struct sock *)tw;
+
+ /* Step 3: Same for the protocol sklist. */
+ (tw->sklist_next = sk->sklist_next)->sklist_prev = (struct sock *)tw;
+ (tw->sklist_prev = sk->sklist_prev)->sklist_next = (struct sock *)tw;
+ sk->sklist_next = NULL;
+ sk->prot->inuse--;
+
+ /* Step 4: Hash TW into TIMEWAIT half of established hash table. */
+ head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+ sktw = (struct sock *)tw;
+ if((sktw->next = *head) != NULL)
+ (*head)->pprev = &sktw->next;
+ *head = sktw;
+ sktw->pprev = head;
+}
+
+void tcp_time_wait(struct sock *sk)
+{
+ struct tcp_tw_bucket *tw;
+
+ tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
+ if(tw != NULL) {
+ /* Give us an identity. */
+ tw->daddr = sk->daddr;
+ tw->rcv_saddr = sk->rcv_saddr;
+ tw->bound_dev_if= sk->bound_dev_if;
+ tw->num = sk->num;
+ tw->state = TCP_TIME_WAIT;
+ tw->family = sk->family;
+ tw->source = sk->dummy_th.source;
+ tw->dest = sk->dummy_th.dest;
+ tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt;
+ tw->af_specific = sk->tp_pinfo.af_tcp.af_specific;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ if(tw->family == AF_INET6) {
+ memcpy(&tw->v6_daddr,
+ &sk->net_pinfo.af_inet6.daddr,
+ sizeof(struct in6_addr));
+ memcpy(&tw->v6_rcv_saddr,
+ &sk->net_pinfo.af_inet6.rcv_saddr,
+ sizeof(struct in6_addr));
+ }
+#endif
+ /* Linkage updates. */
+ tcp_tw_hashdance(sk, tw);
+
+ /* Get the TIME_WAIT timeout firing. */
+ init_timer(&tw->timer);
+ tw->timer.function = tcp_timewait_kill;
+ tw->timer.data = (unsigned long) tw;
+ tw->timer.expires = jiffies + TCP_TIMEWAIT_LEN;
+ add_timer(&tw->timer);
+
+ /* CLOSE the SK. */
+ if(sk->state == TCP_ESTABLISHED)
+ tcp_statistics.TcpCurrEstab--;
+ sk->state = TCP_CLOSE;
+ net_reset_timer(sk, TIME_DONE,
+ min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME));
+ } else {
+ /* Sorry, we're out of memory, just CLOSE this
+ * socket up. We've got bigger problems than
+ * non-graceful socket closings.
+ */
+ tcp_set_state(sk, TCP_CLOSE);
+ }
+
+ /* Prevent rcvmsg/sndmsg calls, and wake people up. */
+ sk->shutdown = SHUTDOWN_MASK;
+ if(!sk->dead)
+ sk->state_change(sk);
+}
+
/*
* Process the FIN bit. This now behaves as it is supposed to work
* and the FIN takes effect when it is validly part of sequence
@@ -976,17 +1042,9 @@ uninteresting_ack:
* If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
*/
-static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
+static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
{
- struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-
- if(sk->state == TCP_SYN_SENT) {
- /* RFC793 says to drop the segment and return. */
- return 1;
- }
-
- /* XXX This fin_seq thing should disappear... -DaveM */
- tp->fin_seq = skb->end_seq;
+ sk->tp_pinfo.af_tcp.fin_seq = skb->end_seq;
tcp_send_ack(sk);
@@ -1013,12 +1071,6 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
case TCP_LAST_ACK:
/* RFC793: Remain in the LAST-ACK state. */
break;
- case TCP_TIME_WAIT:
- /* Received a retransmission of the FIN,
- * restart the TIME_WAIT timer.
- */
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- break;
case TCP_FIN_WAIT1:
/* This case occurs when a simultaneous close
@@ -1035,21 +1087,15 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
break;
case TCP_FIN_WAIT2:
/* Received a FIN -- send ACK and enter TIME_WAIT. */
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- sk->shutdown |= SHUTDOWN_MASK;
- tcp_set_state(sk,TCP_TIME_WAIT);
- break;
- case TCP_CLOSE:
- /* Already in CLOSE. */
+ tcp_time_wait(sk);
break;
default:
- /* Only TCP_LISTEN is left, in that case we should never
- * reach this piece of code.
+ /* Only TCP_LISTEN and TCP_CLOSE are left, in these
+ * cases we should never reach this piece of code.
*/
printk("tcp_fin: Impossible, sk->state=%d\n", sk->state);
break;
};
- return 0;
}
/* This one checks to see if we can put data from the
@@ -1060,7 +1106,7 @@ static void tcp_ofo_queue(struct sock *sk)
struct sk_buff *skb;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- while ((skb = skb_peek(&sk->out_of_order_queue))) {
+ while ((skb = skb_peek(&tp->out_of_order_queue))) {
if (after(skb->seq, tp->rcv_nxt))
break;
@@ -1076,6 +1122,8 @@ static void tcp_ofo_queue(struct sock *sk)
skb_unlink(skb);
skb_queue_tail(&sk->receive_queue, skb);
tp->rcv_nxt = skb->end_seq;
+ if(skb->h.th->fin)
+ tcp_fin(skb, sk, skb->h.th);
}
}
@@ -1094,8 +1142,12 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
dst_confirm(sk->dst_cache);
skb_queue_tail(&sk->receive_queue, skb);
tp->rcv_nxt = skb->end_seq;
+ if(skb->h.th->fin)
+ tcp_fin(skb, sk, skb->h.th);
+ else
+ tp->delayed_acks++;
tcp_ofo_queue(sk);
- if (skb_queue_len(&sk->out_of_order_queue) == 0)
+ if (skb_queue_len(&tp->out_of_order_queue) == 0)
tp->pred_flags = htonl((0x5010 << 16) | tp->snd_wnd);
return;
}
@@ -1104,8 +1156,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
if (!after(skb->end_seq, tp->rcv_nxt)) {
/* A retransmit, 2nd most common case. Force an imediate ack. */
SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
-
- tp->delayed_acks = MAX_DELAY_ACK;
+ tcp_enter_quickack_mode(tp);
kfree_skb(skb);
return;
}
@@ -1119,7 +1170,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
}
/* Ok. This is an out_of_order segment, force an ack. */
- tp->delayed_acks = MAX_DELAY_ACK;
+ tp->delayed_acks++;
+ tcp_enter_quickack_mode(tp);
/* Disable header predition. */
tp->pred_flags = 0;
@@ -1127,10 +1179,10 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
tp->rcv_nxt, skb->seq, skb->end_seq);
- if (skb_peek(&sk->out_of_order_queue) == NULL) {
- skb_queue_head(&sk->out_of_order_queue,skb);
+ if (skb_peek(&tp->out_of_order_queue) == NULL) {
+ skb_queue_head(&tp->out_of_order_queue,skb);
} else {
- for(skb1=sk->out_of_order_queue.prev; ; skb1 = skb1->prev) {
+ for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) {
/* Already there. */
if (skb->seq == skb1->seq && skb->len >= skb1->len) {
skb_append(skb1, skb);
@@ -1145,8 +1197,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
}
/* See if we've hit the start. If so insert. */
- if (skb1 == skb_peek(&sk->out_of_order_queue)) {
- skb_queue_head(&sk->out_of_order_queue,skb);
+ if (skb1 == skb_peek(&tp->out_of_order_queue)) {
+ skb_queue_head(&tp->out_of_order_queue,skb);
break;
}
}
@@ -1172,23 +1224,17 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
if (skb->len == 0 && !th->fin)
return(0);
- /* FIXME: don't accept data after the received fin.
- *
- * Would checking snd_seq against fin_seq be enough?
- * If so, how do we handle that case exactly? -DaveM
- */
-
/* We no longer have anyone receiving data on this connection. */
tcp_data_queue(sk, skb);
- if (before(tp->rcv_nxt, sk->copied_seq)) {
+ if (before(tp->rcv_nxt, tp->copied_seq)) {
printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n");
- tp->rcv_nxt = sk->copied_seq;
+ tp->rcv_nxt = tp->copied_seq;
}
- tp->delayed_acks++;
-
- /* Now tell the user we may have some data. */
+ /* Above, tcp_data_queue() increments delayed_acks appropriately.
+ * Now tell the user we may have some data.
+ */
if (!sk->dead) {
SOCK_DEBUG(sk, "Data wakeup.\n");
sk->data_ready(sk,0);
@@ -1204,23 +1250,10 @@ static void tcp_data_snd_check(struct sock *sk)
if ((skb = tp->send_head)) {
if (!after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
tp->packets_out < tp->snd_cwnd ) {
- /* Add more data to the send queue. */
-
- /* FIXME: the congestion window is checked
- * again in tcp_write_xmit anyway?! -- erics
- *
- * I think it must, it bumps tp->packets_out for
- * each packet it fires onto the wire. -DaveM
- */
+ /* Put more data onto the wire. */
tcp_write_xmit(sk);
- if(!sk->dead)
- sk->write_space(sk);
} else if (tp->packets_out == 0 && !tp->pending) {
- /* Data to queue but no room. */
-
- /* FIXME: Is it right to do a zero window probe into
- * a congestion window limited window??? -- erics
- */
+ /* Start probing the receivers window. */
tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
}
}
@@ -1240,12 +1273,24 @@ static __inline__ void __tcp_ack_snd_check(struct sock *sk)
* - delay time <= 0.5 HZ
* - we don't have a window update to send
* - must send at least every 2 full sized packets
+ *
+ * With an extra heuristic to handle loss of packet
+ * situations and also helping the sender leave slow
+ * start in an expediant manner.
*/
- if (tp->delayed_acks >= MAX_DELAY_ACK || tcp_raise_window(sk))
+ /* Two full frames received or... */
+ if (((tp->rcv_nxt - tp->rcv_wup) >= (sk->mss << 1)) ||
+ /* We will update the window "significantly" or... */
+ tcp_raise_window(sk) ||
+ /* We entered "quick ACK" mode */
+ tcp_in_quickack_mode(tp)) {
+ /* Then ack it now */
tcp_send_ack(sk);
- else
- tcp_send_delayed_ack(sk, HZ/2);
+ } else {
+ /* Else, send delayed ack. */
+ tcp_send_delayed_ack(tp, HZ/2);
+ }
}
static __inline__ void tcp_ack_snd_check(struct sock *sk)
@@ -1279,11 +1324,11 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
ptr += ntohl(th->seq);
/* Ignore urgent data that we've already seen and read. */
- if (after(sk->copied_seq, ptr))
+ if (after(tp->copied_seq, ptr))
return;
/* Do we already have a newer (or duplicate) urgent pointer? */
- if (sk->urg_data && !after(ptr, sk->urg_seq))
+ if (tp->urg_data && !after(ptr, tp->urg_seq))
return;
/* Tell the world about our new urgent pointer. */
@@ -1296,14 +1341,14 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
/* We may be adding urgent data when the last byte read was
* urgent. To do this requires some care. We cannot just ignore
- * sk->copied_seq since we would read the last urgent byte again
+ * tp->copied_seq since we would read the last urgent byte again
* as data, nor can we alter copied_seq until this data arrives
* or we break the sematics of SIOCATMARK (and thus sockatmark())
*/
- if (sk->urg_seq == sk->copied_seq)
- sk->copied_seq++; /* Move the copied sequence on correctly */
- sk->urg_data = URG_NOTYET;
- sk->urg_seq = ptr;
+ if (tp->urg_seq == tp->copied_seq)
+ tp->copied_seq++; /* Move the copied sequence on correctly */
+ tp->urg_data = URG_NOTYET;
+ tp->urg_seq = ptr;
/* Disable header prediction. */
tp->pred_flags = 0;
@@ -1312,17 +1357,19 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
/* This is the 'fast' part of urgent handling. */
static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len)
{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
/* Check if we get a new urgent pointer - normally not. */
if (th->urg)
tcp_check_urg(sk,th);
/* Do we wait for any urgent data? - normally not... */
- if (sk->urg_data == URG_NOTYET) {
- u32 ptr = sk->urg_seq - ntohl(th->seq) + (th->doff*4);
+ if (tp->urg_data == URG_NOTYET) {
+ u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4);
/* Is the urgent pointer pointing into this packet? */
if (ptr < len) {
- sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
+ tp->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
if (!sk->dead)
sk->data_ready(sk,0);
}
@@ -1335,33 +1382,39 @@ static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len
*/
static void prune_queue(struct sock *sk)
{
- struct tcp_opt *tp;
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
struct sk_buff * skb;
- SOCK_DEBUG(sk, "prune_queue: c=%x\n", sk->copied_seq);
+ SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq);
/* First Clean the out_of_order queue. */
/* Start with the end because there are probably the least
* useful packets (crossing fingers).
*/
- while ((skb = skb_dequeue_tail(&sk->out_of_order_queue))) {
+ while ((skb = skb_dequeue_tail(&tp->out_of_order_queue))) {
kfree_skb(skb);
if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
return;
}
- tp = &sk->tp_pinfo.af_tcp;
-
/* Now continue with the receive queue if it wasn't enough */
while ((skb = skb_peek_tail(&sk->receive_queue))) {
+ /* Never toss anything when we've seen the FIN.
+ * It's just too complex to recover from it.
+ */
+ if(skb->h.th->fin)
+ break;
+
/* Never remove packets that have been already acked */
if (before(skb->end_seq, tp->last_ack_sent+1)) {
printk(KERN_DEBUG "prune_queue: hit acked data c=%x,%x,%x\n",
- sk->copied_seq, skb->end_seq, tp->last_ack_sent);
+ tp->copied_seq, skb->end_seq, tp->last_ack_sent);
break;
}
skb_unlink(skb);
tp->rcv_nxt = skb->seq;
+ SOCK_DEBUG(sk, "prune_queue: removing %x-%x (c=%x)\n",
+ skb->seq, skb->end_seq, tp->copied_seq);
kfree_skb(skb);
if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf)
break;
@@ -1429,7 +1482,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
}
} else if (skb->ack_seq == tp->snd_una) {
/* Bulk data transfer: receiver */
-
if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
goto discard;
@@ -1441,18 +1493,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
skb_queue_tail(&sk->receive_queue, skb);
tp->rcv_nxt = skb->end_seq;
+ /* FIN bit check is not done since if FIN is set in
+ * this frame, the pred_flags won't match up. -DaveM
+ */
sk->data_ready(sk, 0);
tcp_delack_estimator(tp);
-
-#if 1 /* This checks for required window updates too. */
tp->delayed_acks++;
__tcp_ack_snd_check(sk);
-#else
- if (tp->delayed_acks++ == 0)
- tcp_send_delayed_ack(sk, HZ/2);
- else
- tcp_send_ack(sk);
-#endif
return 0;
}
}
@@ -1469,7 +1516,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
}
}
- if(th->syn && skb->seq != sk->syn_seq) {
+ if(th->syn && skb->seq != tp->syn_seq) {
SOCK_DEBUG(sk, "syn in established state\n");
tcp_statistics.TcpInErrs++;
tcp_reset(sk, skb);
@@ -1490,10 +1537,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
/* step 7: process the segment text */
queued = tcp_data(skb, sk, len);
- /* step 8: check the FIN bit */
- if (th->fin)
- (void) tcp_fin(skb, sk, th);
-
tcp_data_snd_check(sk);
/* If our receive queue has grown past its limits shrink it */
@@ -1657,19 +1700,19 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
tp->snd_wnd = htons(th->window) << tp->snd_wscale;
tp->snd_wl1 = skb->seq;
tp->snd_wl2 = skb->ack_seq;
-
tp->fin_seq = skb->seq;
tcp_set_state(sk, TCP_ESTABLISHED);
tcp_parse_options(th,tp,0);
- /* FIXME: need to make room for SACK still */
+
if (tp->wscale_ok == 0) {
tp->snd_wscale = tp->rcv_wscale = 0;
tp->window_clamp = min(tp->window_clamp,65535);
}
if (tp->tstamp_ok) {
- tp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: Define constant! */
- sk->dummy_th.doff += 3; /* reserve space of options */
+ tp->tcp_header_len =
+ sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+ sk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2);
} else
tp->tcp_header_len = sizeof(struct tcphdr);
if (tp->saw_tstamp) {
@@ -1680,14 +1723,30 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* Can't be earlier, doff would be wrong. */
tcp_send_ack(sk);
- if (tp->in_mss)
- sk->mss = min(sk->mss, tp->in_mss);
-
- /* Take out space for tcp options. */
- sk->mss -= tp->tcp_header_len - sizeof(struct tcphdr);
+ /* Check for the case where we tried to advertise
+ * a window including timestamp options, but did not
+ * end up using them for this connection.
+ */
+ if((tp->tstamp_ok == 0) && sysctl_tcp_timestamps)
+ sk->mss += TCPOLEN_TSTAMP_ALIGNED;
+ /* Now limit it if the other end negotiated a smaller
+ * value.
+ */
+ if (tp->in_mss) {
+ int real_mss = tp->in_mss;
+
+ /* We store MSS locally with the timestamp bytes
+ * subtracted, TCP's advertise it with them
+ * included. Account for this fact.
+ */
+ if(tp->tstamp_ok)
+ real_mss -= TCPOLEN_TSTAMP_ALIGNED;
+ sk->mss = min(sk->mss, real_mss);
+ }
+
sk->dummy_th.dest = th->source;
- sk->copied_seq = tp->rcv_nxt;
+ tp->copied_seq = tp->rcv_nxt;
if(!sk->dead) {
sk->state_change(sk);
@@ -1722,52 +1781,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
}
break;
-
- case TCP_TIME_WAIT:
- /* RFC 1122:
- * "When a connection is [...] on TIME-WAIT state [...]
- * [a TCP] MAY accept a new SYN from the remote TCP to
- * reopen the connection directly, if it:
- *
- * (1) assigns its initial sequence number for the new
- * connection to be larger than the largest sequence
- * number it used on the previous connection incarnation,
- * and
- *
- * (2) returns to TIME-WAIT state if the SYN turns out
- * to be an old duplicate".
- */
- if (th->syn && !th->rst && after(skb->seq, tp->rcv_nxt)) {
- __u32 isn;
-
- skb_orphan(skb);
- sk->err = ECONNRESET;
- tcp_set_state(sk, TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
-
- isn = tp->rcv_nxt + 128000;
- if (isn == 0)
- isn++;
-
- sk = tp->af_specific->get_sock(skb, th);
-
- if (sk == NULL || !ipsec_sk_policy(sk,skb))
- goto discard;
-
- skb_set_owner_r(skb, sk);
- tp = &sk->tp_pinfo.af_tcp;
-
- if(tp->af_specific->conn_request(sk, skb, opt, isn) < 0)
- return 1;
-
- goto discard;
- }
-
- break;
}
/* Parse the tcp_options present on this header.
- * By this point we really only expect timestamps and SACKs.
+ * By this point we really only expect timestamps.
* Note that this really has to be here and not later for PAWS
* (RFC1323) to work.
*/
@@ -1819,7 +1836,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* original syn.
*/
- if (th->syn && skb->seq!=sk->syn_seq) {
+ if (th->syn && skb->seq!=tp->syn_seq) {
tcp_reset(sk, skb);
return 1;
}
@@ -1833,7 +1850,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (acceptable) {
tcp_set_state(sk, TCP_ESTABLISHED);
sk->dummy_th.dest=th->source;
- sk->copied_seq = tp->rcv_nxt;
+ tp->copied_seq = tp->rcv_nxt;
if(!sk->dead)
sk->state_change(sk);
@@ -1850,7 +1867,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
break;
case TCP_FIN_WAIT1:
- if (tp->snd_una == sk->write_seq) {
+ if (tp->snd_una == tp->write_seq) {
sk->shutdown |= SEND_SHUTDOWN;
tcp_set_state(sk, TCP_FIN_WAIT2);
if (!sk->dead)
@@ -1861,12 +1878,12 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
break;
case TCP_CLOSING:
- if (tp->snd_una == sk->write_seq)
+ if (tp->snd_una == tp->write_seq)
tcp_time_wait(sk);
break;
case TCP_LAST_ACK:
- if (tp->snd_una == sk->write_seq) {
+ if (tp->snd_una == tp->write_seq) {
sk->shutdown = SHUTDOWN_MASK;
tcp_set_state(sk,TCP_CLOSE);
if (!sk->dead)
@@ -1874,13 +1891,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
goto discard;
}
break;
-
- case TCP_TIME_WAIT:
- /* Keep us in TIME_WAIT until we stop getting
- * packets, reset the timeout.
- */
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- break;
}
} else
goto discard;
@@ -1918,12 +1928,6 @@ step6:
break;
}
- /* step 8: check the FIN bit */
- if (th->fin) {
- if(tcp_fin(skb, sk, th) != 0)
- goto discard;
- }
-
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index e4f8981ac..91f21ff75 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.79 1998/01/15 22:40:47 freitag Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.109 1998/03/15 07:24:15 davem Exp $
*
* IPv4 specific functions
*
@@ -60,8 +60,6 @@
#include <linux/inet.h>
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_syncookies;
@@ -89,16 +87,19 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
*/
struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
+/* Ok, let's try this, I give up, we do need a local binding
+ * TCP hash as well as the others for fast bind/connect.
+ */
+struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+
/* All sockets in TCP_LISTEN state will be in here. This is the only table
* where wildcard'd TCP sockets can exist. Hash function here is just local
* port number.
*/
struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
-/* Ok, let's try this, I give up, we do need a local binding
- * TCP hash as well as the others for fast bind/connect.
- */
-struct sock *tcp_bound_hash[TCP_BHTABLE_SIZE];
+/* Register cache. */
+struct sock *tcp_regs[TCP_NUM_REGS];
/*
* This array holds the first and last local port number.
@@ -106,6 +107,7 @@ struct sock *tcp_bound_hash[TCP_BHTABLE_SIZE];
* 32768-61000
*/
int sysctl_local_port_range[2] = { 1024, 4999 };
+int tcp_port_rover = (1024 - 1);
static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
__u32 faddr, __u16 fport)
@@ -123,155 +125,135 @@ static __inline__ int tcp_sk_hashfn(struct sock *sk)
return tcp_hashfn(laddr, lport, faddr, fport);
}
-static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
+/* Invariant, sk->num is non-zero. */
+void tcp_bucket_unlock(struct sock *sk)
{
- struct sock *sk2;
- int retval = 0, sk_reuse = sk->reuse;
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
SOCKHASH_LOCK();
- sk2 = tcp_bound_hash[tcp_bhashfn(snum)];
- for(; sk2 != NULL; sk2 = sk2->bind_next) {
- if((sk2->num == snum) && (sk2 != sk)) {
- unsigned char state = sk2->state;
- int sk2_reuse = sk2->reuse;
-
- /* Two sockets can be bound to the same port if they're
- * bound to different interfaces.
- */
-
- if(sk->bound_dev_if != sk2->bound_dev_if)
- continue;
-
- if(!sk2->rcv_saddr || !sk->rcv_saddr) {
- if((!sk2_reuse) ||
- (!sk_reuse) ||
- (state == TCP_LISTEN)) {
- retval = 1;
- break;
- }
- } else if(sk2->rcv_saddr == sk->rcv_saddr) {
- if((!sk_reuse) ||
- (!sk2_reuse) ||
- (state == TCP_LISTEN)) {
- retval = 1;
- break;
- }
+ for(tb = tcp_bound_hash[tcp_bhashfn(snum)]; tb; tb = tb->next) {
+ if(tb->port == snum) {
+ if(tb->owners == NULL &&
+ (tb->flags & TCPB_FLAG_LOCKED)) {
+ tb->flags &= ~TCPB_FLAG_LOCKED;
+ tcp_inc_slow_timer(TCP_SLT_BUCKETGC);
}
+ break;
}
}
SOCKHASH_UNLOCK();
+}
- return retval;
+struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
+{
+ struct tcp_bind_bucket *tb;
+
+ tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
+ if(tb != NULL) {
+ struct tcp_bind_bucket **head =
+ &tcp_bound_hash[tcp_bhashfn(snum)];
+ tb->port = snum;
+ tb->flags = TCPB_FLAG_LOCKED;
+ tb->owners = NULL;
+ if((tb->next = *head) != NULL)
+ tb->next->pprev = &tb->next;
+ *head = tb;
+ tb->pprev = head;
+ }
+ return tb;
}
-static __inline__ int tcp_lport_inuse(int num)
+static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
{
- struct sock *sk = tcp_bound_hash[tcp_bhashfn(num)];
+ struct tcp_bind_bucket *tb;
+ int result = 0;
- for(; sk != NULL; sk = sk->bind_next) {
- if(sk->num == num)
- return 1;
+ SOCKHASH_LOCK();
+ for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+ (tb && (tb->port != snum));
+ tb = tb->next)
+ ;
+ if(tb && tb->owners) {
+ /* Fast path for reuse ports, see include/net/tcp.h for a very
+ * detailed description of why this works, and why it is worth
+ * the effort at all. -DaveM
+ */
+ if((tb->flags & TCPB_FLAG_FASTREUSE) &&
+ (sk->reuse != 0)) {
+ goto go_like_smoke;
+ } else {
+ struct sock *sk2;
+ int sk_reuse = sk->reuse;
+
+ /* We must walk the whole port owner list in this case. -DaveM */
+ for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
+ if(sk->bound_dev_if == sk2->bound_dev_if) {
+ if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
+ if(!sk2->rcv_saddr ||
+ !sk->rcv_saddr ||
+ (sk2->rcv_saddr == sk->rcv_saddr))
+ break;
+ }
+ }
+ }
+ if(sk2 != NULL)
+ result = 1;
+ }
}
- return 0;
+ if((result == 0) &&
+ (tb == NULL) &&
+ (tcp_bucket_create(snum) == NULL))
+ result = 1;
+go_like_smoke:
+ SOCKHASH_UNLOCK();
+ return result;
}
-/* Find a "good" local port, this is family independent.
- * There are several strategies working in unison here to
- * get the best possible performance. The current socket
- * load is kept track of, if it is zero there is a strong
- * likely hood that there is a zero length chain we will
- * find with a small amount of searching, else the load is
- * what we shoot for for when the chains all have at least
- * one entry. The base helps us walk the chains in an
- * order such that a good chain is found as quickly as possible. -DaveM
- */
unsigned short tcp_good_socknum(void)
{
- static int start = 0;
- static int binding_contour = 0;
- int best = 0;
- int size = 32767; /* a big num. */
- int retval = 0, i, end, bc;
+ struct tcp_bind_bucket *tb;
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+ int remaining = high - low;
+ int rover;
SOCKHASH_LOCK();
- if (start > sysctl_local_port_range[1] || start < sysctl_local_port_range[0])
- start = sysctl_local_port_range[0];
- i = tcp_bhashfn(start);
- end = i + TCP_BHTABLE_SIZE;
- bc = binding_contour;
- do {
- struct sock *sk = tcp_bound_hash[i&(TCP_BHTABLE_SIZE-1)];
- if(!sk) {
- /* find the smallest value no smaller than start
- * that has this hash value.
- */
- retval = tcp_bhashnext(start-1,i&(TCP_BHTABLE_SIZE-1));
-
- /* Check for decreasing load. */
- if (bc != 0)
- binding_contour = 0;
- goto done;
- } else {
- int j = 0;
- do { sk = sk->bind_next; } while (++j < size && sk);
- if (j < size) {
- best = i&(TCP_BHTABLE_SIZE-1);
- size = j;
- if (bc && size <= bc)
- goto verify;
- }
- }
- } while(++i != end);
- i = best;
-
- /* Socket load is increasing, adjust our load average. */
- binding_contour = size;
-verify:
- if (size < binding_contour)
- binding_contour = size;
-
- retval = tcp_bhashnext(start-1,i);
-
- best = retval; /* mark the starting point to avoid infinite loops */
- while(tcp_lport_inuse(retval)) {
- retval = tcp_bhashnext(retval,i);
- if (retval > sysctl_local_port_range[1]) /* Upper bound */
- retval = tcp_bhashnext(sysctl_local_port_range[0],i);
- if (retval == best) {
- /* This hash chain is full. No answer. */
- retval = 0;
- break;
+ rover = tcp_port_rover;
+ do {
+ rover += 1;
+ if((rover < low) || (rover > high))
+ rover = low;
+ tb = tcp_bound_hash[tcp_bhashfn(rover)];
+ for( ; tb; tb = tb->next) {
+ if(tb->port == rover)
+ goto next;
}
- }
-
-done:
- start = (retval + 1);
+ break;
+ next:
+ } while(--remaining > 0);
+ tcp_port_rover = rover;
+ if((remaining <= 0) || (tcp_bucket_create(rover) == NULL))
+ rover = 0;
SOCKHASH_UNLOCK();
- return retval;
+ return rover;
}
static void tcp_v4_hash(struct sock *sk)
{
- unsigned char state;
-
- SOCKHASH_LOCK();
- state = sk->state;
- if(state != TCP_CLOSE || !sk->dead) {
+ if (sk->state != TCP_CLOSE) {
struct sock **skp;
- if(state == TCP_LISTEN)
- skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
- else
- skp = &tcp_established_hash[tcp_sk_hashfn(sk)];
-
+ SOCKHASH_LOCK();
+ skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
if((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
*skp = sk;
sk->pprev = skp;
tcp_sk_bindify(sk);
+ SOCKHASH_UNLOCK();
}
- SOCKHASH_UNLOCK();
}
static void tcp_v4_unhash(struct sock *sk)
@@ -282,6 +264,7 @@ static void tcp_v4_unhash(struct sock *sk)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
+ tcp_reg_zap(sk);
tcp_sk_unbindify(sk);
}
SOCKHASH_UNLOCK();
@@ -293,30 +276,27 @@ static void tcp_v4_rehash(struct sock *sk)
SOCKHASH_LOCK();
state = sk->state;
- if(sk->pprev) {
+ if(sk->pprev != NULL) {
if(sk->next)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
- tcp_sk_unbindify(sk);
+ tcp_reg_zap(sk);
}
- if(state != TCP_CLOSE || !sk->dead) {
+ if(state != TCP_CLOSE) {
struct sock **skp;
- if(state == TCP_LISTEN) {
+ if(state == TCP_LISTEN)
skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
- } else {
- int hash= tcp_sk_hashfn(sk);
- if(state == TCP_TIME_WAIT)
- hash += (TCP_HTABLE_SIZE/2);
- skp = &tcp_established_hash[hash];
- }
+ else
+ skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
if((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
*skp = sk;
sk->pprev = skp;
- tcp_sk_bindify(sk);
+ if(state == TCP_LISTEN)
+ tcp_sk_bindify(sk);
}
SOCKHASH_UNLOCK();
}
@@ -360,37 +340,64 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d
return result;
}
+/* Until this is verified... -DaveM */
+/* #define USE_QUICKSYNS */
+
/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
* we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
*/
static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
- u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
+ u32 saddr, u16 sport,
+ u32 daddr, u16 dport, int dif)
{
unsigned short hnum = ntohs(dport);
struct sock *sk;
- int hash = tcp_hashfn(daddr, hnum, saddr, sport);
+ int hash;
+
+#ifdef USE_QUICKSYNS
+ /* Incomming connection short-cut. */
+ if (th && th->syn == 1 && th->ack == 0)
+ goto listener_shortcut;
+#endif
+
+ /* Check TCP register quick cache first. */
+ sk = TCP_RHASH(sport);
+ if(sk &&
+ sk->daddr == saddr && /* remote address */
+ sk->dummy_th.dest == sport && /* remote port */
+ sk->num == hnum && /* local port */
+ sk->rcv_saddr == daddr && /* local address */
+ (!sk->bound_dev_if || sk->bound_dev_if == dif))
+ goto hit;
/* Optimize here for direct hit, only listening connections can
- * have wildcards anyways. It is assumed that this code only
- * gets called from within NET_BH.
+ * have wildcards anyways.
*/
- for(sk = tcp_established_hash[hash]; sk; sk = sk->next)
+ hash = tcp_hashfn(daddr, hnum, saddr, sport);
+ for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
if(sk->daddr == saddr && /* remote address */
sk->dummy_th.dest == sport && /* remote port */
sk->num == hnum && /* local port */
sk->rcv_saddr == daddr && /* local address */
- (!sk->bound_dev_if || sk->bound_dev_if == dif))
+ (!sk->bound_dev_if || sk->bound_dev_if == dif)) {
+ if (sk->state == TCP_ESTABLISHED)
+ TCP_RHASH(sport) = sk;
goto hit; /* You sunk my battleship! */
-
+ }
+ }
/* Must check for a TIME_WAIT'er before going to listener hash. */
- for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
+ for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
if(sk->daddr == saddr && /* remote address */
sk->dummy_th.dest == sport && /* remote port */
sk->num == hnum && /* local port */
sk->rcv_saddr == daddr && /* local address */
(!sk->bound_dev_if || sk->bound_dev_if == dif))
goto hit;
-
+ }
+#ifdef USE_QUICKSYNS
+listener_shortcut:
+#endif
sk = tcp_v4_lookup_listener(daddr, hnum, dif);
hit:
return sk;
@@ -402,20 +409,11 @@ __inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport
}
#ifdef CONFIG_IP_TRANSPARENT_PROXY
-#define secondlist(hpnum, sk, fpass) \
-({ struct sock *s1; if(!(sk) && (fpass)--) \
- s1 = tcp_bound_hash[tcp_bhashfn(hpnum)]; \
- else \
- s1 = (sk); \
- s1; \
-})
-
-#define tcp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \
- secondlist((hpnum), tcp_bound_hash[tcp_bhashfn(hnum)],(fpass))
-
-#define tcp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \
- secondlist((hpnum),(sk)->bind_next,(fpass))
-
+/* Cleaned up a little and adapted to new bind bucket scheme.
+ * Oddly, this should increase performance here for
+ * transparent proxy, as tests within the inner loop have
+ * been eliminated. -DaveM
+ */
static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
unsigned short rnum, unsigned long laddr,
struct device *dev, unsigned short pnum,
@@ -436,51 +434,60 @@ static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
}
/* This code must run only from NET_BH. */
- for(s = tcp_v4_proxy_loop_init(hnum, hpnum, s, firstpass);
- s != NULL;
- s = tcp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) {
- if(s->num == hnum || s->num == hpnum) {
- int score = 0;
- if(s->dead && (s->state == TCP_CLOSE))
+ {
+ struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hnum)];
+ for( ; (tb && tb->port != hnum); tb = tb->next)
+ ;
+ if(tb == NULL)
+ goto next;
+ s = tb->owners;
+ }
+pass2:
+ for(; s; s = s->bind_next) {
+ int score = 0;
+ if(s->rcv_saddr) {
+ if((s->num != hpnum || s->rcv_saddr != paddr) &&
+ (s->num != hnum || s->rcv_saddr != laddr))
continue;
- if(s->rcv_saddr) {
- if((s->num != hpnum || s->rcv_saddr != paddr) &&
- (s->num != hnum || s->rcv_saddr != laddr))
- continue;
- score++;
- }
- if(s->daddr) {
- if(s->daddr != raddr)
- continue;
- score++;
- }
- if(s->dummy_th.dest) {
- if(s->dummy_th.dest != rnum)
- continue;
- score++;
- }
- if(s->bound_dev_if) {
- if(s->bound_dev_if != dif)
- continue;
- score++;
- }
- if(score == 4 && s->num == hnum) {
- result = s;
- break;
- } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
- result = s;
- badness = score;
- }
+ score++;
+ }
+ if(s->daddr) {
+ if(s->daddr != raddr)
+ continue;
+ score++;
+ }
+ if(s->dummy_th.dest) {
+ if(s->dummy_th.dest != rnum)
+ continue;
+ score++;
+ }
+ if(s->bound_dev_if) {
+ if(s->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if(score == 4 && s->num == hnum) {
+ result = s;
+ goto gotit;
+ } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
+ result = s;
+ badness = score;
}
}
+next:
+ if(firstpass--) {
+ struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hpnum)];
+ for( ; (tb && tb->port != hpnum); tb = tb->next)
+ ;
+ if(tb) {
+ s = tb->owners;
+ goto pass2;
+ }
+ }
+gotit:
return result;
}
-
-#undef secondlist
-#undef tcp_v4_proxy_loop_init
-#undef tcp_v4_proxy_loop_next
-
-#endif
+#endif /* CONFIG_IP_TRANSPARENT_PROXY */
static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
{
@@ -495,41 +502,35 @@ static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
/*
* Check that a TCP address is unique, don't allow multiple
- * connects to/from the same address
+ * connects to/from the same address. Actually we can optimize
+ * quite a bit, since the socket about to connect is still
+ * in TCP_CLOSE, a tcp_bind_bucket for the local port he will
+ * use will exist, with a NULL owners list. So check for that.
+ * The good_socknum and verify_bind scheme we use makes this
+ * work.
*/
-static int tcp_unique_address(u32 saddr, u16 snum, u32 daddr, u16 dnum)
+static int tcp_unique_address(struct sock *sk)
{
- int retval = 1, hashent = tcp_hashfn(saddr, snum, daddr, dnum);
- struct sock * sk;
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
+ int retval = 1;
- /* Make sure we are allowed to connect here.
- * But freeze the hash while we snoop around.
- */
+ /* Freeze the hash while we snoop around. */
SOCKHASH_LOCK();
- sk = tcp_established_hash[hashent];
- for (; sk != NULL; sk = sk->next) {
- if(sk->daddr == daddr && /* remote address */
- sk->dummy_th.dest == dnum && /* remote port */
- sk->num == snum && /* local port */
- sk->saddr == saddr) { /* local address */
- retval = 0;
- goto out;
- }
- }
-
- /* Must check TIME_WAIT'ers too. */
- sk = tcp_established_hash[hashent + (TCP_HTABLE_SIZE/2)];
- for (; sk != NULL; sk = sk->next) {
- if(sk->daddr == daddr && /* remote address */
- sk->dummy_th.dest == dnum && /* remote port */
- sk->num == snum && /* local port */
- sk->saddr == saddr) { /* local address */
- retval = 0;
- goto out;
+ tb = tcp_bound_hash[tcp_bhashfn(snum)];
+ for(; tb; tb = tb->next) {
+ if(tb->port == snum && tb->owners != NULL) {
+ /* Almost certainly the re-use port case, search the real hashes
+ * so it actually scales.
+ */
+ sk = __tcp_v4_lookup(NULL, sk->daddr, sk->dummy_th.dest,
+ sk->rcv_saddr, snum, sk->bound_dev_if);
+ if((sk != NULL) && (sk->state != TCP_LISTEN))
+ retval = 0;
+ break;
}
}
-out:
SOCKHASH_UNLOCK();
return retval;
}
@@ -578,8 +579,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return -ENETUNREACH;
}
- if (!tcp_unique_address(rt->rt_src, sk->num, rt->rt_dst,
- usin->sin_port)) {
+ if (!tcp_unique_address(sk)) {
ip_rt_put(rt);
return -EADDRNOTAVAIL;
}
@@ -587,7 +587,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
lock_sock(sk);
/* Do this early, so there is less state to unwind on failure. */
- buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);
+ buff = sock_wmalloc(sk, (MAX_SYN_SIZE + sizeof(struct sk_buff)),
+ 0, GFP_KERNEL);
if (buff == NULL) {
release_sock(sk);
ip_rt_put(rt);
@@ -605,15 +606,13 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk->dummy_th.dest = usin->sin_port;
- sk->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
+ tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
sk->dummy_th.source,
usin->sin_port);
-
tp->snd_wnd = 0;
tp->snd_wl1 = 0;
- tp->snd_wl2 = sk->write_seq;
- tp->snd_una = sk->write_seq;
-
+ tp->snd_wl2 = tp->write_seq;
+ tp->snd_una = tp->write_seq;
tp->rcv_nxt = 0;
sk->err = 0;
@@ -635,14 +634,22 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* No failure conditions can result past this point. */
+ /* We'll fix this up when we get a response from the other end.
+ * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
+ */
+ tp->tcp_header_len = sizeof(struct tcphdr) +
+ (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0);
+
th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
buff->h.th = th;
memcpy(th,(void *)&(sk->dummy_th), sizeof(*th));
- buff->seq = sk->write_seq++;
+ /* th->doff gets fixed up below if we tack on options. */
+
+ buff->seq = tp->write_seq++;
th->seq = htonl(buff->seq);
- tp->snd_nxt = sk->write_seq;
- buff->end_seq = sk->write_seq;
+ tp->snd_nxt = tp->write_seq;
+ buff->end_seq = tp->write_seq;
th->ack = 0;
th->syn = 1;
@@ -656,11 +663,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if(sk->mtu < 64)
sk->mtu = 64; /* Sanity limit */
- if (sk->user_mss)
- sk->mss = sk->user_mss;
- else
- sk->mss = (sk->mtu - sizeof(struct iphdr) -
- sizeof(struct tcphdr));
+ sk->mss = (sk->mtu - sizeof(struct iphdr) - tp->tcp_header_len);
+ if(sk->user_mss)
+ sk->mss = min(sk->mss, sk->user_mss);
if (sk->mss < 1) {
printk(KERN_DEBUG "intial sk->mss below 1\n");
@@ -675,9 +680,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
&tp->rcv_wscale);
th->window = htons(tp->rcv_wnd);
- tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
- sysctl_tcp_timestamps,
- sysctl_tcp_window_scaling,tp->rcv_wscale);
+ tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps,
+ sysctl_tcp_window_scaling, tp->rcv_wscale);
buff->csum = 0;
th->doff = (sizeof(*th)+ tmp)>>2;
@@ -686,9 +690,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tcp_set_state(sk,TCP_SYN_SENT);
/* Socket identity change complete, no longer
- * in TCP_CLOSE, so rehash.
+ * in TCP_CLOSE, so enter ourselves into the
+ * hash tables.
*/
- tcp_v4_rehash(sk);
+ tcp_v4_hash(sk);
tp->rto = rt->u.dst.rtt;
@@ -715,6 +720,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
static int tcp_v4_sendmsg(struct sock *sk, struct msghdr *msg, int len)
{
+ struct tcp_opt *tp;
int retval = -EINVAL;
/* Do sanity checking for sendmsg/sendto/send. */
@@ -740,7 +746,10 @@ static int tcp_v4_sendmsg(struct sock *sk, struct msghdr *msg, int len)
lock_sock(sk);
retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov,
msg->msg_flags);
-
+ /* Push out partial tail frames if needed. */
+ tp = &(sk->tp_pinfo.af_tcp);
+ if(tp->send_head && tcp_snd_test(sk, tp->send_head))
+ tcp_write_xmit(sk);
release_sock(sk);
out:
@@ -854,7 +863,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
th = (struct tcphdr*)(dp+(iph->ihl<<2));
sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
- if (sk == NULL) {
+ if (sk == NULL || sk->state == TCP_TIME_WAIT) {
icmp_statistics.IcmpInErrors++;
return;
}
@@ -1011,7 +1020,8 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
skb1->csum = csum_partial((u8 *) th1, sizeof(*th1), 0);
th1->check = tcp_v4_check(th1, sizeof(*th1), skb1->nh.iph->saddr,
skb1->nh.iph->daddr, skb1->csum);
- /* FIXME: should this carry an options packet? */
+
+ /* Do not place TCP options in a reset. */
ip_queue_xmit(skb1);
tcp_statistics.TcpOutSegs++;
tcp_statistics.TcpOutRsts++;
@@ -1063,6 +1073,14 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
mss = (skb->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
if (sk->user_mss)
mss = min(mss, sk->user_mss);
+ if(req->tstamp_ok)
+ mss -= TCPOLEN_TSTAMP_ALIGNED;
+ else
+ req->mss += TCPOLEN_TSTAMP_ALIGNED;
+
+ /* tcp_syn_build_options will do an skb_put() to obtain the TCP
+ * options bytes below.
+ */
skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
/* Don't offer more than they did.
@@ -1081,9 +1099,8 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
memset(th, 0, sizeof(struct tcphdr));
th->syn = 1;
th->ack = 1;
- th->source =
#ifdef CONFIG_IP_TRANSPARENT_PROXY
- req->lcl_port; /* LVE */
+ th->source = req->lcl_port; /* LVE */
#else
th->source = sk->dummy_th.source;
#endif
@@ -1104,16 +1121,7 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
req->rcv_wscale = rcv_wscale;
}
th->window = htons(req->rcv_wnd);
-
- /* XXX Partial csum of 4 byte quantity is itself! -DaveM
- * Yes, but it's a bit harder to special case now. It's
- * now computed inside the tcp_v4_send_check() to clean up
- * updating the options fields in the mainline send code.
- * If someone thinks this is really bad let me know and
- * I'll try to do it a different way. -- erics
- */
-
- tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+ tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok,
req->wscale_ok,req->rcv_wscale);
skb->csum = 0;
th->doff = (sizeof(*th) + tmp)>>2;
@@ -1232,14 +1240,15 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
req->rcv_isn = skb->seq;
- tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0;
tp.in_mss = 536;
tcp_parse_options(th,&tp,want_cookie);
- if (tp.saw_tstamp)
- req->ts_recent = tp.rcv_tsval;
req->mss = tp.in_mss;
+ if (tp.saw_tstamp) {
+ req->mss -= TCPOLEN_TSTAMP_ALIGNED;
+ req->ts_recent = tp.rcv_tsval;
+ }
req->tstamp_ok = tp.tstamp_ok;
- req->sack_ok = tp.sack_ok;
req->snd_wscale = tp.snd_wscale;
req->wscale_ok = tp.wscale_ok;
req->rmt_port = th->source;
@@ -1289,6 +1298,113 @@ error:
return 0;
}
+/* This is not only more efficient than what we used to do, it eliminates
+ * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM
+ */
+struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb)
+{
+ struct sock *newsk = sk_alloc(AF_INET, GFP_ATOMIC, 0);
+
+ if(newsk != NULL) {
+ struct tcp_opt *newtp;
+
+ memcpy(newsk, sk, sizeof(*newsk));
+ newsk->sklist_next = NULL;
+ newsk->daddr = req->af.v4_req.rmt_addr;
+ newsk->rcv_saddr = req->af.v4_req.loc_addr;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ newsk->num = ntohs(skb->h.th->dest);
+#endif
+ newsk->state = TCP_SYN_RECV;
+
+ /* Clone the TCP header template */
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ newsk->dummy_th.source = req->lcl_port;
+#endif
+ newsk->dummy_th.dest = req->rmt_port;
+ newsk->dummy_th.ack = 1;
+ newsk->dummy_th.doff = sizeof(struct tcphdr)>>2;
+
+ newsk->sock_readers = 0;
+ atomic_set(&newsk->rmem_alloc, 0);
+ skb_queue_head_init(&newsk->receive_queue);
+ atomic_set(&newsk->wmem_alloc, 0);
+ skb_queue_head_init(&newsk->write_queue);
+ newsk->saddr = req->af.v4_req.loc_addr;
+
+ newsk->done = 0;
+ newsk->proc = 0;
+ newsk->pair = NULL;
+ skb_queue_head_init(&newsk->back_log);
+ skb_queue_head_init(&newsk->error_queue);
+
+ /* Now setup tcp_opt */
+ newtp = &(newsk->tp_pinfo.af_tcp);
+ newtp->pred_flags = 0;
+ newtp->rcv_nxt = req->rcv_isn + 1;
+ newtp->snd_nxt = req->snt_isn + 1;
+ newtp->snd_una = req->snt_isn + 1;
+ newtp->srtt = 0;
+ newtp->ato = 0;
+ newtp->snd_wl1 = req->rcv_isn;
+ newtp->snd_wl2 = req->snt_isn;
+ newtp->snd_wnd = ntohs(skb->h.th->window);
+ newtp->max_window = newtp->snd_wnd;
+ newtp->pending = 0;
+ newtp->retransmits = 0;
+ newtp->last_ack_sent = req->rcv_isn + 1;
+ newtp->backoff = 0;
+ newtp->mdev = TCP_TIMEOUT_INIT;
+ newtp->snd_cwnd = 1;
+ newtp->rto = TCP_TIMEOUT_INIT;
+ newtp->packets_out = 0;
+ newtp->high_seq = 0;
+ newtp->snd_ssthresh = 0x7fffffff;
+ newtp->snd_cwnd_cnt = 0;
+ newtp->dup_acks = 0;
+ newtp->delayed_acks = 0;
+ init_timer(&newtp->retransmit_timer);
+ newtp->retransmit_timer.function = &tcp_retransmit_timer;
+ newtp->retransmit_timer.data = (unsigned long) newsk;
+ init_timer(&newtp->delack_timer);
+ newtp->delack_timer.function = &tcp_delack_timer;
+ newtp->delack_timer.data = (unsigned long) newsk;
+ skb_queue_head_init(&newtp->out_of_order_queue);
+ newtp->send_head = newtp->retrans_head = NULL;
+ newtp->rcv_wup = req->rcv_isn + 1;
+ newtp->write_seq = req->snt_isn + 1;
+ newtp->copied_seq = req->rcv_isn + 1;
+
+ newtp->saw_tstamp = 0;
+ newtp->in_mss = 536;
+
+ init_timer(&newtp->probe_timer);
+ newtp->probe_timer.function = &tcp_probe_timer;
+ newtp->probe_timer.data = (unsigned long) newsk;
+ newtp->probes_out = 0;
+ newtp->syn_seq = req->rcv_isn;
+ newtp->fin_seq = req->rcv_isn;
+ newtp->urg_data = 0;
+ tcp_synq_init(newtp);
+ newtp->syn_backlog = 0;
+
+ /* Back to base struct sock members. */
+ newsk->err = 0;
+ newsk->ack_backlog = 0;
+ newsk->max_ack_backlog = SOMAXCONN;
+ newsk->priority = 1;
+
+ /* IP layer stuff */
+ newsk->opt = req->af.v4_req.opt;
+ newsk->timeout = 0;
+ init_timer(&newsk->timer);
+ newsk->timer.function = &net_timer;
+ newsk->timer.data = (unsigned long) newsk;
+ newsk->socket = NULL;
+ }
+ return newsk;
+}
+
struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
struct open_request *req,
struct dst_entry *dst)
@@ -1301,98 +1417,14 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (sk->ack_backlog > sk->max_ack_backlog)
goto exit; /* head drop */
#endif
- newsk = sk_alloc(AF_INET, GFP_ATOMIC);
+ newsk = tcp_create_openreq_child(sk, req, skb);
if (!newsk)
goto exit;
#ifdef NEW_LISTEN
sk->ack_backlog++;
#endif
- memcpy(newsk, sk, sizeof(*newsk));
-
- /* Or else we die! -DaveM */
- newsk->sklist_next = NULL;
-
- newsk->opt = req->af.v4_req.opt;
- skb_queue_head_init(&newsk->write_queue);
- skb_queue_head_init(&newsk->receive_queue);
- skb_queue_head_init(&newsk->out_of_order_queue);
- skb_queue_head_init(&newsk->error_queue);
-
- /* Unused */
newtp = &(newsk->tp_pinfo.af_tcp);
- newtp->send_head = NULL;
- newtp->retrans_head = NULL;
-
- newtp->pending = 0;
-
- skb_queue_head_init(&newsk->back_log);
-
- newsk->prot->init(newsk);
-
- newtp->snd_cwnd_cnt = 0;
- newtp->backoff = 0;
- newsk->proc = 0;
- newsk->done = 0;
- newsk->pair = NULL;
- atomic_set(&newsk->wmem_alloc, 0);
- atomic_set(&newsk->rmem_alloc, 0);
- newsk->localroute = sk->localroute;
-
- newsk->err = 0;
- newsk->shutdown = 0;
- newsk->ack_backlog = 0;
-
- newtp->fin_seq = req->rcv_isn;
- newsk->syn_seq = req->rcv_isn;
- newsk->state = TCP_SYN_RECV;
- newsk->timeout = 0;
-
- newsk->write_seq = req->snt_isn;
-
- newtp->snd_wnd = ntohs(skb->h.th->window);
- newtp->max_window = newtp->snd_wnd;
- newtp->snd_wl1 = req->rcv_isn;
- newtp->snd_wl2 = newsk->write_seq;
- newtp->snd_una = newsk->write_seq++;
- newtp->snd_nxt = newsk->write_seq;
-
- newsk->urg_data = 0;
- newtp->packets_out = 0;
- newtp->retransmits = 0;
- newsk->linger=0;
- newsk->destroy = 0;
- init_timer(&newsk->timer);
- newsk->timer.data = (unsigned long) newsk;
- newsk->timer.function = &net_timer;
-
- tcp_init_xmit_timers(newsk);
-
- newsk->dummy_th.source =
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
- req->lcl_port; /* LVE */
-#else
- sk->dummy_th.source;
-#endif
- newsk->dummy_th.dest = req->rmt_port;
- newsk->sock_readers=0;
-
- newtp->last_ack_sent = newtp->rcv_nxt = req->rcv_isn + 1;
- newtp->rcv_wup = req->rcv_isn + 1;
- newsk->copied_seq = req->rcv_isn + 1;
-
- newsk->socket = NULL;
-
-#ifdef CONFIG_IP_TRANSPARENT_PROXY
- /*
- * Deal with possibly redirected traffic by setting num to
- * the intended destination port of the received packet.
- */
- newsk->num = ntohs(skb->h.th->dest);
-#endif
- newsk->daddr = req->af.v4_req.rmt_addr;
- newsk->saddr = req->af.v4_req.loc_addr;
- newsk->rcv_saddr = req->af.v4_req.loc_addr;
/* options / mss / route_cache */
if (dst == NULL) {
@@ -1418,7 +1450,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (newsk->mtu < 64)
newsk->mtu = 64;
- newtp->sack_ok = req->sack_ok;
newtp->tstamp_ok = req->tstamp_ok;
newtp->window_clamp = req->window_clamp;
newtp->rcv_wnd = req->rcv_wnd;
@@ -1433,8 +1464,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (newtp->tstamp_ok) {
newtp->ts_recent = req->ts_recent;
newtp->ts_recent_stamp = jiffies;
- newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define constant! */
- newsk->dummy_th.doff += 3;
+ newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+ newsk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2);
} else {
newtp->tcp_header_len = sizeof(struct tcphdr);
}
@@ -1446,13 +1477,13 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
/* Make sure our mtu is adjusted for headers. */
newsk->mss = min(req->mss, snd_mss) + sizeof(struct tcphdr) - newtp->tcp_header_len;
- tcp_v4_hash(newsk);
+ /* Must use the af_specific ops here for the case of IPv6 mapped. */
+ newsk->prot->hash(newsk);
add_to_prot_sklist(newsk);
return newsk;
exit:
- if (dst)
- dst_release(dst);
+ dst_release(dst);
return NULL;
}
@@ -1623,6 +1654,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
skb->used = 0;
+ if (sk->state == TCP_TIME_WAIT)
+ goto do_time_wait;
if (!sk->sock_readers)
return tcp_v4_do_rcv(sk, skb);
@@ -1636,6 +1669,12 @@ discard_it:
/* Discard frame. */
kfree_skb(skb);
return 0;
+
+do_time_wait:
+ if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+ skb, th, &(IPCB(skb)->opt), skb->len))
+ goto no_tcp_socket;
+ goto discard_it;
}
int tcp_v4_build_header(struct sock *sk, struct sk_buff *skb)
@@ -1770,33 +1809,21 @@ struct tcp_func ipv4_specific = {
sizeof(struct sockaddr_in)
};
+/* NOTE: A lot of things set to zero explicitly by call to
+ * sk_alloc() so need not be done here.
+ */
static int tcp_v4_init_sock(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- skb_queue_head_init(&sk->out_of_order_queue);
+ skb_queue_head_init(&tp->out_of_order_queue);
tcp_init_xmit_timers(sk);
- tp->srtt = 0;
tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
tp->mdev = TCP_TIMEOUT_INIT;
-
- tp->ato = 0;
- tp->iat = (HZ/5) << 3;
-
- /* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */
- /* tp->rcv_wnd = 8192; */
- tp->tstamp_ok = 0;
- tp->sack_ok = 0;
- tp->wscale_ok = 0;
tp->in_mss = 536;
- tp->snd_wscale = 0;
- tp->sacks = 0;
- tp->saw_tstamp = 0;
- tp->syn_backlog = 0;
- /*
- * See draft-stevens-tcpca-spec-01 for discussion of the
+ /* See draft-stevens-tcpca-spec-01 for discussion of the
* initialization of these values.
*/
tp->snd_cwnd = 1;
@@ -1804,9 +1831,7 @@ static int tcp_v4_init_sock(struct sock *sk)
sk->priority = 1;
sk->state = TCP_CLOSE;
-
sk->max_ack_backlog = SOMAXCONN;
-
sk->mtu = 576;
sk->mss = 536;
@@ -1824,6 +1849,7 @@ static int tcp_v4_init_sock(struct sock *sk)
static int tcp_v4_destroy_sock(struct sock *sk)
{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct sk_buff *skb;
tcp_clear_xmit_timers(sk);
@@ -1836,9 +1862,17 @@ static int tcp_v4_destroy_sock(struct sock *sk)
kfree_skb(skb);
/* Cleans up our, hopefuly empty, out_of_order_queue. */
- while((skb = skb_dequeue(&sk->out_of_order_queue)) != NULL)
+ while((skb = skb_dequeue(&tp->out_of_order_queue)) != NULL)
kfree_skb(skb);
+ /* Clean up a locked TCP bind bucket, this only happens if a
+ * port is allocated for a socket, but it never fully connects.
+ * In which case we will find num to be non-zero and daddr to
+ * be zero.
+ */
+ if(sk->daddr == 0 && sk->num != 0)
+ tcp_bucket_unlock(sk);
+
return 0;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index fbae5cfa6..d8c3c6480 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.51 1998/01/15 22:40:39 freitag Exp $
+ * Version: $Id: tcp_output.c,v 1.65 1998/03/15 12:07:03 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -34,8 +34,6 @@
#include <net/tcp.h>
-extern int sysctl_tcp_sack;
-extern int sysctl_tcp_tsack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
@@ -45,7 +43,8 @@ static __inline__ void clear_delayed_acks(struct sock * sk)
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
tp->delayed_acks = 0;
- sk->ack_backlog = 0;
+ if(tcp_in_quickack_mode(tp))
+ tp->ato = ((HZ/100)*2);
tcp_clear_xmit_timer(sk, TIME_DACK);
}
@@ -58,69 +57,26 @@ static __inline__ void update_send_head(struct sock *sk)
tp->send_head = NULL;
}
-static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- int nagle_check = 1;
- int len;
-
- /* RFC 1122 - section 4.2.3.4
- *
- * We must queue if
- *
- * a) The right edge of this frame exceeds the window
- * b) There are packets in flight and we have a small segment
- * [SWS avoidance and Nagle algorithm]
- * (part of SWS is done on packetization)
- * c) We are retransmiting [Nagle]
- * d) We have too many packets 'in flight'
- *
- * Don't use the nagle rule for urgent data.
- */
- len = skb->end_seq - skb->seq;
- if (!sk->nonagle && len < (sk->mss >> 1) && tp->packets_out &&
- !skb->h.th->urg)
- nagle_check = 0;
-
- return (nagle_check && tp->packets_out < tp->snd_cwnd &&
- !after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
- tp->retransmits == 0);
-}
-
/*
* This is the main buffer sending routine. We queue the buffer
* having checked it is sane seeming.
*/
-void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
+void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
{
- struct tcphdr * th = skb->h.th;
+ struct tcphdr *th = skb->h.th;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
int size;
/* Length of packet (not counting length of pre-tcp headers). */
size = skb->len - ((unsigned char *) th - skb->data);
- /* Sanity check it.. */
- if (size < sizeof(struct tcphdr) || size > skb->len) {
- printk(KERN_DEBUG "tcp_send_skb: bad skb "
- "(skb = %p, data = %p, th = %p, len = %u)\n",
- skb, skb->data, th, skb->len);
- kfree_skb(skb);
- return;
- }
-
- /* If we have queued a header size packet.. (these crash a few
- * tcp stacks if ack is not set)
- * FIXME: What is the equivalent below when we have options?
- */
- if (size == sizeof(struct tcphdr)) {
- /* If it's got a syn or fin discard. */
- if(!th->syn && !th->fin) {
- printk(KERN_DEBUG "tcp_send_skb: attempt to queue a bogon.\n");
- kfree_skb(skb);
- return;
- }
+ /* If there is a FIN or a SYN we add it onto the size. */
+ if (th->fin || th->syn) {
+ if(th->syn)
+ size++;
+ if(th->fin)
+ size++;
}
/* Actual processing. */
@@ -129,14 +85,14 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
skb_queue_tail(&sk->write_queue, skb);
- if (tp->send_head == NULL && tcp_snd_test(sk, skb)) {
+ if (!force_queue && tp->send_head == NULL && tcp_snd_test(sk, skb)) {
struct sk_buff * buff;
/* This is going straight out. */
tp->last_ack_sent = tp->rcv_nxt;
th->ack_seq = htonl(tp->rcv_nxt);
th->window = htons(tcp_select_window(sk));
- tcp_update_options((__u32 *)(th+1),tp);
+ tcp_update_options((__u32 *)(th + 1),tp);
tp->af_specific->send_check(sk, th, size, skb);
@@ -165,11 +121,10 @@ queue:
/* Remember where we must start sending. */
if (tp->send_head == NULL)
tp->send_head = skb;
- if (tp->packets_out == 0 && !tp->pending) {
+ if (!force_queue && tp->packets_out == 0 && !tp->pending) {
tp->pending = TIME_PROBE0;
tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
}
- return;
}
/*
@@ -214,8 +169,6 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
buff->h.th = nth;
memcpy(nth, th, tp->tcp_header_len);
- /* FIXME: Make sure this gets tcp options right. */
-
/* Correct the new header. */
buff->seq = skb->seq + len;
buff->end_seq = skb->end_seq;
@@ -281,14 +234,6 @@ static int tcp_wrxmit_frag(struct sock *sk, struct sk_buff *skb, int size)
tp->send_head = skb;
tp->packets_out--;
return -1;
- } else {
-#if 0
- /* If tcp_fragment succeded then
- * the send head is the resulting
- * fragment
- */
- tp->send_head = skb->next;
-#endif
}
return 0;
}
@@ -346,9 +291,10 @@ void tcp_write_xmit(struct sock *sk)
size = skb->len - (((unsigned char*)th) - skb->data);
}
- tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
+ tp->last_ack_sent = tp->rcv_nxt;
+ th->ack_seq = htonl(tp->rcv_nxt);
th->window = rcv_wnd;
- tcp_update_options((__u32 *)(th+1),tp);
+ tcp_update_options((__u32 *)(th + 1),tp);
tp->af_specific->send_check(sk, th, size, skb);
@@ -437,128 +383,44 @@ void tcp_write_xmit(struct sock *sk)
* taken by headers, and the remaining space will be available for TCP data.
* This should be accounted for correctly instead.
*/
-unsigned short tcp_select_window(struct sock *sk)
+u32 __tcp_select_window(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- int mss = sk->mss;
- long free_space = sock_rspace(sk) / 2;
- long window, cur_win;
+ unsigned int mss = sk->mss;
+ unsigned int free_space;
+ u32 window, cur_win;
+ free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2;
if (tp->window_clamp) {
free_space = min(tp->window_clamp, free_space);
mss = min(tp->window_clamp, mss);
- }
-#ifdef NO_ANK_FIX
- /* I am tired of this message */
- else
- printk(KERN_DEBUG "Clamp failure. Water leaking.\n");
-#endif
+ } else {
+ printk("tcp_select_window: tp->window_clamp == 0.\n");
+ }
if (mss < 1) {
mss = 1;
- printk(KERN_DEBUG "tcp_select_window: mss fell to 0.\n");
+ printk("tcp_select_window: sk->mss fell to 0.\n");
}
- /* compute the actual window i.e.
- * old_window - received_bytes_on_that_win
- */
- cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
- window = tp->rcv_wnd;
-
- if (cur_win < 0) {
- cur_win = 0;
-#ifdef NO_ANK_FIX
- /* And this too. */
- printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
- tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
-#endif
- }
-
- if (free_space < sk->rcvbuf/4 && free_space < mss/2)
+ cur_win = tcp_receive_window(tp);
+ if (free_space < sk->rcvbuf/4 && free_space < mss/2) {
window = 0;
-
- /* Get the largest window that is a nice multiple of mss.
- * Window clamp already applied above.
- * If our current window offering is within 1 mss of the
- * free space we just keep it. This prevents the divide
- * and multiply from happening most of the time.
- * We also don't do any window rounding when the free space
- * is too small.
- */
- if (window < free_space - mss && free_space > mss)
- window = (free_space/mss)*mss;
-
- /* Never shrink the offered window */
- if (window < cur_win)
- window = cur_win;
-
- tp->rcv_wnd = window;
- tp->rcv_wup = tp->rcv_nxt;
- return window >> tp->rcv_wscale; /* RFC1323 scaling applied */
-}
-
-#if 0
-/* Old algorithm for window selection */
-unsigned short tcp_select_window(struct sock *sk)
-{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- int mss = sk->mss;
- long free_space = sock_rspace(sk);
- long window, cur_win, usable;
-
- if (tp->window_clamp) {
- free_space = min(tp->window_clamp, free_space);
- mss = min(tp->window_clamp, mss);
- }
-
- /* compute the actual window i.e.
- * old_window - received_bytes_on_that_win
- */
- cur_win = tp->rcv_wnd - (tp->rcv_nxt - tp->rcv_wup);
- window = tp->rcv_wnd;
-
- if (cur_win < 0) {
- cur_win = 0;
- printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
- tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
- }
-
- /* RFC 1122:
- * "the suggested [SWS] avoidance algoritm for the receiver is to keep
- * RECV.NEXT + RCV.WIN fixed until:
- * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
- *
- * i.e. don't raise the right edge of the window until you can raise
- * it at least MSS bytes.
- */
-
- usable = free_space - cur_win;
- if (usable < 0)
- usable = 0;
-
- if (window < usable) {
- /* Window is not blocking the sender
- * and we have enough free space for it
- */
- if (cur_win > (sk->mss << 1))
- goto out;
- }
-
- if (window >= usable) {
- /* We are offering too much, cut it down...
- * but don't shrink the window
- */
- window = max(usable, cur_win);
} else {
- while ((usable - window) >= mss)
- window += mss;
+ /* Get the largest window that is a nice multiple of mss.
+ * Window clamp already applied above.
+ * If our current window offering is within 1 mss of the
+ * free space we just keep it. This prevents the divide
+ * and multiply from happening most of the time.
+ * We also don't do any window rounding when the free space
+ * is too small.
+ */
+ window = tp->rcv_wnd;
+ if ((window <= (free_space - mss)) || (window > free_space))
+ window = (free_space/mss)*mss;
}
-out:
- tp->rcv_wnd = window;
- tp->rcv_wup = tp->rcv_nxt;
return window;
}
-#endif
static int tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb)
{
@@ -729,84 +591,123 @@ void tcp_do_retransmit(struct sock *sk, int all)
}
}
-/*
- * Send a fin.
+/* Send a fin. The caller locks the socket for us. This cannot be
+ * allowed to fail queueing a FIN frame under any circumstances.
*/
-
void tcp_send_fin(struct sock *sk)
{
- struct tcphdr *th =(struct tcphdr *)&sk->dummy_th;
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- struct tcphdr *t1;
- struct sk_buff *buff;
- int tmp;
- buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_KERNEL);
- if (buff == NULL) {
- /* FIXME: This is a disaster if it occurs. */
- printk(KERN_INFO "tcp_send_fin: Impossible malloc failure");
- return;
- }
+ /* Optimization, tack on the FIN if we have a queue of
+ * unsent frames.
+ */
+ if(tp->send_head != NULL) {
+ struct sk_buff *tail = skb_peek_tail(&sk->write_queue);
+ struct tcphdr *th = tail->h.th;
+ int data_len;
+
+ /* Unfortunately tcp_write_xmit won't check for going over
+ * the MSS due to the FIN sequence number, so we have to
+ * watch out for it here.
+ */
+ data_len = (tail->tail - (((unsigned char *)th)+tp->tcp_header_len));
+ if(data_len >= sk->mss)
+ goto build_new_frame; /* ho hum... */
- /* Administrivia. */
- buff->csum = 0;
+ /* tcp_write_xmit() will checksum the header etc. for us. */
+ th->fin = 1;
+ tail->end_seq++;
+ } else {
+ struct sk_buff *buff;
+ struct tcphdr *th;
- /* Put in the IP header and routing stuff. */
- tmp = tp->af_specific->build_net_header(sk, buff);
- if (tmp < 0) {
- int t;
+build_new_frame:
+ buff = sock_wmalloc(sk,
+ (BASE_ACK_SIZE + tp->tcp_header_len +
+ sizeof(struct sk_buff)),
+ 1, GFP_KERNEL);
+ if (buff == NULL) {
+ /* We can only fail due to low memory situations, not
+ * due to going over our sndbuf limits (due to the
+ * force flag passed to sock_wmalloc). So just keep
+ * trying. We cannot allow this fail. The socket is
+ * still locked, so we need not check if the connection
+ * was reset in the meantime etc.
+ */
+ goto build_new_frame;
+ }
- /* FIXME: We must not throw this out. Eventually we must
- * put a FIN into the queue, otherwise it never gets queued.
- */
- kfree_skb(buff);
- sk->write_seq++;
- t = del_timer(&sk->timer);
- if (t)
- add_timer(&sk->timer);
- else
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return;
- }
-
- /* We ought to check if the end of the queue is a buffer and
- * if so simply add the fin to that buffer, not send it ahead.
- */
- t1 =(struct tcphdr *)skb_put(buff,tp->tcp_header_len);
- buff->h.th = t1;
- tcp_build_options((__u32 *)(t1+1),tp);
-
- memcpy(t1, th, sizeof(*t1));
- buff->seq = sk->write_seq;
- sk->write_seq++;
- buff->end_seq = sk->write_seq;
- t1->seq = htonl(buff->seq);
- t1->ack_seq = htonl(tp->rcv_nxt);
- t1->window = htons(tcp_select_window(sk));
- t1->fin = 1;
-
- tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff);
-
- /* The fin can only be transmited after the data. */
- skb_queue_tail(&sk->write_queue, buff);
- if (tp->send_head == NULL) {
- /* FIXME: BUG! we need to check if the fin fits into the window
- * here. If not we need to do window probing (sick, but true)
+ /* Administrivia. */
+ buff->csum = 0;
+
+ /* Put in the IP header and routing stuff.
+ *
+ * FIXME:
+ * We can fail if the interface for the route
+ * this socket takes goes down right before
+ * we get here. ANK is there a way to point
+ * this into a "black hole" route in such a
+ * case? Ideally, we should still be able to
+ * queue this and let the retransmit timer
+ * keep trying until the destination becomes
+ * reachable once more. -DaveM
*/
- struct sk_buff *skb1;
+ if(tp->af_specific->build_net_header(sk, buff) < 0) {
+ kfree_skb(buff);
+ goto update_write_seq;
+ }
+ th = (struct tcphdr *) skb_put(buff, tp->tcp_header_len);
+ buff->h.th = th;
- tp->packets_out++;
- tp->snd_nxt = sk->write_seq;
- buff->when = jiffies;
+ memcpy(th, (void *) &(sk->dummy_th), sizeof(*th));
+ th->seq = htonl(tp->write_seq);
+ th->fin = 1;
+ tcp_build_options((__u32 *)(th + 1), tp);
- skb1 = skb_clone(buff, GFP_KERNEL);
- if (skb1) {
- skb_set_owner_w(skb1, sk);
- tp->af_specific->queue_xmit(skb1);
- }
+ /* This makes sure we do things like abide by the congestion
+ * window and other constraints which prevent us from sending.
+ */
+ tcp_send_skb(sk, buff, 0);
+ }
+update_write_seq:
+ /* So that we recognize the ACK coming back for
+ * this FIN as being legitimate.
+ */
+ tp->write_seq++;
+}
- if (!tcp_timer_is_set(sk, TIME_RETRANS))
- tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+/* We get here when a process closes a file descriptor (either due to
+ * an explicit close() or as a byproduct of exit()'ing) and there
+ * was unread data in the receive queue. This behavior is recommended
+ * by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM
+ */
+void tcp_send_active_reset(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+ struct tcphdr *th;
+
+again:
+ /* NOTE: No TCP options attached and we never retransmit this. */
+ skb = sock_wmalloc(sk, (BASE_ACK_SIZE + sizeof(*th)), 1, GFP_KERNEL);
+ if(skb == NULL)
+ goto again;
+ skb->csum = 0;
+ if(tp->af_specific->build_net_header(sk, skb) < 0) {
+ kfree_skb(skb);
+ } else {
+ th = (struct tcphdr *) skb_put(skb, sizeof(*th));
+ memcpy(th, &(sk->dummy_th), sizeof(*th));
+ th->seq = htonl(tp->write_seq);
+ th->rst = 1;
+ th->doff = sizeof(*th) / 4;
+ tp->last_ack_sent = tp->rcv_nxt;
+ th->ack_seq = htonl(tp->rcv_nxt);
+ th->window = htons(tcp_select_window(sk));
+ tp->af_specific->send_check(sk, th, sizeof(*th), skb);
+ tp->af_specific->queue_xmit(skb);
+ tcp_statistics.TcpOutSegs++;
+ tcp_statistics.TcpOutRsts++;
}
}
@@ -814,6 +715,9 @@ void tcp_send_fin(struct sock *sk)
* a SYN packet that crossed the incoming SYN that caused this routine
* to get called. If this assumption fails then the initial rcv_wnd
* and rcv_wscale values will not be correct.
+ *
+ * XXX When you have time Dave, redo this to use tcp_send_skb() just
+ * XXX like tcp_send_fin() above now does.... -DaveM
*/
int tcp_send_synack(struct sock *sk)
{
@@ -823,7 +727,7 @@ int tcp_send_synack(struct sock *sk)
struct tcphdr *th;
int tmp;
- skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
+ skb = sock_wmalloc(sk, MAX_SYN_SIZE + sizeof(struct sk_buff), 1, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -855,8 +759,7 @@ int tcp_send_synack(struct sock *sk)
tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt);
tmp = tcp_syn_build_options(skb, sk->mss,
- tp->sack_ok, tp->tstamp_ok,
- tp->wscale_ok,tp->rcv_wscale);
+ tp->tstamp_ok, tp->wscale_ok, tp->rcv_wscale);
skb->csum = 0;
th->doff = (sizeof(*th) + tmp)>>2;
@@ -880,31 +783,24 @@ int tcp_send_synack(struct sock *sk)
}
/*
- * Set up the timers for sending a delayed ack..
- *
- * rules for delaying an ack:
- * - delay time <= 0.5 HZ
- * - must send at least every 2 full sized packets
- * - we don't have a window update to send
+ * Send out a delayed ack, the caller does the policy checking
+ * to see if we should even be here. See tcp_input.c:tcp_ack_snd_check()
+ * for details.
*/
-void tcp_send_delayed_ack(struct sock * sk, int max_timeout)
+void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout)
{
- struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- unsigned long timeout, now;
+ unsigned long timeout;
- /* Calculate new timeout. */
- now = jiffies;
+ /* Stay within the limit we were given */
timeout = tp->ato;
-
- if (timeout > max_timeout ||
- ((tp->rcv_nxt - tp->rcv_wup) > (sk->mss << 2)))
- timeout = now;
- else
- timeout += now;
+ if (timeout > max_timeout)
+ timeout = max_timeout;
+ timeout += jiffies;
/* Use new timeout only if there wasn't a older one earlier. */
- if (!del_timer(&tp->delack_timer) || timeout < tp->delack_timer.expires)
+ if ((!tp->delack_timer.prev || !del_timer(&tp->delack_timer)) ||
+ (timeout < tp->delack_timer.expires))
tp->delack_timer.expires = timeout;
add_timer(&tp->delack_timer);
@@ -928,8 +824,6 @@ void tcp_send_ack(struct sock *sk)
/* We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent.
- * FIXME: is it better to waste memory here and use a
- * constant sized ACK?
*/
buff = sock_wmalloc(sk, BASE_ACK_SIZE + tp->tcp_header_len, 1, GFP_ATOMIC);
if (buff == NULL) {
@@ -938,7 +832,7 @@ void tcp_send_ack(struct sock *sk)
* bandwidth on slow links to send a spare ack than
* resend packets.
*/
- tcp_send_delayed_ack(sk, HZ/2);
+ tcp_send_delayed_ack(tp, HZ/2);
return;
}
@@ -956,22 +850,16 @@ void tcp_send_ack(struct sock *sk)
th = (struct tcphdr *)skb_put(buff,tp->tcp_header_len);
memcpy(th, &sk->dummy_th, sizeof(struct tcphdr));
- tcp_build_options((__u32 *)(th+1),tp);
/* Swap the send and the receive. */
th->window = ntohs(tcp_select_window(sk));
th->seq = ntohl(tp->snd_nxt);
tp->last_ack_sent = tp->rcv_nxt;
th->ack_seq = htonl(tp->rcv_nxt);
+ tcp_build_and_update_options((__u32 *)(th + 1), tp);
/* Fill in the packet and send it. */
tp->af_specific->send_check(sk, th, tp->tcp_header_len, buff);
-
-#if 0
- SOCK_DEBUG(sk, "\rtcp_send_ack: seq %x ack %x\n",
- tp->snd_nxt, tp->rcv_nxt);
-#endif
-
tp->af_specific->queue_xmit(buff);
tcp_statistics.TcpOutSegs++;
}
@@ -1017,6 +905,7 @@ void tcp_write_wakeup(struct sock *sk)
}
th = skb->h.th;
+ tcp_update_options((__u32 *)(th + 1), tp);
tp->af_specific->send_check(sk, th, th->doff * 4 + win_size, skb);
buff = skb_clone(skb, GFP_ATOMIC);
if (buff == NULL)
@@ -1047,25 +936,19 @@ void tcp_write_wakeup(struct sock *sk)
return;
}
- t1 = (struct tcphdr *) skb_put(buff, sizeof(struct tcphdr));
+ t1 = (struct tcphdr *) skb_put(buff, tp->tcp_header_len);
memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
- /* FIXME: should zero window probes have SACK and/or TIMESTAMP data?
- * If so we have to tack them on here.
- */
/* Use a previous sequence.
* This should cause the other end to send an ack.
*/
t1->seq = htonl(tp->snd_nxt-1);
-/* t1->fin = 0; -- We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */
t1->ack_seq = htonl(tp->rcv_nxt);
t1->window = htons(tcp_select_window(sk));
+ tcp_build_and_update_options((__u32 *)(t1 + 1), tp);
- /* Value from dummy_th may be larger. */
- t1->doff = sizeof(struct tcphdr)/4;
-
- tp->af_specific->send_check(sk, t1, sizeof(*t1), buff);
+ tp->af_specific->send_check(sk, t1, tp->tcp_header_len, buff);
}
/* Send it. */
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 76ccedab2..fdf8f50ec 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_timer.c,v 1.5 1998/03/03 01:23:44 ralf Exp $
+ * Version: $Id: tcp_timer.c,v 1.6 1998/03/17 22:18:35 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -31,6 +31,7 @@ int sysctl_tcp_retries2 = TCP_RETR2;
static void tcp_sltimer_handler(unsigned long);
static void tcp_syn_recv_timer(unsigned long);
static void tcp_keepalive(unsigned long data);
+static void tcp_bucketgc(unsigned long);
struct timer_list tcp_slow_timer = {
NULL, NULL,
@@ -41,7 +42,8 @@ struct timer_list tcp_slow_timer = {
struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {
{ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK */
- {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive} /* KEEPALIVE */
+ {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}, /* KEEPALIVE */
+ {ATOMIC_INIT(0), TCP_BUCKETGC_PERIOD, 0, tcp_bucketgc} /* BUCKETGC */
};
const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
@@ -87,20 +89,24 @@ void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when)
* The delayed ack timer can be set if we are changing the
* retransmit timer when removing acked frames.
*/
- del_timer(&tp->probe_timer);
- del_timer(&tp->retransmit_timer);
+ if(tp->probe_timer.prev)
+ del_timer(&tp->probe_timer);
+ if(tp->retransmit_timer.prev)
+ del_timer(&tp->retransmit_timer);
tp->retransmit_timer.expires=jiffies+when;
add_timer(&tp->retransmit_timer);
break;
case TIME_DACK:
- del_timer(&tp->delack_timer);
+ if(tp->delack_timer.prev)
+ del_timer(&tp->delack_timer);
tp->delack_timer.expires=jiffies+when;
add_timer(&tp->delack_timer);
break;
case TIME_PROBE0:
- del_timer(&tp->probe_timer);
+ if(tp->probe_timer.prev)
+ del_timer(&tp->probe_timer);
tp->probe_timer.expires=jiffies+when;
add_timer(&tp->probe_timer);
break;
@@ -118,9 +124,12 @@ void tcp_clear_xmit_timers(struct sock *sk)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- del_timer(&tp->retransmit_timer);
- del_timer(&tp->delack_timer);
- del_timer(&tp->probe_timer);
+ if(tp->retransmit_timer.prev)
+ del_timer(&tp->retransmit_timer);
+ if(tp->delack_timer.prev)
+ del_timer(&tp->delack_timer);
+ if(tp->probe_timer.prev)
+ del_timer(&tp->probe_timer);
}
static int tcp_write_err(struct sock *sk, int force)
@@ -131,9 +140,8 @@ static int tcp_write_err(struct sock *sk, int force)
tcp_clear_xmit_timers(sk);
/* Time wait the socket. */
- if (!force && (1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
- tcp_set_state(sk,TCP_TIME_WAIT);
- tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ if (!force && ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) {
+ tcp_time_wait(sk);
} else {
/* Clean up time. */
tcp_set_state(sk, TCP_CLOSE);
@@ -173,9 +181,8 @@ static int tcp_write_timeout(struct sock *sk)
return 1;
}
-
-void tcp_delack_timer(unsigned long data) {
-
+void tcp_delack_timer(unsigned long data)
+{
struct sock *sk = (struct sock*)data;
if(sk->zapped)
@@ -185,8 +192,8 @@ void tcp_delack_timer(unsigned long data) {
tcp_read_wakeup(sk);
}
-void tcp_probe_timer(unsigned long data) {
-
+void tcp_probe_timer(unsigned long data)
+{
struct sock *sk = (struct sock*)data;
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
@@ -212,10 +219,9 @@ void tcp_probe_timer(unsigned long data) {
sk->err = ETIMEDOUT;
sk->error_report(sk);
- /* Time wait the socket. */
if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
- tcp_set_state(sk, TCP_TIME_WAIT);
- tcp_reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ /* Time wait the socket. */
+ tcp_time_wait(sk);
} else {
/* Clean up time. */
tcp_set_state(sk, TCP_CLOSE);
@@ -252,6 +258,35 @@ static __inline__ int tcp_keepopen_proc(struct sock *sk)
return res;
}
+/* Garbage collect TCP bind buckets. */
+static void tcp_bucketgc(unsigned long __unused)
+{
+ int i;
+
+ for(i = 0; i < TCP_BHTABLE_SIZE; i++) {
+ struct tcp_bind_bucket *tb = tcp_bound_hash[i];
+
+ while(tb) {
+ struct tcp_bind_bucket *next = tb->next;
+
+ if((tb->owners == NULL) &&
+ !(tb->flags & TCPB_FLAG_LOCKED)) {
+ /* Eat timer reference. */
+ tcp_dec_slow_timer(TCP_SLT_BUCKETGC);
+
+ /* Unlink bucket. */
+ if(tb->next)
+ tb->next->pprev = tb->pprev;
+ *tb->pprev = tb->next;
+
+ /* Finally, free it up. */
+ kmem_cache_free(tcp_bucket_cachep, tb);
+ }
+ tb = next;
+ }
+ }
+}
+
/*
* Check all sockets for keepalive timer
* Called every 75 seconds
diff --git a/net/ipv4/timer.c b/net/ipv4/timer.c
index fe02b3f4c..79ae3309e 100644
--- a/net/ipv4/timer.c
+++ b/net/ipv4/timer.c
@@ -5,7 +5,7 @@
*
* TIMER - implementation of software timers for IP.
*
- * Version: $Id: timer.c,v 1.7 1997/09/17 18:50:26 freitag Exp $
+ * Version: $Id: timer.c,v 1.2 1997/12/16 05:37:48 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -52,76 +52,52 @@
void net_delete_timer (struct sock *t)
{
- unsigned long flags;
-
- save_flags (flags);
- cli();
-
+ if(t->timer.prev)
+ del_timer (&t->timer);
t->timeout = 0;
- del_timer (&t->timer);
-
- restore_flags (flags);
}
void net_reset_timer (struct sock *t, int timeout, unsigned long len)
{
net_delete_timer (t);
t->timeout = timeout;
-#if 1
- /* FIXME: ??? */
- if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
- len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
-#endif
t->timer.expires = jiffies+len;
add_timer (&t->timer);
}
-
-/*
- * Now we will only be called whenever we need to do
- * something, but we must be sure to process all of the
- * sockets that need it.
+/* Now we will only be called whenever we need to do
+ * something, but we must be sure to process all of the
+ * sockets that need it.
*/
-
void net_timer (unsigned long data)
{
struct sock *sk = (struct sock*)data;
int why = sk->timeout;
- /*
- * only process if socket is not in use
- */
-
- if (sk->sock_readers)
- {
+ /* Only process if socket is not in use. */
+ if (sk->sock_readers) {
sk->timer.expires = jiffies+HZ;
add_timer(&sk->timer);
- sti();
return;
}
/* Always see if we need to send an ack. */
-
- if (sk->ack_backlog && !sk->zapped)
- {
+ if (sk->tp_pinfo.af_tcp.delayed_acks && !sk->zapped) {
sk->prot->read_wakeup (sk);
- if (! sk->dead)
- sk->data_ready(sk,0);
+ if (!sk->dead)
+ sk->data_ready(sk,0);
}
/* Now we need to figure out why the socket was on the timer. */
-
- switch (why)
- {
+ switch (why) {
case TIME_DONE:
- /* If the socket hasn't been closed off, re-try a bit later */
+ /* If the socket hasn't been closed off, re-try a bit later. */
if (!sk->dead) {
net_reset_timer(sk, TIME_DONE, TCP_DONE_TIME);
break;
}
- if (sk->state != TCP_CLOSE)
- {
+ if (sk->state != TCP_CLOSE) {
printk (KERN_DEBUG "non CLOSE socket in time_done\n");
break;
}
@@ -129,11 +105,9 @@ void net_timer (unsigned long data)
break;
case TIME_DESTROY:
- /*
- * We've waited for a while for all the memory associated with
- * the socket to be freed.
- */
-
+ /* We've waited for a while for all the memory associated with
+ * the socket to be freed.
+ */
destroy_sock(sk);
break;
@@ -148,7 +122,8 @@ void net_timer (unsigned long data)
break;
default:
- printk (KERN_DEBUG "net_timer: timer expired - reason %d is unknown\n", why);
+ /* I want to see these... */
+ printk ("net_timer: timer expired - reason %d is unknown\n", why);
break;
}
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f355caa85..6ba50b280 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.3 1998/03/03 01:23:44 ralf Exp $
+ * Version: $Id: udp.c,v 1.4 1998/03/17 22:18:36 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -828,7 +828,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
* of this packet since that is all
* that will be read.
*/
- amount = skb->tail - skb->h.raw;
+ amount = skb->len - sizeof(struct udphdr);
}
return put_user(amount, (int *)arg);
}
@@ -1033,17 +1033,18 @@ static inline void udp_deliver(struct sock *sk, struct sk_buff *skb)
/*
* Multicasts and broadcasts go to each listener.
+ *
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
*/
static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
u32 saddr, u32 daddr)
{
struct sock *sk;
- int given = 0;
- SOCKHASH_LOCK();
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr);
- if(sk) {
+ if (sk) {
struct sock *sknext = NULL;
do {
@@ -1058,10 +1059,7 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
udp_deliver(sk, skb1);
sk = sknext;
} while(sknext);
- given = 1;
- }
- SOCKHASH_UNLOCK();
- if(!given)
+ } else
kfree_skb(skb);
return 0;
}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c4faba4b7..4a4060601 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: addrconf.c,v 1.32 1997/12/27 20:41:18 kuznet Exp $
+ * $Id: addrconf.c,v 1.37 1998/03/08 20:52:46 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1753,6 +1753,8 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf
t->sysctl_header = register_sysctl_table(t->addrconf_root_dir, 0);
if (t->sysctl_header == NULL)
kfree(t);
+ else
+ p->sysctl = t;
}
static void addrconf_sysctl_unregister(struct ipv6_devconf *p)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index b0a0eb702..bc5ba892a 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.24 1997/12/13 21:53:08 kuznet Exp $
+ * $Id: af_inet6.c,v 1.28 1998/03/08 05:56:49 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -71,7 +71,7 @@ static int inet6_create(struct socket *sock, int protocol)
struct sock *sk;
struct proto *prot;
- sk = sk_alloc(AF_INET6, GFP_KERNEL);
+ sk = sk_alloc(AF_INET6, GFP_KERNEL, 1);
if (sk == NULL)
goto do_oom;
@@ -139,8 +139,7 @@ static int inet6_create(struct socket *sock, int protocol)
* creation time automatically shares.
*/
sk->dummy_th.source = ntohs(sk->num);
- if(sk->prot->hash)
- sk->prot->hash(sk);
+ sk->prot->hash(sk);
add_to_prot_sklist(sk);
}
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 6b7508666..af29057ec 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: exthdrs.c,v 1.4 1997/03/18 18:24:29 davem Exp $
+ * $Id: exthdrs.c,v 1.5 1998/02/12 07:43:39 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index b84dc9268..96867403b 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.12 1997/12/13 21:53:10 kuznet Exp $
+ * $Id: icmp.c,v 1.13 1998/02/12 07:43:41 davem Exp $
*
* Based on net/ipv4/icmp.c
*
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 15ce420ac..9fce1acca 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.10 1997/12/13 21:53:10 kuznet Exp $
+ * $Id: ip6_fib.c,v 1.11 1998/03/08 05:56:50 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/ip6_fw.c b/net/ipv6/ip6_fw.c
index 7316a30f1..3c3a0cfc5 100644
--- a/net/ipv6/ip6_fw.c
+++ b/net/ipv6/ip6_fw.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fw.c,v 1.8 1997/12/13 21:53:11 kuznet Exp $
+ * $Id: ip6_fw.c,v 1.9 1998/02/12 07:43:42 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index ead32047a..71ad7e1a0 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.7 1997/09/20 20:48:27 davem Exp $
+ * $Id: ip6_input.c,v 1.8 1998/02/12 07:43:43 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 67b81d041..13029e175 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.7 1997/12/29 19:52:46 kuznet Exp $
+ * $Id: ip6_output.c,v 1.9 1998/03/08 05:56:50 davem Exp $
*
* Based on linux/net/ipv4/ip_output.c
*
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index f2ef3fd76..c6714eea3 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -7,7 +7,7 @@
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.16 1997/12/13 21:53:13 kuznet Exp $
+ * $Id: ipv6_sockglue.c,v 1.17 1998/03/08 05:56:51 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3fb0680bc..ce37117a3 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -132,7 +132,7 @@ struct neigh_table nd_tbl =
pndisc_destructor,
pndisc_redo,
{ NULL, NULL, &nd_tbl, 0, NULL, NULL,
- 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 0, 64 },
+ 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 0 },
30*HZ, 128, 512, 1024,
};
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index b9b811e35..b87d4696b 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -7,7 +7,7 @@
* PROC file system. This is very similar to the IPv4 version,
* except it reports the sockets in the INET6 address family.
*
- * Version: $Id: proc.c,v 1.4 1997/04/20 22:50:44 schenk Exp $
+ * Version: $Id: proc.c,v 1.6 1998/03/13 08:02:19 davem Exp $
*
* Authors: David S. Miller (davem@caip.rutgers.edu)
*
@@ -21,6 +21,7 @@
#include <linux/net.h>
#include <linux/in6.h>
#include <net/sock.h>
+#include <net/tcp.h>
#include <net/transp_v6.h>
/* This is the main implementation workhorse of all these routines. */
@@ -52,21 +53,35 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
SOCKHASH_LOCK();
sp = pro->sklist_next;
while(sp != (struct sock *)pro) {
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
+ int tw_bucket = 0;
+
pos += 149;
if(pos < offset)
goto next;
tp = &(sp->tp_pinfo.af_tcp);
- dest = &sp->net_pinfo.af_inet6.daddr;
- src = &sp->net_pinfo.af_inet6.rcv_saddr;
+ if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+ tw_bucket = 1;
+ dest = &tw->v6_daddr;
+ src = &tw->v6_rcv_saddr;
+ } else {
+ dest = &sp->net_pinfo.af_inet6.daddr;
+ src = &sp->net_pinfo.af_inet6.rcv_saddr;
+ }
destp = ntohs(sp->dummy_th.dest);
srcp = ntohs(sp->dummy_th.source);
-
- timer_active1 = del_timer(&tp->retransmit_timer);
- timer_active2 = del_timer(&sp->timer);
- if(!timer_active1) tp->retransmit_timer.expires = 0;
- if(!timer_active2) sp->timer.expires = 0;
- timer_active = 0;
- timer_expires = (unsigned) -1;
+ if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+ timer_active1 = timer_active2 = 0;
+ timer_active = 3;
+ timer_expires = tw->timer.expires;
+ } else {
+ timer_active1 = del_timer(&tp->retransmit_timer);
+ timer_active2 = del_timer(&sp->timer);
+ if(!timer_active1) tp->retransmit_timer.expires = 0;
+ if(!timer_active2) sp->timer.expires = 0;
+ timer_active = 0;
+ timer_expires = (unsigned) -1;
+ }
if(timer_active1 && tp->retransmit_timer.expires < timer_expires) {
timer_active = timer_active1;
timer_expires = tp->retransmit_timer.expires;
@@ -75,6 +90,8 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
timer_active = timer_active2;
timer_expires = sp->timer.expires;
}
+ if(timer_active == 0)
+ timer_expires = jiffies;
sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
i,
@@ -83,13 +100,23 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
sp->state,
- format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc),
- format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc),
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->write_seq-tp->snd_una :
+ atomic_read(&sp->wmem_alloc)),
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->rcv_nxt-tp->copied_seq :
+ atomic_read(&sp->rmem_alloc)),
timer_active, timer_expires-jiffies,
- tp->retransmits,
- sp->socket ? sp->socket->inode->i_uid:0,
- timer_active?sp->timeout:0,
- sp->socket ? sp->socket->inode->i_ino:0);
+ (tw_bucket ? 0 : tp->retransmits),
+ ((!tw_bucket && sp->socket) ?
+ sp->socket->inode->i_uid : 0),
+ (!tw_bucket && timer_active) ? sp->timeout : 0,
+ ((!tw_bucket && sp->socket) ?
+ sp->socket->inode->i_ino : 0));
if(timer_active1) add_timer(&tp->retransmit_timer);
if(timer_active2) add_timer(&sp->timer);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4ee1b13ad..5b182b7ef 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.16 1997/12/29 19:52:48 kuznet Exp $
+ * $Id: raw.c,v 1.18 1998/03/08 05:56:54 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index aa027da14..55fecc676 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: reassembly.c,v 1.8 1997/12/29 19:52:50 kuznet Exp $
+ * $Id: reassembly.c,v 1.9 1998/02/12 07:43:48 davem Exp $
*
* Based on: net/ipv4/ip_fragment.c
*
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 28ee43e78..5188de864 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.19 1997/12/13 21:53:16 kuznet Exp $
+ * $Id: route.c,v 1.25 1998/03/15 03:31:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -85,18 +85,18 @@ struct dst_ops ip6_dst_ops = {
};
struct rt6_info ip6_null_entry = {
- {{NULL, ATOMIC_INIT(0), ATOMIC_INIT(0), NULL,
+ {{NULL, ATOMIC_INIT(1), ATOMIC_INIT(1), NULL,
-1, 0, 0, 0, 0, 0, 0, 0, 0,
-ENETUNREACH, NULL, NULL,
ip6_pkt_discard, ip6_pkt_discard, &ip6_dst_ops}},
NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0U,
- 0, 255, {NULL}, {{{{0}}}, 128}, {{{{0}}}, 128}
+ 255, 0, {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0}
};
struct fib6_node ip6_routing_table = {
NULL, NULL, NULL, NULL,
&ip6_null_entry,
- 0, RTN_ROOT|RTN_TL_ROOT, 0
+ 0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0
};
#ifdef CONFIG_RT6_POLICY
@@ -709,14 +709,14 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err)
if (rt == NULL) {
RDBG(("dalloc fails, "));
*err = -ENOMEM;
- goto out;
+ return NULL;
}
rt->u.dst.obsolete = -1;
rt->rt6i_expires = rtmsg->rtmsg_info;
addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);
-
+
if (addr_type & IPV6_ADDR_MULTICAST) {
RDBG(("MCAST, "));
rt->u.dst.input = ip6_mc_input;
@@ -743,6 +743,21 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err)
rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);
+ /* We cannot add true routes via loopback here,
+ they would result in kernel looping; promote them to reject routes
+ */
+ if ((rtmsg->rtmsg_flags&RTF_REJECT) ||
+ (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
+ dev = dev_get("lo");
+ rt->u.dst.output = ip6_pkt_discard;
+ rt->u.dst.input = ip6_pkt_discard;
+ rt->u.dst.error = -ENETUNREACH;
+ rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
+ rt->rt6i_metric = rtmsg->rtmsg_metric;
+ rt->rt6i_dev = dev;
+ goto install_route;
+ }
+
if (rtmsg->rtmsg_flags & RTF_GATEWAY) {
struct in6_addr *gw_addr;
int gwa_type;
@@ -773,7 +788,7 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err)
}
dev = grt->rt6i_dev;
}
- if (dev == NULL) {
+ if (dev == NULL || (dev->flags&IFF_LOOPBACK)) {
*err = -EINVAL;
goto out;
}
@@ -805,6 +820,7 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err)
rt->rt6i_hoplimit = ipv6_get_hoplimit(dev);
rt->rt6i_flags = rtmsg->rtmsg_flags;
+install_route:
RDBG(("rt6ins(%p) ", rt));
rt6_lock();
@@ -1421,6 +1437,7 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg)
int ip6_pkt_discard(struct sk_buff *skb)
{
ipv6_statistics.Ip6OutNoRoutes++;
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
kfree_skb(skb);
return 0;
}
@@ -1671,7 +1688,8 @@ static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
rtmsg->rtmsg_dst_len = r->rtm_dst_len;
rtmsg->rtmsg_src_len = r->rtm_src_len;
rtmsg->rtmsg_flags = RTF_UP;
- rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
+ if (r->rtm_type == RTN_UNREACHABLE)
+ rtmsg->rtmsg_flags |= RTF_REJECT;
if (rta[RTA_GATEWAY-1]) {
if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16))
@@ -1754,7 +1772,12 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
rtm->rtm_src_len = rt->rt6i_src.plen;
rtm->rtm_tos = 0;
rtm->rtm_table = RT_TABLE_MAIN;
- rtm->rtm_type = RTN_UNICAST;
+ if (rt->rt6i_flags&RTF_REJECT)
+ rtm->rtm_type = RTN_UNREACHABLE;
+ else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
+ rtm->rtm_type = RTN_LOCAL;
+ else
+ rtm->rtm_type = RTN_UNICAST;
rtm->rtm_flags = 0;
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
#ifdef CONFIG_RTNL_OLD_IFINFO
@@ -1795,6 +1818,8 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
if (rt->u.dst.rtt)
RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);
mx->rta_len = skb->tail - (u8*)mx;
+ if (mx->rta_len == RTA_LENGTH(0))
+ skb_trim(skb, (u8*)mx - skb->data);
#endif
if (rt->u.dst.neighbour)
RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index f029942df..577b85d0f 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.24 1997/12/13 21:53:17 kuznet Exp $
+ * $Id: sit.c,v 1.27 1998/03/08 05:56:57 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f7a080a0d..1d082c195 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.44 1997/12/13 21:53:18 kuznet Exp $
+ * $Id: tcp_ipv6.c,v 1.60 1998/03/15 02:59:32 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -44,7 +44,6 @@
#define ICMP_PARANOIA
-extern int sysctl_tcp_sack;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
@@ -86,62 +85,69 @@ static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
/* Grrr, addr_type already calculated by caller, but I don't want
* to add some silly "cookie" argument to this method just for that.
+ * But it doesn't matter, the recalculation is in the rarest path
+ * this function ever takes.
*/
static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
{
- struct sock *sk2;
- int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
- int retval = 0, sk_reuse = sk->reuse;
+ struct tcp_bind_bucket *tb;
+ int result = 0;
SOCKHASH_LOCK();
- sk2 = tcp_bound_hash[tcp_sk_bhashfn(sk)];
- for(; sk2 != NULL; sk2 = sk2->bind_next) {
- if((sk2->num == snum) && (sk2 != sk)) {
- unsigned char state = sk2->state;
- int sk2_reuse = sk2->reuse;
- if(addr_type == IPV6_ADDR_ANY || (!sk2->rcv_saddr)) {
- if((!sk2_reuse) ||
- (!sk_reuse) ||
- (state == TCP_LISTEN)) {
- retval = 1;
- break;
- }
- } else if(!ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
- &sk2->net_pinfo.af_inet6.rcv_saddr)) {
- if((!sk_reuse) ||
- (!sk2_reuse) ||
- (state == TCP_LISTEN)) {
- retval = 1;
- break;
+ for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+ (tb && (tb->port != snum));
+ tb = tb->next)
+ ;
+ if(tb && tb->owners) {
+ /* Fast path for reuse ports, see include/net/tcp.h for a very
+ * detailed description of why this works, and why it is worth
+ * the effort at all. -DaveM
+ */
+ if((tb->flags & TCPB_FLAG_FASTREUSE) &&
+ (sk->reuse != 0)) {
+ goto go_like_smoke;
+ } else {
+ struct sock *sk2;
+ int sk_reuse = sk->reuse;
+ int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+
+ /* We must walk the whole port owner list in this case. -DaveM */
+ for(sk2 = tb->owners; sk2; sk2 = sk2->bind_next) {
+ if(!sk_reuse || !sk2->reuse || sk2->state == TCP_LISTEN) {
+ if(addr_type == IPV6_ADDR_ANY ||
+ !sk2->rcv_saddr ||
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+ &sk2->net_pinfo.af_inet6.rcv_saddr))
+ break;
}
}
+ if(sk2 != NULL)
+ result = 1;
}
}
+ if((result == 0) &&
+ (tb == NULL) &&
+ (tcp_bucket_create(snum) == NULL))
+ result = 1;
+go_like_smoke:
SOCKHASH_UNLOCK();
-
- return retval;
+ return result;
}
static void tcp_v6_hash(struct sock *sk)
{
- unsigned char state;
-
- SOCKHASH_LOCK();
- state = sk->state;
- if(state != TCP_CLOSE) {
+ if(sk->state != TCP_CLOSE) {
struct sock **skp;
- if(state == TCP_LISTEN)
- skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
- else
- skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+ SOCKHASH_LOCK();
+ skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
if((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
*skp = sk;
sk->pprev = skp;
tcp_sk_bindify(sk);
+ SOCKHASH_UNLOCK();
}
- SOCKHASH_UNLOCK();
}
static void tcp_v6_unhash(struct sock *sk)
@@ -153,6 +159,7 @@ static void tcp_v6_unhash(struct sock *sk)
*sk->pprev = sk->next;
sk->pprev = NULL;
tcp_sk_unbindify(sk);
+ tcp_reg_zap(sk);
}
SOCKHASH_UNLOCK();
}
@@ -163,29 +170,27 @@ static void tcp_v6_rehash(struct sock *sk)
SOCKHASH_LOCK();
state = sk->state;
- if(sk->pprev) {
+ if(sk->pprev != NULL) {
if(sk->next)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
- tcp_sk_unbindify(sk);
+ tcp_reg_zap(sk);
}
if(state != TCP_CLOSE) {
struct sock **skp;
- if(state == TCP_LISTEN) {
+ if(state == TCP_LISTEN)
skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
- } else {
- int hash = tcp_v6_sk_hashfn(sk);
- if(state == TCP_TIME_WAIT)
- hash += (TCP_HTABLE_SIZE/2);
- skp = &tcp_established_hash[hash];
- }
+ else
+ skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+
if((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
*skp = sk;
sk->pprev = skp;
- tcp_sk_bindify(sk);
+ if(state == TCP_LISTEN)
+ tcp_sk_bindify(sk);
}
SOCKHASH_UNLOCK();
}
@@ -209,8 +214,12 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
return result;
}
+/* Until this is verified... -DaveM */
+/* #define USE_QUICKSYNS */
+
/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
* we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
*/
static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
struct in6_addr *saddr, u16 sport,
@@ -218,30 +227,53 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
{
unsigned short hnum = ntohs(dport);
struct sock *sk;
- int hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
+ int hash;
+
+#ifdef USE_QUICKSYNS
+ /* Incomming connection short-cut. */
+ if (th && th->syn == 1 && th->ack == 0)
+ goto listener_shortcut;
+#endif
+
+ /* Check TCP register quick cache first. */
+ sk = TCP_RHASH(sport);
+ if(sk &&
+ sk->num == hnum && /* local port */
+ sk->family == AF_INET6 && /* address family */
+ sk->dummy_th.dest == sport && /* remote port */
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr))
+ goto hit;
/* Optimize here for direct hit, only listening connections can
- * have wildcards anyways. It is assumed that this code only
- * gets called from within NET_BH.
+ * have wildcards anyways.
*/
- for(sk = tcp_established_hash[hash]; sk; sk = sk->next)
+ hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
+ for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
/* For IPV6 do the cheaper port and family tests first. */
if(sk->num == hnum && /* local port */
sk->family == AF_INET6 && /* address family */
sk->dummy_th.dest == sport && /* remote port */
!ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
- !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr))
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr)) {
+ if (sk->state == TCP_ESTABLISHED)
+ TCP_RHASH(sport) = sk;
goto hit; /* You sunk my battleship! */
-
+ }
+ }
/* Must check for a TIME_WAIT'er before going to listener hash. */
for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
if(sk->num == hnum && /* local port */
sk->family == AF_INET6 && /* address family */
- sk->dummy_th.dest == sport && /* remote port */
- !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.daddr, saddr) &&
- !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr, daddr))
- goto hit;
-
+ sk->dummy_th.dest == sport) { /* remote port */
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
+ if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) &&
+ !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr))
+ goto hit;
+ }
+#ifdef USE_QUICKSYNS
+listener_shortcut:
+#endif
sk = tcp_v6_lookup_listener(daddr, hnum);
hit:
return sk;
@@ -275,6 +307,33 @@ static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
skb->h.th->source);
}
+static int tcp_v6_unique_address(struct sock *sk)
+{
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
+ int retval = 1;
+
+ /* Freeze the hash while we snoop around. */
+ SOCKHASH_LOCK();
+ tb = tcp_bound_hash[tcp_bhashfn(snum)];
+ for(; tb; tb = tb->next) {
+ if(tb->port == snum && tb->owners != NULL) {
+ /* Almost certainly the re-use port case, search the real hashes
+ * so it actually scales. (we hope that all ipv6 ftp servers will
+ * use passive ftp, I just cover this case for completeness)
+ */
+ sk = __tcp_v6_lookup(NULL, &sk->net_pinfo.af_inet6.daddr,
+ sk->dummy_th.dest,
+ &sk->net_pinfo.af_inet6.rcv_saddr, snum);
+ if((sk != NULL) && (sk->state != TCP_LISTEN))
+ retval = 0;
+ break;
+ }
+ }
+ SOCKHASH_UNLOCK();
+ return retval;
+}
+
static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len)
{
@@ -390,7 +449,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&np->saddr, saddr);
}
- /* FIXME: Need to do tcp_v6_unique_address() here! -DaveM */
+ sk->dummy_th.dest = usin->sin6_port;
+ if (!tcp_v6_unique_address(sk))
+ return -EADDRNOTAVAIL;
/*
* Init variables
@@ -398,16 +459,15 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
lock_sock(sk);
- sk->dummy_th.dest = usin->sin6_port;
- sk->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
+ tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
np->daddr.s6_addr32[3],
sk->dummy_th.source,
sk->dummy_th.dest);
tp->snd_wnd = 0;
tp->snd_wl1 = 0;
- tp->snd_wl2 = sk->write_seq;
- tp->snd_una = sk->write_seq;
+ tp->snd_wl2 = tp->write_seq;
+ tp->snd_una = tp->write_seq;
tp->rcv_nxt = 0;
@@ -415,30 +475,35 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
release_sock(sk);
- buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);
-
- if (buff == NULL)
+ buff = sock_wmalloc(sk, (MAX_SYN_SIZE + sizeof(struct sk_buff)),
+ 0, GFP_KERNEL);
+ if (buff == NULL) {
+ /* FIXME: Free route references etc??? */
return(-ENOMEM);
+ }
lock_sock(sk);
tcp_v6_build_header(sk, buff);
+ tp->tcp_header_len = sizeof(struct tcphdr) +
+ (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0);
+
/* build the tcp header */
th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
buff->h.th = th;
memcpy(th, (void *) &(sk->dummy_th), sizeof(*th));
- buff->seq = sk->write_seq++;
+ buff->seq = tp->write_seq++;
th->seq = htonl(buff->seq);
- tp->snd_nxt = sk->write_seq;
- buff->end_seq = sk->write_seq;
+ tp->snd_nxt = tp->write_seq;
+ buff->end_seq = tp->write_seq;
th->ack = 0;
th->syn = 1;
sk->mtu = dst->pmtu;
- sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
+ sk->mss = (sk->mtu - sizeof(struct ipv6hdr) - tp->tcp_header_len);
if (sk->mss < 1) {
printk(KERN_DEBUG "intial ipv6 sk->mss below 1\n");
@@ -457,8 +522,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
* Put in the TCP options to say MTU.
*/
- tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_sack,
- sysctl_tcp_timestamps,
+ tmp = tcp_syn_build_options(buff, sk->mss, sysctl_tcp_timestamps,
sysctl_tcp_window_scaling,tp->rcv_wscale);
th->doff = sizeof(*th)/4 + (tmp>>2);
buff->csum = 0;
@@ -467,9 +531,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tcp_set_state(sk, TCP_SYN_SENT);
/* Socket identity change complete, no longer
- * in TCP_CLOSE, so rehash.
+ * in TCP_CLOSE, so enter ourselves into the
+ * hash tables.
*/
- sk->prot->rehash(sk);
+ sk->prot->hash(sk);
/* FIXME: should use dcache->rtt if availiable */
tp->rto = TCP_TIMEOUT_INIT;
@@ -482,12 +547,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->packets_out++;
buff->when = jiffies;
skb1 = skb_clone(buff, GFP_KERNEL);
- skb_set_owner_w(skb1, sk);
-
- tcp_v6_xmit(skb1);
+ if(skb1 != NULL) {
+ skb_set_owner_w(skb1, sk);
+ tcp_v6_xmit(skb1);
+ }
/* Timer for repeating the SYN until an answer */
-
tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
tcp_statistics.TcpActiveOpens++;
tcp_statistics.TcpOutSegs++;
@@ -499,6 +564,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
{
+ struct tcp_opt *tp;
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
int retval = -EINVAL;
@@ -530,7 +596,10 @@ static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
lock_sock(sk);
retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov,
msg->msg_flags);
-
+ /* Push out partial tail frames if needed. */
+ tp = &(sk->tp_pinfo.af_tcp);
+ if(tp->send_head && tcp_snd_test(sk, tp->send_head))
+ tcp_write_xmit(sk);
release_sock(sk);
out:
@@ -555,7 +624,7 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source);
- if (sk == NULL) {
+ if (sk == NULL || sk->state == TCP_TIME_WAIT) {
/* XXX: Update ICMP error count */
return;
}
@@ -596,11 +665,14 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
ip6_dst_store(sk, dst);
}
- if (sk->dst_cache->error)
+ if (sk->dst_cache->error) {
sk->err_soft = sk->dst_cache->error;
- else
+ } else {
+ /* FIXME: Reset sk->mss, taking into account TCP option
+ * bytes for timestamps. -DaveM
+ */
sk->mtu = sk->dst_cache->pmtu;
-
+ }
if (sk->sock_readers) { /* remove later */
printk(KERN_DEBUG "tcp_v6_err: pmtu disc: socket locked.\n");
return;
@@ -713,11 +785,10 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
* match what happens under IPV4. Figure out the right thing to do.
*/
req->mss = min(sk->mss, req->mss);
-
- if (req->mss < 1) {
- printk(KERN_DEBUG "initial req->mss below 1\n");
- req->mss = 1;
- }
+ if(sk->user_mss)
+ req->mss = min(req->mss, sk->user_mss);
+ if(req->tstamp_ok == 0)
+ req->mss += TCPOLEN_TSTAMP_ALIGNED;
if (req->rcv_wnd == 0) {
__u8 rcv_wscale;
@@ -732,7 +803,7 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
}
th->window = htons(req->rcv_wnd);
- tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
+ tmp = tcp_syn_build_options(skb, req->mss, req->tstamp_ok,
req->wscale_ok,req->rcv_wscale);
skb->csum = 0;
th->doff = (sizeof(*th) + tmp)>>2;
@@ -740,9 +811,13 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
&req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
csum_partial((char *)th, sizeof(*th)+tmp, skb->csum));
+ /* Actually we should not attach dst to socket in state LISTEN,
+ it results in stale destination per listen socket and
+ overflow of routing cache.
+ (IPv4 has the same flaw with more unpleasant consequences.)
+ */
ip6_dst_store(sk, dst);
ip6_xmit(sk, skb, &fl, req->af.v6_req.opt);
- dst_release(dst);
tcp_statistics.TcpOutSegs++;
}
@@ -801,14 +876,15 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
req->rcv_isn = skb->seq;
req->snt_isn = isn;
- tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0;
tp.in_mss = 536;
tcp_parse_options(skb->h.th,&tp,0);
- if (tp.saw_tstamp)
- req->ts_recent = tp.rcv_tsval;
req->mss = tp.in_mss;
+ if (tp.saw_tstamp) {
+ req->mss -= TCPOLEN_TSTAMP_ALIGNED;
+ req->ts_recent = tp.rcv_tsval;
+ }
req->tstamp_ok = tp.tstamp_ok;
- req->sack_ok = tp.sack_ok;
req->snd_wscale = tp.snd_wscale;
req->wscale_ok = tp.wscale_ok;
req->rmt_port = skb->h.th->source;
@@ -879,92 +955,17 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
return newsk;
}
- newsk = sk_alloc(AF_INET6, GFP_ATOMIC);
+ newsk = tcp_create_openreq_child(sk, req, skb);
if (newsk == NULL) {
- if (dst)
- dst_release(dst);
+ dst_release(dst);
return NULL;
}
- memcpy(newsk, sk, sizeof(*newsk));
-
- /* Or else we die! -DaveM */
- newsk->sklist_next = NULL;
-
- newsk->opt = NULL;
newsk->dst_cache = NULL;
- skb_queue_head_init(&newsk->write_queue);
- skb_queue_head_init(&newsk->receive_queue);
- skb_queue_head_init(&newsk->out_of_order_queue);
- skb_queue_head_init(&newsk->error_queue);
-
- /*
- * Unused
- */
newtp = &(newsk->tp_pinfo.af_tcp);
- np = &newsk->net_pinfo.af_inet6;
-
- newtp->send_head = NULL;
- newtp->retrans_head = NULL;
-
- newtp->pending = 0;
-
- skb_queue_head_init(&newsk->back_log);
-
- newsk->prot->init(newsk);
-
- newtp->snd_cwnd_cnt = 0;
-#if 0 /* Don't mess up the initialization we did in the init routine! */
- newtp->snd_ssthresh = 0;
-#endif
- newtp->backoff = 0;
- newsk->proc = 0;
- newsk->done = 0;
- newsk->pair = NULL;
- atomic_set(&newsk->wmem_alloc, 0);
- atomic_set(&newsk->rmem_alloc, 0);
- newsk->localroute = sk->localroute;
-
- newsk->err = 0;
- newsk->shutdown = 0;
- newsk->ack_backlog = 0;
-
- newtp->fin_seq = req->rcv_isn;
- newsk->syn_seq = req->rcv_isn;
- newsk->state = TCP_SYN_RECV;
- newsk->timeout = 0;
-
- newsk->write_seq = req->snt_isn;
-
- newtp->snd_wnd = ntohs(skb->h.th->window);
- newtp->max_window = newtp->snd_wnd;
- newtp->snd_wl1 = req->rcv_isn;
- newtp->snd_wl2 = newsk->write_seq;
- newtp->snd_una = newsk->write_seq++;
- newtp->snd_nxt = newsk->write_seq;
-
- newsk->urg_data = 0;
- newtp->packets_out = 0;
- newtp->retransmits = 0;
- newsk->linger=0;
- newsk->destroy = 0;
- init_timer(&newsk->timer);
- newsk->timer.data = (unsigned long) newsk;
- newsk->timer.function = &net_timer;
-
- tcp_init_xmit_timers(newsk);
-
- newsk->dummy_th.source = sk->dummy_th.source;
- newsk->dummy_th.dest = req->rmt_port;
- newsk->sock_readers=0;
-
- newtp->rcv_nxt = req->rcv_isn + 1;
- newtp->rcv_wup = req->rcv_isn + 1;
- newsk->copied_seq = req->rcv_isn + 1;
-
- newsk->socket = NULL;
+ np = &newsk->net_pinfo.af_inet6;
ipv6_addr_copy(&np->daddr, &req->af.v6_req.rmt_addr);
ipv6_addr_copy(&np->saddr, &req->af.v6_req.loc_addr);
ipv6_addr_copy(&np->rcv_saddr, &req->af.v6_req.loc_addr);
@@ -987,14 +988,22 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
ip6_dst_store(newsk, dst);
- newtp->sack_ok = req->sack_ok;
newtp->tstamp_ok = req->tstamp_ok;
- newtp->snd_wscale = req->snd_wscale;
+ newtp->window_clamp = req->window_clamp;
+ newtp->rcv_wnd = req->rcv_wnd;
newtp->wscale_ok = req->wscale_ok;
- newtp->ts_recent = req->ts_recent;
+ if (newtp->wscale_ok) {
+ newtp->snd_wscale = req->snd_wscale;
+ newtp->rcv_wscale = req->rcv_wscale;
+ } else {
+ newtp->snd_wscale = newtp->rcv_wscale = 0;
+ newtp->window_clamp = min(newtp->window_clamp,65535);
+ }
if (newtp->tstamp_ok) {
- newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define the contant. */
- newsk->dummy_th.doff += 3;
+ newtp->ts_recent = req->ts_recent;
+ newtp->ts_recent_stamp = jiffies;
+ newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+ newsk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2);
} else {
newtp->tcp_header_len = sizeof(struct tcphdr);
}
@@ -1006,7 +1015,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newsk->mss = min(req->mss+sizeof(struct tcphdr)-newtp->tcp_header_len,
(newsk->mtu - sizeof(struct ipv6hdr) - newtp->tcp_header_len));
- /* XXX tp->window_clamp??? -DaveM */
newsk->daddr = LOOPBACK4_IPV6;
newsk->saddr = LOOPBACK4_IPV6;
@@ -1181,12 +1189,14 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
goto no_tcp_socket;
}
- skb->sk = sk;
skb->seq = ntohl(th->seq);
skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
skb->ack_seq = ntohl(th->ack_seq);
-
skb->used = 0;
+ if(sk->state == TCP_TIME_WAIT)
+ goto do_time_wait;
+
+ skb->sk = sk;
}
/*
@@ -1249,6 +1259,12 @@ discard_it:
kfree_skb(skb);
return 0;
+
+do_time_wait:
+ if(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+ skb, th, &(IPCB(skb)->opt), skb->len))
+ goto no_tcp_socket;
+ goto discard_it;
}
static int tcp_v6_rebuild_header(struct sock *sk, struct sk_buff *skb)
@@ -1384,51 +1400,34 @@ static struct tcp_func ipv6_mapped = {
sizeof(struct sockaddr_in6)
};
+/* NOTE: A lot of things set to zero explicitly by call to
+ * sk_alloc() so need not be done here.
+ */
static int tcp_v6_init_sock(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- skb_queue_head_init(&sk->out_of_order_queue);
+ skb_queue_head_init(&tp->out_of_order_queue);
tcp_init_xmit_timers(sk);
- tp->srtt = 0;
tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
tp->mdev = TCP_TIMEOUT_INIT;
-
- tp->ato = 0;
- tp->iat = (HZ/5) << 3;
-
- /* FIXME: right thing? */
- tp->rcv_wnd = 0;
tp->in_mss = 536;
- /* tp->rcv_wnd = 8192; */
- tp->tstamp_ok = 0;
- tp->sack_ok = 0;
- tp->wscale_ok = 0;
- tp->snd_wscale = 0;
- tp->sacks = 0;
- tp->saw_tstamp = 0;
- tp->syn_backlog = 0;
-
- /* start with only sending one packet at a time. */
+
+ /* See draft-stevens-tcpca-spec-01 for discussion of the
+ * initialization of these values.
+ */
tp->snd_cwnd = 1;
tp->snd_ssthresh = 0x7fffffff;
-
-
sk->priority = 1;
sk->state = TCP_CLOSE;
-
sk->max_ack_backlog = SOMAXCONN;
-
sk->mtu = 576;
sk->mss = 536;
-
sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
- /*
- * Speed up by setting some standard state for the dummy_th.
- */
+ /* Speed up by setting some standard state for the dummy_th. */
sk->dummy_th.ack=1;
sk->dummy_th.doff=sizeof(struct tcphdr)>>2;
@@ -1442,6 +1441,7 @@ static int tcp_v6_init_sock(struct sock *sk)
static int tcp_v6_destroy_sock(struct sock *sk)
{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct sk_buff *skb;
tcp_clear_xmit_timers(sk);
@@ -1460,15 +1460,22 @@ static int tcp_v6_destroy_sock(struct sock *sk)
* Cleans up our, hopefuly empty, out_of_order_queue
*/
- while((skb = skb_dequeue(&sk->out_of_order_queue)) != NULL)
+ while((skb = skb_dequeue(&tp->out_of_order_queue)) != NULL)
kfree_skb(skb);
/*
* Release destination entry
*/
- dst_release(sk->dst_cache);
- sk->dst_cache = NULL;
+ dst_release(xchg(&sk->dst_cache,NULL));
+
+ /* Clean up a locked TCP bind bucket, this only happens if a
+ * port is allocated for a socket, but it never fully connects.
+ * In which case we will find num to be non-zero and daddr to
+ * be zero.
+ */
+ if(ipv6_addr_any(&(sk->net_pinfo.af_inet6.daddr)) && sk->num != 0)
+ tcp_bucket_unlock(sk);
return 0;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index b99dc19e3..40e9b0233 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.21 1997/12/29 19:52:52 kuznet Exp $
+ * $Id: udp.c,v 1.24 1998/03/12 03:20:21 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -448,32 +448,43 @@ static struct sock *udp_v6_mcast_next(struct sock *sk,
return NULL;
}
+/*
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
+ */
static void udpv6_mcast_deliver(struct udphdr *uh,
struct in6_addr *saddr, struct in6_addr *daddr,
struct sk_buff *skb)
{
struct sock *sk, *sk2;
+ struct sk_buff *buff;
- SOCKHASH_LOCK();
sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr);
- if(sk) {
- sk2 = sk;
- while((sk2 = udp_v6_mcast_next(sk2->next,
- uh->dest, saddr,
- uh->source, daddr))) {
- struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
- if (buff && sock_queue_rcv_skb(sk2, buff) < 0) {
- buff->sk = NULL;
- kfree_skb(buff);
- }
+ if (!sk)
+ goto free_skb;
+
+ buff = NULL;
+ sk2 = sk;
+ while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
+ uh->source, daddr))) {
+ if (!buff) {
+ buff = skb_clone(skb, GFP_ATOMIC);
+ if (!buff)
+ continue;
}
+ if (sock_queue_rcv_skb(sk2, buff) >= 0)
+ buff = NULL;
+ }
+ if (buff) {
+ buff->sk = NULL;
+ kfree_skb(buff);
}
- if(!sk || sock_queue_rcv_skb(sk, skb) < 0) {
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
+ free_skb:
skb->sk = NULL;
kfree_skb(skb);
}
- SOCKHASH_UNLOCK();
}
int udpv6_rcv(struct sk_buff *skb, struct device *dev,
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index cf56df492..904fa1174 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1713,7 +1713,7 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname,
static int ipx_create(struct socket *sock, int protocol)
{
struct sock *sk;
- sk=sk_alloc(AF_IPX, GFP_KERNEL);
+ sk=sk_alloc(AF_IPX, GFP_KERNEL, 1);
if(sk==NULL)
return(-ENOMEM);
switch(sock->type)
diff --git a/net/netbeui/af_netbeui.c b/net/netbeui/af_netbeui.c
index 85bd8f4d1..6769edde5 100644
--- a/net/netbeui/af_netbeui.c
+++ b/net/netbeui/af_netbeui.c
@@ -150,7 +150,7 @@ static int netbeui_listen(struct socket *sock, int backlog)
static int netbeui_create(struct socket *sock, int protocol)
{
netbeui_socket *sk;
- sk=(netbeui_socket *)sk_alloc(GFP_KERNEL);
+ sk=(netbeui_socket *)sk_alloc(GFP_KERNEL, 1);
if(sk==NULL)
return(-ENOBUFS);
switch(sock->type)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3f02f4c3c..8b8e5a4b8 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -147,7 +147,7 @@ static int netlink_create(struct socket *sock, int protocol)
sock->ops = &netlink_ops;
- sk = sk_alloc(AF_NETLINK, GFP_KERNEL);
+ sk = sk_alloc(AF_NETLINK, GFP_KERNEL, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index a84d1fd53..9d8a206da 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -98,7 +98,7 @@ static struct sock *nr_alloc_sock(void)
struct sock *sk;
nr_cb *nr;
- if ((sk = sk_alloc(AF_NETROM, GFP_ATOMIC)) == NULL)
+ if ((sk = sk_alloc(AF_NETROM, GFP_ATOMIC, 1)) == NULL)
return NULL;
if ((nr = kmalloc(sizeof(*nr), GFP_ATOMIC)) == NULL) {
@@ -759,6 +759,8 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
newsk = skb->sk;
newsk->pair = NULL;
+ newsk->socket = newsock;
+ newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */
diff --git a/net/netsyms.c b/net/netsyms.c
index b7809863b..ad51e9a3e 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -244,7 +244,6 @@ EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
EXPORT_SYMBOL(__release_sock);
EXPORT_SYMBOL(net_timer);
/* UDP/TCP exported functions for TCPv6 */
-EXPORT_SYMBOL(sysctl_tcp_sack);
EXPORT_SYMBOL(sysctl_tcp_timestamps);
EXPORT_SYMBOL(sysctl_tcp_window_scaling);
EXPORT_SYMBOL(sock_rspace);
@@ -272,11 +271,15 @@ EXPORT_SYMBOL(tcp_slt_array);
EXPORT_SYMBOL(__tcp_inc_slow_timer);
EXPORT_SYMBOL(tcp_statistics);
EXPORT_SYMBOL(tcp_rcv_state_process);
+EXPORT_SYMBOL(tcp_timewait_state_process);
EXPORT_SYMBOL(tcp_do_sendmsg);
EXPORT_SYMBOL(tcp_v4_build_header);
EXPORT_SYMBOL(tcp_v4_rebuild_header);
EXPORT_SYMBOL(tcp_v4_send_check);
EXPORT_SYMBOL(tcp_v4_conn_request);
+EXPORT_SYMBOL(tcp_create_openreq_child);
+EXPORT_SYMBOL(tcp_bucket_create);
+EXPORT_SYMBOL(tcp_bucket_unlock);
EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
EXPORT_SYMBOL(tcp_v4_do_rcv);
EXPORT_SYMBOL(tcp_v4_connect);
@@ -290,6 +293,11 @@ EXPORT_SYMBOL(ipv4_specific);
EXPORT_SYMBOL(tcp_simple_retransmit);
EXPORT_SYMBOL(xrlim_allow);
+
+EXPORT_SYMBOL(tcp_write_xmit);
+EXPORT_SYMBOL(dev_loopback_xmit);
+EXPORT_SYMBOL(tcp_regs);
+
#endif
#ifdef CONFIG_NETLINK
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index a098f59b9..74fc7af82 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -35,6 +35,7 @@
* Alan Cox : sendmsg/recvmsg support.
* Alan Cox : Protocol setting support
* Alexey Kuznetsov : Untied from IPv4 stack.
+ * Cyrus Durgin : Fixed kerneld for kmod.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -54,7 +55,7 @@
#include <linux/netdevice.h>
#include <linux/if_packet.h>
#include <linux/wireless.h>
-#include <linux/kerneld.h>
+#include <linux/kmod.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
@@ -710,7 +711,7 @@ static int packet_create(struct socket *sock, int protocol)
sock->state = SS_UNCONNECTED;
MOD_INC_USE_COUNT;
- sk = sk_alloc(AF_PACKET, GFP_KERNEL);
+ sk = sk_alloc(AF_PACKET, GFP_KERNEL, 1);
if (sk == NULL) {
MOD_DEC_USE_COUNT;
return -ENOBUFS;
@@ -831,9 +832,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
/* We can't use skb_copy_datagram here */
err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
- if (err)
+ if (err) {
+ err = -EFAULT;
goto out_free;
-
+ }
sk->stamp=skb->stamp;
if (msg->msg_name)
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index eeb396350..a575402c7 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -149,7 +149,7 @@ static struct sock *rose_alloc_sock(void)
struct sock *sk;
rose_cb *rose;
- if ((sk = sk_alloc(AF_ROSE, GFP_ATOMIC)) == NULL)
+ if ((sk = sk_alloc(AF_ROSE, GFP_ATOMIC, 1)) == NULL)
return NULL;
if ((rose = kmalloc(sizeof(*rose), GFP_ATOMIC)) == NULL) {
@@ -847,6 +847,8 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
newsk = skb->sk;
newsk->pair = NULL;
+ newsk->socket = newsock;
+ newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */
diff --git a/net/socket.c b/net/socket.c
index 5c9534031..dc77ef3e8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -76,8 +76,8 @@
#include <linux/init.h>
#include <linux/poll.h>
-#if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
-#include <linux/kerneld.h>
+#if defined(CONFIG_KMOD) && defined(CONFIG_NET)
+#include <linux/kmod.h>
#endif
#include <asm/system.h>
@@ -577,7 +577,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
if(family<0||family>=NPROTO)
return -EINVAL;
-#if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
+#if defined(CONFIG_KMOD) && defined(CONFIG_NET)
/* Attempt to load a protocol module if the find failed.
*
* 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
@@ -814,7 +814,7 @@ restart:
newsock = socki_lookup(inode);
if ((err = get_fd(inode)) < 0)
- goto out_inval;
+ goto out_release;
newsock->file = current->files->fd[err];
if (upeer_sockaddr)
@@ -835,8 +835,6 @@ out:
unlock_kernel();
return err;
-out_inval:
- err = -EINVAL;
out_release:
sock_release(newsock);
goto out_put;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 2fbce16fe..b04072d80 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -364,7 +364,7 @@ static int unix_create(struct socket *sock, int protocol)
default:
return -ESOCKTNOSUPPORT;
}
- sk = sk_alloc(AF_UNIX, GFP_KERNEL);
+ sk = sk_alloc(AF_UNIX, GFP_KERNEL, 1);
if (!sk)
return -ENOMEM;
@@ -1265,7 +1265,9 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size
}
chunk = min(skb->len, size);
- /* N.B. This could fail with -EFAULT */
+ /* N.B. This could fail with a non-zero value (which means -EFAULT
+ * and the non-zero value is the number of bytes not copied).
+ */
memcpy_toiovec(msg->msg_iov, skb->data, chunk);
copied += chunk;
size -= chunk;
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 7e3c9cae2..a85aeea5f 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -423,7 +423,7 @@ static struct sock *x25_alloc_socket(void)
struct sock *sk;
x25_cb *x25;
- if ((sk = sk_alloc(AF_X25, GFP_ATOMIC)) == NULL)
+ if ((sk = sk_alloc(AF_X25, GFP_ATOMIC, 1)) == NULL)
return NULL;
if ((x25 = kmalloc(sizeof(*x25), GFP_ATOMIC)) == NULL) {