]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.14pre1 2.2.14pre1
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:07 +0000 (15:20 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:07 +0000 (15:20 -0500)
o Update Alpha architecture slightly (Jay Estabrook)
o Multi-apic support (Ingo Molnar)
o Fix FC4 compile glitch (Alan Cox)
o PCNet 32 speed ups (HP, Alan Cox)
o Update oldpci tables
o Qlogic Alpha fixes (Jay Estabrook)
o Audio compile fixes
o knfsd 0.4.7 (HJ Lu et al)
o Hashing scale by memory (Dave Miller)
o Revert a.out change, switch from timers to (Several people)
counts
o Support very big disks (Andries Brouwer)
o Compile cleanups (Arjan van de Ven)
o Fix enabled flag on transparent proxy on (Alan Cox)
o SIS900 driver update (SIS)
o Small PPC update (Cort Dougan)
o Increase loader heap for uncompressing (HJ Lu)
o Future domain build fix (Anthony Barbachan)
o Bring PCI sound drivers in 2.2.x in line with
2.3.x enhancements (Thomas Sailer)
o Documentation fixes (Thierry Vignaud)
o Bridge update (more of a rewrite) (Matthew Grant)
o Masquerade fix (Juanjo Ciarlante)
o Changes file update (Chris Ricker)
o NFS zero padding cleanup (Trond Myklebust)
o Clean up OPL3 configuration and surplus options (Thomas Molina)
o GCC 2.95 patches (Bero Rosenkraenzer)
| If you hit problems please verify them with an
| older gcc, but you should now be able to build
| with 2.95.* to go looking for them...

123 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/kernel-parameters.txt
Makefile
arch/alpha/kernel/process.c
arch/alpha/kernel/proto.h
arch/alpha/math-emu/fp-emul.c
arch/alpha/math-emu/sfp-machine.h
arch/i386/boot/compressed/Makefile
arch/i386/boot/compressed/misc.c
arch/i386/kernel/bios32.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.h
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/ppc/common_defconfig
arch/ppc/defconfig
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/head.S
arch/ppc/kernel/setup.c
arch/ppc/mm/init.c
arch/ppc/xmon/xmon.c
drivers/block/Config.in
drivers/block/genhd.c
drivers/block/ide-disk.c
drivers/block/ide-proc.c
drivers/char/bttv.c
drivers/char/buz.c
drivers/char/radio-aimslab.c
drivers/char/radio-cadet.c
drivers/char/radio-rtrack2.c
drivers/fc4/Makefile
drivers/isdn/avmb1/capi.c
drivers/macintosh/macserial.c
drivers/macintosh/macserial.h
drivers/macintosh/mediabay.c
drivers/net/Config.in
drivers/net/arlan-proc.c
drivers/net/hamradio/Config.in
drivers/net/pcnet32.c
drivers/net/sis900.c
drivers/net/sis900.h [new file with mode: 0644]
drivers/pci/oldproc.c
drivers/scsi/fdomain.c
drivers/scsi/gdth.h
drivers/scsi/ips.h
drivers/scsi/megaraid.h
drivers/scsi/psi240i.h
drivers/scsi/qlogicfc.c
drivers/scsi/qlogicisp.c
drivers/scsi/sym53c416.h
drivers/scsi/sym53c8xx_defs.h
drivers/scsi/u14-34f.h
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/ac97.h
drivers/sound/adlib_card.c
drivers/sound/es1370.c
drivers/sound/es1371.c
drivers/sound/esssolo1.c
drivers/sound/lowlevel/miroaci.h
drivers/sound/msnd_pinnacle.c
drivers/sound/nm256_audio.c
drivers/sound/opl3.c
drivers/sound/sonicvibes.c
fs/binfmt_aout.c
fs/buffer.c
fs/dcache.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/filesystems.c
fs/inode.c
fs/lockd/lockd_syms.c
fs/lockd/svc.c
fs/locks.c
fs/nfs/inode.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfssvc.c
fs/nfsd/stats.c
fs/nfsd/vfs.c
include/asm-alpha/delay.h
include/asm-alpha/io.h
include/asm-i386/fixmap.h
include/linux/fs.h
include/linux/genhd.h
include/linux/lockd/syscall.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/nfsd/nfsfh.h
include/linux/nfsd/stats.h
include/linux/nfsd/syscall.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/proc_fs.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svcsock.h
include/net/br.h
include/net/tcp.h
init/main.c
ipc/sem.c
kernel/ksyms.c
kernel/sysctl.c
mm/filemap.c
net/802/fc.c
net/Config.in
net/bridge/br.c
net/bridge/br_tree.c
net/core/dev.c
net/ipv4/ip_forward.c
net/ipv4/ip_fw.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_timer.c
net/ipv6/tcp_ipv6.c
net/irda/irlan/irlan_eth.c
net/netsyms.c
net/sunrpc/clnt.c
net/sunrpc/svc.c
net/sunrpc/svcsock.c

diff --git a/CREDITS b/CREDITS
index 00aab7cb70f58b76172089565e3045a23a2a95f2..6aa113c223c187df7d8b771f5780d174a457b7c6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -789,12 +789,12 @@ E: ajh@primag.co.uk
 D: Selection mechanism
 
 N: Jochen Hein
-E: jochen.hein@delphi.central.de
+E: jochen@jochen.org
 P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B  CB 0A DA DA 40 77 05 6C
 D: National Language Support
 D: Linux Internationalization Project
 D: German Localization for Linux and GNU software
-S: Frankenstraße
+S: Frankenstraße 33
 S: 34131 Kassel
 S: Germany
 
index 85f40bb4446eaa6ce5588e478c2afc774b9fad15..77dc7ee7e00b03674dd9b9413e8f549d98276c5a 100644 (file)
@@ -43,7 +43,7 @@ obtener la traducci
 
    for all your Linux kernel needs.
 
-Last updated: July 13, 1999
+Last updated: October 13, 1999
 Current Author: Chris Ricker (kaboom@gatech.edu or
        chris.ricker@genetics.utah.edu).
 
@@ -61,19 +61,19 @@ running, the suggested command should tell you.
 - Linux libc6 C Library  2.0.7pre6               ; ls -l /lib/libc*
 - Dynamic Linker (ld.so) 1.9.9                   ; ldd --version or ldd -v
 - Linux C++ Library     2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
-- Procps                1.2.9                   ; ps --version
+- Procps                2.0.3                   ; ps --version
 - Procinfo               16                      ; procinfo -v
 - Psmisc                17                      ; pstree -V
 - Net-tools              1.52                    ; hostname -V
 - Loadlin                1.6a
 - Sh-utils               1.16                    ; basename --v
-- Autofs                 3.1.1                   ; automount --version
+- Autofs                 3.1.3                   ; automount --version
 - NFS                    2.2beta40               ; showmount --version
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
-- Pcmcia-cs              3.0.13                  ; cardmgr -V
-- PPP                    2.3.                  ; pppd --version
-- Util-linux             2.9t                    ; chsh -v
+- Pcmcia-cs              3.0.14                  ; cardmgr -V
+- PPP                    2.3.10                  ; pppd --version
+- Util-linux             2.9z                    ; chsh -v
 
 Upgrade notes
 *************
@@ -226,7 +226,7 @@ your system, you don't have to upgrade just so the kernel will work
    Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad
 Things while compiling your kernel, particularly if absurd
 optimizations (like -O9) are used.  Caveat emptor.  Currently, the only
-C compiler available in a binary distribution is egcs.  Version 1.0.3
+C compiler available in a binary distribution is egcs.  Version 1.1.2
 seems okay; if you have to have a binary, you may be successful using
 that.  In general, however, gcc-2.7.2.3 is known to be stable, while
 egcs and others have not been as thoroughly tested yet.
@@ -284,8 +284,8 @@ Memory
 ======
 
    As of 2.1.41, the format of /proc/meminfo has changed.  This broke
-many memory utils, which have to be upgraded.  Get the new procps-1.2
-and you should be set.
+many memory utils, which have to be upgraded.  Get the new procps and
+you should be set.
 
 Network File System
 ===================
@@ -519,23 +519,15 @@ Where to get the files
 Binutils
 ========
 
-The 2.8.1.0.23 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz
+The 2.9.1.0.25 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
-
-The 2.9.1.0.15 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15.tar.gz
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/release.binutils-2.9.1.0.25
+
+The 2.9.5.0.16 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.16.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.15
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.15
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.16
 
 Bin86
 =====
@@ -547,14 +539,12 @@ ftp://tsx-11.mit.edu/pub/linux/packages/GCC/bin86-0.4.tar.gz
 Gnu C
 =====
 
-The egcs-1.0.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2
+The egcs-1.1.2 release:
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.x86.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3
-ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/release.egcs-1.1.2
 
 Gnu C 2.7.2.3 source:
 ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
@@ -596,15 +586,14 @@ ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.121.tar.gz
 Procps utilities
 ================
 
-The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz
-ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz
+The 2.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-2.0.3.tar.gz
 
 Procinfo utilities
 ==================
 
-The 16 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz
+The 17 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-17.tar.gz
 
 Psmisc utilities
 ================
@@ -624,7 +613,6 @@ DOSEMU
 ======
 
 The 0.98.6 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.6.tgz
 ftp://ftp.dosemu.org/dosemu/dosemu-0.98.6.tgz
 
 Loadlin
@@ -645,7 +633,7 @@ Util-linux
 ==========
 
 The 2.9 release:
-ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9t.tar.gz
+ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9z.tar.gz
 
 Autofs
 ======
@@ -660,9 +648,9 @@ The user-land 2.2beta40 release:
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 
-The kernel-level 1.4.4 release:
-ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.4.tar.gz
-ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.4.tar.gz
+The kernel-level 1.4.7 release:
+ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.7.tar.gz
+ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.7.tar.gz
 
 Net-tools
 =========
@@ -707,8 +695,8 @@ ftp://ftp.samba.org/pub/samba/samba-2.0.5a.tar.gz
 Pcmcia-cs
 =========
 
-The 3.0.13 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.13.tar.gz
+The 3.0.14 release:
+ftp://sourceforge.org/pcmcia/pcmcia-cs.3.0.14.tar.gz
 
 Setserial
 =========
@@ -720,15 +708,15 @@ ftp://metalab.unc.edu/pub/Linux/system/serial/setserial-2.15.tar.gz
 PPP
 ===
 
-The 2.3.8 release:
-ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.8.tar.gz
+The 2.3.10 release:
+ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.10.tar.gz
 
 IP Chains
 =========
 
-The 1.3.8 release:
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.gz
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.bz2
+The 1.3.9 release:
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.gz
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.bz2
 
 IP Masq Adm
 ===========
@@ -739,11 +727,11 @@ http://juanjox.linuxhq.com/ipmasqadm-0.4.2.tar.gz
 DHCP clients
 ============
 
-The 2.0b1pl27 ISC dhcpclient release:
-ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl27.tar.gz
+The 2.0 ISC dhcpclient release:
+ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0.tar.gz
 
-The 1.3.17-pl2 PhysTech dhcpcd release:
-ftp://ftp.phystech.com/pub/dhcpcd-1.3.17-pl2.tar.gz
+The 1.3.18-pl1 PhysTech dhcpcd release:
+ftp://ftp.phystech.com/pub/dhcpcd-1.3.18-pl1.tar.gz
 
 iBCS
 ====
@@ -754,8 +742,8 @@ ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.1-981105-ALPHA.tar.gz
 Asun netatalk
 =============
 
-The 2.0a18.2 release:
-ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.tar.gz
+The 2.1.3 release:
+ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.1.3.tar.gz
 
 Fbset
 =====
@@ -792,9 +780,9 @@ ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.src.rpm
 IP utils
 ========
 
-The June 1999 release:
-ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990630.tar.gz
-ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990610.tar.gz
+The latest releases:
+ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990824.tar.gz
+ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990915.tar.gz
 
 Patch
 =====
index b9173039238d48e17d4ff746154258ac62f5f25d..90d47b5e26aee534a79f41c073bf4a8b54f93b0f 100644 (file)
@@ -9422,20 +9422,6 @@ CONFIG_SOUND_SB
   You can say M here to compile this driver as a module; the module is
   called sb.o.
 
-Generic OPL2/OPL3 FM synthesizer support
-CONFIG_SOUND_ADLIB
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however). 
-
-  Please read the file Documentation/sound/OPL3 if your card has an
-  OPL3 chip.
-
-  If unsure, say Y.
-  
-
 #Loopback MIDI device support
 #CONFIG_SOUND_VMIDI
 ###
@@ -9715,7 +9701,15 @@ CONFIG_SOUND_MIDI
 
 FM synthesizer (YM3812/OPL-3) support
 CONFIG_SOUND_YM3812
-  Answer Y here, unless you know you will not need the option.
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however).
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
+
+  If unsure, say Y.
 
 Sun Audio support
 CONFIG_SUN_AUDIO
index e1392c277afc0da5fe84f0e1d518553cc8914d73..d5ead50f2bd5e8b3d557a0996e9f7f8e4a23c079 100644 (file)
@@ -50,7 +50,7 @@ be entered as an environment variable, whereas its absence indicates that
 it will appear as a kernel argument readable via /proc/cmdline by programs
 running once the system is up.
 
-    53c7xx=            [HW,SCSI]
+    53c7xx=            [HW,SCSI] Amiga SCSI controllers
 
     adb_buttons=       [HW,MOUSE]
 
@@ -68,6 +68,8 @@ running once the system is up.
 
     arcrimi=           [HW,NET]
 
+       ataflop=                [HW, M68k]
+
     atamouse=          [HW,MOUSE] Atari Mouse.
 
     atascsi=           [HW,SCSI] Atari SCSI.
@@ -96,22 +98,22 @@ running once the system is up.
 
     com90xx=           [HW,NET]
 
-    console=           
+    console=           [KNL] output console + comm spec (speed, control, parity)
 
     cyclades=          [HW,SERIAL] Cyclades multi-serial port adapter.
 
-    debug              [KNL] Enable kernel debugging.
+    debug              [KNL] Enable kernel debugging (events log level).
 
     decnet=            [HW,NET]
 
-    digi=              [HW,SERIAL]
+    digi=              [HW,SERIAL] io parameters + enable/disable command
 
     digiepca=          [HW,SERIAL]
 
     dmascc=            [HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA
                        support available.
 
-    dmasound=          [HW,SOUND]
+    dmasound=          [HW,SOUND] (sound subsystem buffers)
 
     dtc3181e=          [HW,SCSI]
 
@@ -121,7 +123,7 @@ running once the system is up.
 
     edb=               [HW,PS2]
 
-    ether=             [HW,NET] Ethernet.
+    ether=             [HW,NET] Ethernet cards parameters (iomem,irq,dev_name).
 
     fd_mcs=            [HW,SCSI]
 
@@ -129,7 +131,7 @@ running once the system is up.
 
     floppy=            [HW]
 
-    ftape=             [HW] Floppy Tape subsystem.
+    ftape=             [HW] Floppy Tape subsystem debugging options.
 
     gdth=              [HW,SCSI]
 
@@ -137,7 +139,8 @@ running once the system is up.
 
     gvp11=             [HW,SCSI]
 
-    hd=                [EIDE] IDE and EIDE hard drive subsystem.
+    hd=                [EIDE] (E)IDE hard drive subsystem
+                geometry (Cyl/heads/sectors) or tune parameters.
 
     hfmodem=           [HW,AX25]
 
@@ -149,10 +152,18 @@ running once the system is up.
 
     icn=               [HW,ISDN]
 
+       ide?=           [HW] (E)IDE subsystem : config (iomem/irq), tuning or
+                     debugging (serialize,reset,no{dma,tune,probe}) or
+                                       chipset specific parameters
+
+       idebus=         [HW] (E)IDE subsystem : VLB/PCI bus speed
+
     in2000=            [HW,SCSI]
 
     init=              [KNL]
 
+       initrd=         [KNL] initial ramdisk path
+
     ip=                [PNP]
 
     isp16=             [HW,CD]
@@ -185,7 +196,7 @@ running once the system is up.
 
     kbd-reset          [VT]
 
-    load_ramdisk=      [RAM]
+    load_ramdisk=      [RAM] initrd loading boolean
 
     lp=                [LPT] Parallel Printer.
 
@@ -204,7 +215,7 @@ running once the system is up.
 
     mcdx=              [HW,CD]
 
-    md=                [HW]
+    md=                [HW] RAID subsystems devices and level
 
     mdacon=            [MDA]
 
@@ -224,6 +235,8 @@ running once the system is up.
 
     nfsroot=           [NFS]
 
+       nmi_watchdog=   [KNL, BUGS=ix86] debugging features for SMP kernels
+
     no387              [BUGS=ix86] Tells the kernel to use the 387 maths
                        emulation library even if a 387 maths coprocessor
                        is present.
@@ -231,6 +244,10 @@ running once the system is up.
     noapic             [SMP,APIC] Tells the kernel not to make use of any
                        APIC that may be present on the system.
 
+    noasync            [HW, M68K] Disables async and sync negotiation for all devices.
+
+    nodisconnect       [HW,SCSI, M68K] Disables SCSI disconnects.
+
     no-halt            [BUGS=ix86]
 
     noinitrd           [RAM] Tells the kernel not to load any configured
@@ -240,6 +257,8 @@ running once the system is up.
 
     nosmp              [SMP] Tells an SMP kernel to act as a UP kernel.
 
+    nosync             [HW, M68K] Disables sync negotiation for all devices.
+
     optcd=             [HW,CD]
 
     panic=             
@@ -260,7 +279,7 @@ running once the system is up.
 
     pg.                [PARIDE]
 
-    pirq=              [SMP,APIC]
+    pirq=              [SMP,APIC] mp-table
 
     plip=              [LP,NET] Parallel port network link.
 
@@ -275,13 +294,14 @@ running once the system is up.
 
     ramdisk_size=      [RAM]
 
-    ramdisk_start=     [RAM]
+    ramdisk_start=     [RAM] offset of the initrd image when cohabiting with
+                                       a kernel image on a floppy
 
     reboot=            [BUGS=ix86]
 
     reserve=
 
-    riscom8=           [HW,SERIAL]
+    riscom8=           [HW,SERIAL] multi-port serial driver (io parameters)
 
     ro                 [KNL] Mount root device read-only on boot.
 
@@ -303,12 +323,14 @@ running once the system is up.
 
     specialix=         [HW,SERIAL] Specialix multi-serial port adapter.
 
-    st=                [HW]
+    st=                [HW] SCSI tape parameters (buffers, ..)
 
     st0x=              [HW,SCSI]
 
     stram_swap=        [HW]
 
+    switches=          [HW, M68K]
+
     sym53c416=         [HW,SCSI]
 
     sym53c8xx=         [HW,SCSI]
@@ -331,6 +353,6 @@ running once the system is up.
 
     wdt=               [HW]
 
-    xd=                [HW,XT]
+    xd=                [HW,XT] Original XT 8bit disk controllers
 
     xd_geo=            [HW,XT]
index b5cddda99765cec77d37624ac872a1d5382373ef..a5cc3f5ce3447d3b08ebca485fe342de7cf3df92 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 13
-EXTRAVERSION =
+SUBLEVEL = 14
+EXTRAVERSION = pre1
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -381,6 +381,10 @@ mrproper: clean archmrproper
        rm -f drivers/net/hamradio/soundmodem/gentbl
        rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
        rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
+       rm -f drivers/sound/msndinit.c
+       rm -f drivers/sound/msndperm.c
+       rm -f drivers/sound/pndsperm.c
+       rm -f drivers/sound/pndspini.c
        rm -f .version .config* config.in config.old
        rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
        rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
index 19109d12e1a12ca385f63de9007b52c7296f95a6..86dcb2dc3c50b87edfad1c37687cfac5f13f8c21 100644 (file)
@@ -117,58 +117,44 @@ sys_idle(void)
        }
 }
 
-void
-generic_kill_arch (int mode, char *restart_cmd)
+struct halt_info {
+       int     mode;
+       char *  restart_cmd;
+};
+
+static void
+halt_processor(void * generic_ptr)
 {
-       /* The following currently only has any effect on SRM.  We should
-          fix MILO to understand it.  Should be pretty easy.  Also we can
-          support RESTART2 via the ipc_buffer machinations pictured below,
-          which SRM ignores.  */
+       struct percpu_struct * cpup;
+       struct halt_info * how = (struct halt_info *)generic_ptr;
+       unsigned long *flags;
+       int cpuid = smp_processor_id();
 
-       if (alpha_using_srm) {
-               struct percpu_struct *cpup;
-               unsigned long flags;
-       
-               cpup = (struct percpu_struct *)
-                 ((unsigned long)hwrpb + hwrpb->processor_offset);
-
-               flags = cpup->flags;
-
-               /* Clear reason to "default"; clear "bootstrap in progress". */
-               flags &= ~0x00ff0001UL;
-
-               if (mode == LINUX_REBOOT_CMD_RESTART) {
-                       if (!restart_cmd) {
-                               flags |= 0x00020000UL; /* "cold bootstrap" */
-                               cpup->ipc_buffer[0] = 0;
-                       } else {
-                               flags |=  0x00030000UL; /* "warm bootstrap" */
-                               strncpy((char *)cpup->ipc_buffer, restart_cmd,
-                                       sizeof(cpup->ipc_buffer));
-                       }
-               } else {
-                       flags |=  0x00040000UL; /* "remain halted" */
-               }
-                       
-               cpup->flags = flags;                                           
-               mb();                                           
+       /* No point in taking interrupts anymore. */
+       __cli();
 
-               reset_for_srm();
-               set_hae(srm_hae);
+       cpup = (struct percpu_struct *)
+                       ((unsigned long)hwrpb + hwrpb->processor_offset
+                        + hwrpb->processor_size * cpuid);
+       flags = &cpup->flags;
 
-#ifdef CONFIG_DUMMY_CONSOLE
-               /* This has the effect of reseting the VGA video origin.  */
-               take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
-#endif
+       /* Clear reason to "default"; clear "bootstrap in progress". */
+       *flags &= ~0x00ff0001UL;
+
+#ifdef __SMP__
+       /* Secondaries halt here. */
+       if (cpuid != smp_boot_cpuid) {
+               *flags |= 0x00040000UL; /* "remain halted" */
+               clear_bit(cpuid, &cpu_present_mask);
+               halt();
        }
+#endif /* __SMP__ */
 
 #ifdef CONFIG_RTC
        /* Reset rtc to defaults.  */
        {
                unsigned char control;
 
-               cli();
-
                /* Reset periodic interrupt frequency.  */
                CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 
@@ -177,24 +163,75 @@ generic_kill_arch (int mode, char *restart_cmd)
                control |= RTC_PIE;
                CMOS_WRITE(control, RTC_CONTROL);       
                CMOS_READ(RTC_INTR_FLAGS);
-
-               sti();
        }
-#endif
+#endif /* CONFIG_RTC */
+
+       if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+               if (!how->restart_cmd) {
+                       *flags |= 0x00020000UL; /* "cold bootstrap" */
+                       cpup->ipc_buffer[0] = 0;
+               } else {
+                 /* NOTE: this could really only work when returning
+                    into MILO, rather than SRM console. The latter
+                    does NOT look at the ipc_buffer to get a new
+                    boot command. It could be done by using callbacks
+                    to change some of the SRM environment variables,
+                    but that is beyond our capabilities at this time.
+                    At the moment, SRM will use the last boot device,
+                    but the file and flags will be the defaults, when
+                    doing a "warm" bootstrap.
+                 */
+                       *flags |=  0x00030000UL; /* "warm bootstrap" */
+                       strncpy((char *)cpup->ipc_buffer,
+                               how->restart_cmd,
+                               sizeof(cpup->ipc_buffer));
+               }
+       } else
+               *flags |=  0x00040000UL; /* "remain halted" */
 
-       if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
+#ifdef __SMP__
+       /* Wait for the secondaries to halt. */
+       clear_bit(smp_boot_cpuid, &cpu_present_mask);
+       while (cpu_present_mask)
+               /* Make sure we sample memory and not a register. */
+               barrier();
+#endif /* __SMP__ */
+
+        /* If booted from SRM, reset some of the original environment. */
+       if (alpha_using_srm) {
+#ifdef CONFIG_DUMMY_CONSOLE
+               /* This has the effect of resetting the VGA video origin.  */
+               take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
+#endif
+               reset_for_srm();
+               set_hae(srm_hae);
+       }
+       else if (how->mode != LINUX_REBOOT_CMD_RESTART &&
+                how->mode != LINUX_REBOOT_CMD_RESTART2) {
                /* Unfortunately, since MILO doesn't currently understand
                   the hwrpb bits above, we can't reliably halt the 
                   processor and keep it halted.  So just loop.  */
                return;
        }
 
-       if (alpha_using_srm)
-               srm_paging_stop();
-
+       /* PRIMARY */
        halt();
 }
 
+void
+generic_kill_arch(int mode, char * restart_cmd)
+{
+       struct halt_info copy_of_args;
+
+       copy_of_args.mode = mode;
+       copy_of_args.restart_cmd = restart_cmd;
+#ifdef __SMP__
+       /* A secondary can't wait here for the primary to finish, can it now? */
+       smp_call_function(halt_processor, (void *)&copy_of_args, 1, 0);
+#endif /* __SMP__ */
+       halt_processor(&copy_of_args);
+}
+
 void
 machine_restart(char *restart_cmd)
 {
index 12f181b98c3de3080cac3859c4d2a83adae50b75..743fc1d64eb4a4d895c3b475fe2db7543b0bba15 100644 (file)
@@ -153,6 +153,7 @@ extern int smp_info(char *buffer);
 extern void handle_ipi(struct pt_regs *);
 extern void smp_percpu_timer_interrupt(struct pt_regs *);
 extern int smp_boot_cpuid;
+extern unsigned long cpu_present_mask;
 
 /* bios32.c */
 extern void reset_for_srm(void);
index 9ab3b710b2bc9ec3e55d7602da7dcd81f2e1720e..16651b09643bec7a1e22e1a432de8e9fd8addcfd 100644 (file)
@@ -85,15 +85,15 @@ void cleanup_module(void)
 
 /* For 128-bit division.  */
 
-__complex__ unsigned long
+void
 udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
-       unsigned long dividend_f0, unsigned long dividend_f1)
+       unsigned long dividend_f0, unsigned long dividend_f1,
+       unsigned long *quot, unsigned long *remd)
 {
        _FP_FRAC_DECL_2(quo);
        _FP_FRAC_DECL_2(rem);
        _FP_FRAC_DECL_2(tmp);
        unsigned long i, num_bits, bit;
-       __complex__ unsigned long ret;
 
        _FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2);
        _FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2);
@@ -139,9 +139,9 @@ udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
        }
 
 out:
-       __real__ ret = quo_f1;
-       __imag__ ret = rem_f1;
-       return ret;
+       *quot = quo_f1;
+       *remd = rem_f1;
+       return;
 }
 
 /*
index 9557f5aa6dda792cf0252d34ecb7489a8a0573b5..710eade038d9f475c270760b6acd5ae6e08290e2 100644 (file)
@@ -552,15 +552,17 @@ do {                                                      \
           : "r" ((UDItype)(u)),                \
             "r" ((UDItype)(v)))
 
-extern __complex__ unsigned long udiv128(unsigned long, unsigned long,
-                                        unsigned long, unsigned long);
-
-#define udiv_qrnnd(q, r, n1, n0, d)    \
-  do {                                 \
-    __complex__ unsigned long x_;      \
-    x_ = udiv128((n0), (n1), 0, (d));  \
-    (q) = __real__ x_;                 \
-    (r) = __imag__ x_;                 \
+extern void udiv128(unsigned long, unsigned long,
+                   unsigned long, unsigned long,
+                   unsigned long *,
+                   unsigned long *);
+
+#define udiv_qrnnd(q, r, n1, n0, d)            \
+  do {                                         \
+    unsigned long xr, xi;                      \
+    udiv128((n0), (n1), 0, (d), &xr, &xi);     \
+    (q) = xr;                                  \
+    (r) = xi;                                  \
   } while (0)
 
 #define UDIV_NEEDS_NORMALIZATION 1  
index 30404dc3772b718c3a85bf559e50f4bc31afdee6..6a3fda06dcc72bf259595f7611907d3439ed4048 100644 (file)
@@ -37,7 +37,7 @@ piggy.o:      $(SYSTEM)
        tmppiggy=_tmp_$$$$piggy; \
        rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
        $(OBJCOPY) $(SYSTEM) $$tmppiggy; \
-       gzip -f -3 < $$tmppiggy > $$tmppiggy.gz; \
+       gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
        echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
        $(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
        rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
index ad78c419d9889248419ec780f951a7b2469c94d5..89beaa70fb2a06a5683440de38bc5c697881c1fb 100644 (file)
@@ -104,7 +104,7 @@ static long free_mem_end_ptr = 0x90000;
 #define LOW_BUFFER_START      0x2000
 #define LOW_BUFFER_END       0x90000
 #define LOW_BUFFER_SIZE      ( LOW_BUFFER_END - LOW_BUFFER_START )
-#define HEAP_SIZE             0x2000
+#define HEAP_SIZE             0x2400
 static int high_loaded =0;
 static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
 
index 91d338b2c2f4fe2143b65633f932347f67f47d95..44a8b61f3c042ceb1f915fe8706c615a66241f35 100644 (file)
@@ -1097,6 +1097,7 @@ static void __init pcibios_scan_buglist(struct pci_bus *b)
 
 extern int skip_ioapic_setup;
 
+extern int skip_ioapic_setup;  /* defined in arch/i386/kernel/smp.c */
 static void __init pcibios_fixup_devices(void)
 {
        struct pci_dev *dev;
index b56b379bf5145f8071ce9565bdd7b2bc954f3c7d..76854d4553b3a96618e00641e1af01434a48fcc2 100644 (file)
@@ -19,7 +19,7 @@
  * volatile is justified in this case, IO-APIC register contents
  * might change spontaneously, GCC should not cache it
  */
-#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE))
+#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
 /*
  * The structure of the IO-APIC:
@@ -47,7 +47,7 @@ struct IO_APIC_reg_02 {
 /*
  * # of IRQ routing registers
  */
-int nr_ioapic_registers = 0;
+int nr_ioapic_registers[MAX_IO_APICS];
 
 enum ioapic_irq_destination_types {
        dest_Fixed = 0,
@@ -94,6 +94,8 @@ enum mp_irq_source_types {
        mp_ExtINT = 3
 };
 
+int mp_apic_entries = 0;                       /* # of I/O APIC entries */
+struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */
 int mp_irq_entries = 0;                                /* # of MP IRQ source entries */
 struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
                                                /* MP IRQ source entries */
@@ -108,34 +110,34 @@ int mpc_default_type = 0;                 /* non-0 if default (table-less)
  * between pins and IRQs.
  */
 
-static inline unsigned int io_apic_read(unsigned int reg)
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
-       *IO_APIC_BASE = reg;
-       return *(IO_APIC_BASE+4);
+       *IO_APIC_BASE(apic) = reg;
+       return *(IO_APIC_BASE(apic)+4);
 }
 
-static inline void io_apic_write(unsigned int reg, unsigned int value)
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
 {
-       *IO_APIC_BASE = reg;
-       *(IO_APIC_BASE+4) = value;
+       *IO_APIC_BASE(apic) = reg;
+       *(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Re-write a value: to be used for read-modify-write
  * cycles where the read already set up the index register.
  */
-static inline void io_apic_modify(unsigned int value)
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
 {
-       *(IO_APIC_BASE+4) = value;
+       *(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Synchronize the IO-APIC and the CPU by doing
  * a dummy read from the IO-APIC
  */
-static inline void io_apic_sync(void)
+static inline void io_apic_sync(unsigned int apic)
 {
-       (void) *(IO_APIC_BASE+4);
+       (void) *(IO_APIC_BASE(apic)+4);
 }
 
 /*
@@ -146,7 +148,7 @@ static inline void io_apic_sync(void)
 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
 
 static struct irq_pin_list {
-       int pin, next;
+       int apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
 /*
@@ -154,7 +156,7 @@ static struct irq_pin_list {
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int pin)
+static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
        static int first_free_entry = NR_IRQS;
        struct irq_pin_list *entry = irq_2_pin + irq;
@@ -168,6 +170,7 @@ static void add_pin_to_irq(unsigned int irq, int pin)
                if (++first_free_entry >= PIN_MAP_SIZE)
                        panic("io_apic.c: whoops");
        }
+       entry->apic = apic;
        entry->pin = pin;
 }
 
@@ -183,9 +186,9 @@ static void name##_IO_APIC_irq(unsigned int irq)                    \
                pin = entry->pin;                                       \
                if (pin == -1)                                          \
                        break;                                          \
-               reg = io_apic_read(0x10 + R + pin*2);                   \
+               reg = io_apic_read(entry->apic, 0x10 + R + pin*2);      \
                reg ACTION;                                             \
-               io_apic_modify(reg);                                    \
+               io_apic_modify(entry->apic, reg);                       \
                if (!entry->next)                                       \
                        break;                                          \
                entry = irq_2_pin + entry->next;                        \
@@ -197,12 +200,12 @@ static void name##_IO_APIC_irq(unsigned int irq)                  \
  * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
  * zero. Trick by Ramesh Nalluri.
  */
-DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync())          /* destination = 0x00 */
+DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */
 DO_ACTION( enable,  1, |= 0xff000000, )                                /* destination = 0xff */
-DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync())          /* mask = 1 */
+DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
 DO_ACTION( unmask,  0, &= 0xfffeffff, )                                /* mask = 0 */
 
-static void clear_IO_APIC_pin(unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
        struct IO_APIC_route_entry entry;
 
@@ -211,16 +214,17 @@ static void clear_IO_APIC_pin(unsigned int pin)
         */
        memset(&entry, 0, sizeof(entry));
        entry.mask = 1;
-       io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0));
-       io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
+       io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+       io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
 }
 
 static void clear_IO_APIC (void)
 {
-       int pin;
+       int apic, pin;
 
-       for (pin = 0; pin < nr_ioapic_registers; pin++)
-               clear_IO_APIC_pin(pin);
+       for (apic = 0; apic < mp_apic_entries; apic++)
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+                       clear_IO_APIC_pin(apic, pin);
 }
 
 /*
@@ -270,12 +274,13 @@ void __init ioapic_pirq_setup(char *str, int *ints)
 /*
  * Find the IRQ entry number of a certain pin.
  */
-static int __init find_irq_entry(int pin, int type)
+static int __init find_irq_entry(int apic, int pin, int type)
 {
        int i;
 
        for (i = 0; i < mp_irq_entries; i++)
                if ( (mp_irqs[i].mpc_irqtype == type) &&
+                       (mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) &&
                        (mp_irqs[i].mpc_dstirq == pin))
 
                        return i;
@@ -307,21 +312,26 @@ static int __init find_timer_pin(int type)
  * Find a specific PCI IRQ entry.
  * Not an initfunc, possibly needed by modules
  */
+static int __init pin_2_irq(int idx, int apic, int pin);
 int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
 {
-       int i;
+       int apic, i;
 
        for (i = 0; i < mp_irq_entries; i++) {
                int lbus = mp_irqs[i].mpc_srcbus;
 
-               if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) &&
+               for (apic = 0; apic < mp_apic_entries; apic++)
+                       if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+                               break;
+
+               if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
                    (mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
                    !mp_irqs[i].mpc_irqtype &&
                    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
                    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) &&
                    (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)))
 
-                       return mp_irqs[i].mpc_dstirq;
+                       return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
        }
        return -1;
 }
@@ -491,9 +501,9 @@ static inline int irq_trigger(int idx)
        return MPBIOS_trigger(idx);
 }
 
-static int __init pin_2_irq(int idx, int pin)
+static int __init pin_2_irq(int idx, int apic, int pin)
 {
-       int irq;
+       int irq, i;
        int bus = mp_irqs[idx].mpc_srcbus;
 
        /*
@@ -513,9 +523,12 @@ static int __init pin_2_irq(int idx, int pin)
                case MP_BUS_PCI: /* PCI pin */
                {
                        /*
-                        * PCI IRQs are 'directly mapped'
+                        * PCI IRQs are mapped in order
                         */
-                       irq = pin;
+                       i = irq = 0;
+                       while (i < apic)
+                               irq += nr_ioapic_registers[i++];
+                       irq += pin;
                        break;
                }
                default:
@@ -545,12 +558,14 @@ static int __init pin_2_irq(int idx, int pin)
 
 static inline int IO_APIC_irq_trigger(int irq)
 {
-       int idx, pin;
+       int apic, idx, pin;
 
-       for (pin = 0; pin < nr_ioapic_registers; pin++) {
-               idx = find_irq_entry(pin,mp_INT);
-               if ((idx != -1) && (irq == pin_2_irq(idx,pin)))
-                       return irq_trigger(idx);
+       for (apic = 0; apic < mp_apic_entries; apic++) {
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+                       idx = find_irq_entry(apic,pin,mp_INT);
+                       if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+                               return irq_trigger(idx);
+               }
        }
        /*
         * nonexistent IRQs are edge default
@@ -582,11 +597,12 @@ static int __init assign_irq_vector(int irq)
 void __init setup_IO_APIC_irqs(void)
 {
        struct IO_APIC_route_entry entry;
-       int pin, idx, bus, irq, first_notcon = 1;
+       int apic, pin, idx, irq, first_notcon = 1;
 
        printk("init IO_APIC IRQs\n");
 
-       for (pin = 0; pin < nr_ioapic_registers; pin++) {
+       for (apic = 0; apic < mp_apic_entries; apic++) {
+       for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
 
                /*
                 * add it to the IO-APIC irq-routing table:
@@ -598,13 +614,13 @@ void __init setup_IO_APIC_irqs(void)
                entry.mask = 0;                         /* enable IRQ */
                entry.dest.logical.logical_dest = 0;    /* but no route */
 
-               idx = find_irq_entry(pin,mp_INT);
+               idx = find_irq_entry(apic,pin,mp_INT);
                if (idx == -1) {
                        if (first_notcon) {
-                               printk(" IO-APIC pin %d", pin);
+                               printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
                                first_notcon = 0;
                        } else
-                               printk(", %d", pin);
+                               printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
                        continue;
                }
 
@@ -617,18 +633,17 @@ void __init setup_IO_APIC_irqs(void)
                        entry.dest.logical.logical_dest = 0xff;
                }
 
-               irq = pin_2_irq(idx,pin);
-               add_pin_to_irq(irq, pin);
+               irq = pin_2_irq(idx,apic,pin);
+               add_pin_to_irq(irq, apic, pin);
 
-               if (!IO_APIC_IRQ(irq))
+               if (!apic && !IO_APIC_IRQ(irq))
                        continue;
 
                entry.vector = assign_irq_vector(irq);
 
-               bus = mp_irqs[idx].mpc_srcbus;
-
-               io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
-               io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+               io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+               io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+       }
        }
 
        if (!first_notcon)
@@ -638,7 +653,7 @@ void __init setup_IO_APIC_irqs(void)
 /*
  * Set up a certain pin as ExtINT delivered interrupt
  */
-void __init setup_ExtINT_pin(unsigned int pin, int irq)
+void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
 {
        struct IO_APIC_route_entry entry;
 
@@ -662,8 +677,8 @@ void __init setup_ExtINT_pin(unsigned int pin, int irq)
        entry.polarity = 0;
        entry.trigger = 0;
 
-       io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
-       io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+       io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+       io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
 }
 
 void __init UNEXPECTED_IO_APIC(void)
@@ -674,17 +689,14 @@ void __init UNEXPECTED_IO_APIC(void)
 
 void __init print_IO_APIC(void)
 {
-       int i;
+       int apic, i;
        struct IO_APIC_reg_00 reg_00;
        struct IO_APIC_reg_01 reg_01;
        struct IO_APIC_reg_02 reg_02;
 
        printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
-       printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers);
-
-       *(int *)&reg_00 = io_apic_read(0);
-       *(int *)&reg_01 = io_apic_read(1);
-       *(int *)&reg_02 = io_apic_read(2);
+       for (i = 0; i < mp_apic_entries; i++)
+               printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]);
 
        /*
         * We are a bit conservative about what we expect.  We have to
@@ -692,6 +704,12 @@ void __init print_IO_APIC(void)
         */
        printk("testing the IO APIC.......................\n");
 
+       for (apic = 0; apic < mp_apic_entries; apic++) {
+
+       *(int *)&reg_00 = io_apic_read(apic, 0);
+       *(int *)&reg_01 = io_apic_read(apic, 1);
+       *(int *)&reg_02 = io_apic_read(apic, 2);
+       printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid);
        printk(".... register #00: %08X\n", *(int *)&reg_00);
        printk(".......    : physical APIC id: %02X\n", reg_00.ID);
        if (reg_00.__reserved_1 || reg_00.__reserved_2)
@@ -731,8 +749,8 @@ void __init print_IO_APIC(void)
        for (i = 0; i <= reg_01.entries; i++) {
                struct IO_APIC_route_entry entry;
 
-               *(((int *)&entry)+0) = io_apic_read(0x10+i*2);
-               *(((int *)&entry)+1) = io_apic_read(0x11+i*2);
+               *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+               *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
 
                printk(" %02x %03X %02X  ",
                        i,
@@ -751,7 +769,7 @@ void __init print_IO_APIC(void)
                        entry.vector
                );
        }
-
+       }
        printk(KERN_DEBUG "IRQ to pin mappings:\n");
        for (i = 0; i < NR_IRQS; i++) {
                struct irq_pin_list *entry = irq_2_pin + i;
@@ -796,9 +814,12 @@ static void __init init_sym_mode(void)
         */
        {
                struct IO_APIC_reg_01 reg_01;
+               int i;
 
-               *(int *)&reg_01 = io_apic_read(1);
-               nr_ioapic_registers = reg_01.entries+1;
+               for (i = 0; i < mp_apic_entries; i++) {
+                       *(int *)&reg_01 = io_apic_read(i, 1);
+                       nr_ioapic_registers[i] = reg_01.entries+1;
+               }
        }
 
        /*
@@ -897,15 +918,15 @@ static void __init setup_ioapic_id(void)
        /*
         * Set the ID
         */
-       *(int *)&reg_00 = io_apic_read(0);
+       *(int *)&reg_00 = io_apic_read(0, 0);
        printk("...changing IO-APIC physical APIC ID to 2...\n");
        reg_00.ID = 0x2;
-       io_apic_write(0, *(int *)&reg_00);
+       io_apic_write(0, 0, *(int *)&reg_00);
 
        /*
         * Sanity check
         */
-       *(int *)&reg_00 = io_apic_read(0);
+       *(int *)&reg_00 = io_apic_read(0, 0);
        if (reg_00.ID != 0x2)
                panic("could not set ID");
 }
@@ -1227,7 +1248,10 @@ static inline void check_timer(void)
 
                if (pin2 != -1) {
                        printk(".. (found pin %d) ...", pin2);
-                       setup_ExtINT_pin(pin2, 0);
+                       /*
+                        * legacy devices should be connected to IO APIC #0
+                        */
+                       setup_ExtINT_pin(0, pin2, 0);
                        make_8259A_irq(0);
                }
 
@@ -1238,9 +1262,9 @@ static inline void check_timer(void)
                         * Just in case ...
                         */
                        if (pin1 != -1)
-                               clear_IO_APIC_pin(pin1);
+                               clear_IO_APIC_pin(0, pin1);
                        if (pin2 != -1)
-                               clear_IO_APIC_pin(pin2);
+                               clear_IO_APIC_pin(0, pin2);
 
                        make_8259A_irq(0);
 
@@ -1282,7 +1306,8 @@ void __init setup_IO_APIC(void)
         * - those for which the user has specified a pirq= parameter
         */
        if (    ioapic_whitelisted() ||
-               (nr_ioapic_registers == 16) ||
+               (mp_apic_entries == 1 && nr_ioapic_registers[0] == 16) ||
+               (mp_apic_entries > 1) ||
                pirqs_enabled)
        {
                printk("ENABLING IO-APIC IRQs\n");
index 5187df93bca5462cb316d362679d8ceb684f339a..6d1c31212cb356d1dc9885f8c7842938597b8c62 100644 (file)
@@ -112,6 +112,11 @@ extern unsigned long io_apic_irqs;
 
 extern char _stext, _etext;
 
+/*
+ * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
+ * FIX_IO_APIC_BASE_* in fixmap.h
+ */
+#define MAX_IO_APICS 4
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
index 98a22a275f1dd9da50aa03974ef6b317ee671570..b225637b8c37be789f7ce0db7796fcc615ac799e 100644 (file)
@@ -366,7 +366,7 @@ __initfunc(void setup_arch(char **cmdline_p,
                        /* Zero is valid according to the BIOS weenies */
                        if(i386_endbase)
                        {
-                               printk(KERN_NOTICE "Ignoring bogus EBDA pointer %X\n", 
+                               printk(KERN_NOTICE "Ignoring bogus EBDA pointer %lX\n", 
                                        i386_endbase);
                        }
                        i386_endbase = BIOS_ENDBASE;
@@ -755,8 +755,8 @@ static struct cpu_model_info cpu_models[] __initdata = {
        { X86_VENDOR_INTEL,     6,
          { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
            NULL, "Pentium II (Deschutes)", "Mobile Pentium II", 
-            "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
-            NULL, NULL, NULL, NULL }},
+           "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
+           NULL, NULL, NULL, NULL, NULL }},
        { X86_VENDOR_AMD,       4,
          { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
            "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -1019,8 +1019,9 @@ int get_cpuinfo(char * buffer)
                        x86_cap_flags[14] = "mca";
                        x86_cap_flags[16] = "pat";
                        x86_cap_flags[17] = "pse36";
-                       x86_cap_flags[18] = "psn";
-                       x86_cap_flags[24] = "osfxsr";
+                       x86_cap_flags[18] = "pn";
+                       x86_cap_flags[24] = "fxsr";
+                       x86_cap_flags[25] = "xmm";
                        break;
 
                    case X86_VENDOR_CENTAUR:
index b087e6bf202993921a8a922d5ea93bec2431db4b..3a52d51138a750a70f63c5069d1ac96f5da9a0e2 100644 (file)
@@ -128,6 +128,8 @@ volatile unsigned long ipi_count;                   /* Number of IPIs delivered                             */
 const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
 
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
+extern int mp_apic_entries;
+extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
 extern int mpc_default_type;
@@ -367,11 +369,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                                        printk("I/O APIC #%d Version %d at 0x%lX.\n",
                                                m->mpc_apicid,m->mpc_apicver,
                                                m->mpc_apicaddr);
-                                       /*
-                                        * we use the first one only currently
-                                        */
-                                       if (ioapics == 1)
-                                               mp_ioapic_addr = m->mpc_apicaddr;
+                                       mp_apics [mp_apic_entries] = *m;
+                                       if (++mp_apic_entries > MAX_IO_APICS)
+                                               --mp_apic_entries;
                                }
                                mpt+=sizeof(*m);
                                count+=sizeof(*m);
@@ -403,9 +403,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                        }
                }
        }
-       if (ioapics > 1)
+       if (ioapics > MAX_IO_APICS)
        {
-               printk("Warning: Multiple IO-APICs not yet supported.\n");
+               printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics);
                printk("Warning: switching to non APIC mode.\n");
                skip_ioapic_setup=1;
        }
@@ -772,18 +772,22 @@ unsigned long __init init_smp_mappings(unsigned long memory_start)
 
 #ifdef CONFIG_X86_IO_APIC
        {
-               unsigned long ioapic_phys;
-
-               if (smp_found_config) {
-                       ioapic_phys = mp_ioapic_addr;
-               } else {
-                       ioapic_phys = __pa(memory_start);
-                       memset((void *)memory_start, 0, PAGE_SIZE);
-                       memory_start += PAGE_SIZE;
+               unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+               int i;
+
+               for (i = 0; i < mp_apic_entries; i++) {
+                       if (smp_found_config) {
+                               ioapic_phys = mp_apics[i].mpc_apicaddr;
+                       } else {
+                               ioapic_phys = __pa(memory_start);
+                               memset((void *)memory_start, 0, PAGE_SIZE);
+                               memory_start += PAGE_SIZE;
+                       }
+                       set_fixmap(idx,ioapic_phys);
+                       printk("mapped IOAPIC to %08lx (%08lx)\n",
+                                       __fix_to_virt(idx), ioapic_phys);
+                       idx++;
                }
-               set_fixmap(FIX_IO_APIC_BASE,ioapic_phys);
-               printk("mapped IOAPIC to %08lx (%08lx)\n",
-                               fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys);
        }
 #endif
 
index f0ae093fa61a6ba9c49de96e161e5cbfd4786f6f..2fef5a644c5834a6e84e8cc9e8f10e6676c79350 100644 (file)
@@ -91,8 +91,10 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -155,7 +157,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -226,10 +228,19 @@ CONFIG_SCSI_MAC53C94=y
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
@@ -238,11 +249,12 @@ CONFIG_BMAC=y
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
+# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -261,7 +273,10 @@ CONFIG_DE4X5=y
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
+
+#
+# Appletalk devices
+#
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
@@ -272,11 +287,22 @@ CONFIG_PPP=y
 #
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
-# CONFIG_RCPCI is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_DLCI is not set
 
 #
 # Amateur Radio support
@@ -311,7 +337,6 @@ CONFIG_FB_MATROX=y
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -407,6 +432,7 @@ CONFIG_DEVPTS_FS=y
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_EFS_FS is not set
 
 #
 # Network File Systems
@@ -458,6 +484,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
@@ -468,6 +495,7 @@ CONFIG_SOUND=y
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
index c63ca94797f96dbb3d1e17d19ebb586cbc04f4c3..2fef5a644c5834a6e84e8cc9e8f10e6676c79350 100644 (file)
@@ -9,14 +9,13 @@ CONFIG_PPC=y
 CONFIG_6xx=y
 # CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -24,7 +23,7 @@ CONFIG_6xx=y
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -35,11 +34,10 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
-CONFIG_PARPORT=m
-# CONFIG_PARPORT_PC is not set
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_PARPORT is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -52,6 +50,7 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -61,7 +60,7 @@ CONFIG_BOOTX_TEXT=y
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -75,16 +74,8 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
-CONFIG_BLK_DEV_CMD646=y
-# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -101,7 +92,7 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -125,7 +116,7 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
@@ -166,7 +157,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -200,14 +191,14 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -215,7 +206,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -262,7 +253,7 @@ CONFIG_BMAC=y
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
@@ -289,7 +280,6 @@ CONFIG_DE4X5=y
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
-# CONFIG_PLIP is not set
 CONFIG_PPP=y
 
 #
@@ -338,12 +328,15 @@ CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -365,13 +358,22 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -392,6 +394,14 @@ CONFIG_NVRAM=y
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -406,10 +416,10 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -475,7 +485,7 @@ CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -489,7 +499,34 @@ CONFIG_DMASOUND=y
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+CONFIG_SOUND_CS4232=m
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Kernel hacking
index 8fc5c6d3dc1c16457f0c1859409c08ff5b26692f..771c51364fd7de0cf2b488cf99952deb64c32d18 100644 (file)
@@ -287,9 +287,6 @@ chrp_pcibios_fixup(void)
        {
                if ( dev->irq )
                        dev->irq = openpic_to_irq( dev->irq );
-               /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
-               if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
-                       dev->base_address[0] += (dev->bus->number*0x08000000);
                /* these need to be absolute addrs for OF and Matrox FB -- Cort */
                if ( dev->vendor == PCI_VENDOR_ID_MATROX )
                {
@@ -306,6 +303,10 @@ chrp_pcibios_fixup(void)
                        pcibios_write_config_word(dev->bus->number,
                          dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
                }
+               if ( (dev->bus->number > 0) &&
+                    ((dev->vendor == PCI_VENDOR_ID_NCR) ||
+                     (dev->vendor == PCI_VENDOR_ID_AMD)))
+                       dev->base_address[0] += (dev->bus->number*0x08000000);
        }
 }
 
index b5c1e9328730ba28eea59d8f5ba987bb694654a4..47a1777a5a671013b08f45d71c87e7dd265a515d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130.2.3 1999/08/10 21:36:48 cort Exp $
+ *  $Id: head.S,v 1.130.2.6 1999/10/12 01:03:34 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -112,6 +112,10 @@ LG_CACHE_LINE_SIZE = 4
        
 /* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
+       /* see the comment for clear_bats() -- Cort */ \
+       li      RA,0;                   \
+       mtspr   IBAT##n##U,RA;          \
+       mtspr   DBAT##n##U,RA;          \
        lwz     RA,offset+0(reg);       \
        lwz     RB,offset+4(reg);       \
        mtspr   IBAT##n##U,RA;          \
@@ -285,6 +289,14 @@ __secondary_start:
        clrldi  r16,r16,63
        mtsdr1  r16
 #else /* CONFIG_PPC64 */
+       /*
+        * If the MMU is off clear the bats.  See clear_bat() -- Cort
+        */
+       mfmsr   r20
+       andi.   r20,r20,MSR_DR
+       bne     100f
+       bl      clear_bats
+100:
        /* 
         * allow secondary cpus to get at all of ram in early bootup
         * since their init_task may be up there -- Cort
@@ -1312,7 +1324,6 @@ hash_page:
 #else
        bnelr-
 #endif
-
        ori     r6,r6,0x100             /* set _PAGE_ACCESSED in pte */
        rlwinm  r5,r4,5,24,24           /* _PAGE_RW access -> _PAGE_DIRTY */
        rlwimi  r5,r4,7,22,22           /* _PAGE_RW -> _PAGE_HWWRITE */
@@ -2733,3 +2744,36 @@ swapper_pg_dir:
        .globl  cmd_line
 cmd_line:
        .space  512
+
+/* 
+ * An undocumented "feature" of 604e requires that the v bit
+ * be cleared before changing BAT values.
+ *
+ * Also, newer IBM firmware does not clear bat3 and 4 so
+ * this makes sure it's done.
+ *  -- Cort 
+ */
+clear_bats:
+       li      r20,0
+       
+       mtspr   DBAT0U,r20
+       mtspr   DBAT0L,r20
+       mtspr   IBAT0U,r20
+       mtspr   IBAT0L,r20
+       
+       mtspr   DBAT1U,r20
+       mtspr   DBAT1L,r20
+       mtspr   IBAT1U,r20
+       mtspr   IBAT1L,r20
+       
+       mtspr   DBAT2U,r20
+       mtspr   DBAT2L,r20
+       mtspr   IBAT2U,r20
+       mtspr   IBAT2L,r20
+       
+       mtspr   DBAT3U,r20
+       mtspr   DBAT3L,r20
+       mtspr   IBAT3U,r20
+       mtspr   IBAT3L,r20
+
+       blr
index 5990fe03672358d8d0599e0b42d18c601cb8933d..71aa08b8a2ffa68eaaed5e3cadeb3e37fbd7f360 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132.2.5 1999/09/11 03:32:50 paulus Exp $
+ * $Id: setup.c,v 1.132.2.6 1999/10/19 04:32:33 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -497,6 +497,28 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
                extern int __map_without_bats;
                __map_without_bats = 1;
        }
+
+       /* Look for mem= option on command line */
+       if (strstr(cmd_line, "mem=")) {
+               char *p, *q;
+               unsigned long maxmem = 0;
+               extern unsigned long __max_memory;
+
+               for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+                       q = p + 4;
+                       if (p > cmd_line && p[-1] != ' ')
+                               continue;
+                       maxmem = simple_strtoul(q, &q, 0);
+                       if (*q == 'k' || *q == 'K') {
+                               maxmem <<= 10;
+                               ++q;
+                       } else if (*q == 'm' || *q == 'M') {
+                               maxmem <<= 20;
+                               ++q;
+                       }
+               }
+               __max_memory = maxmem;
+       }
        
        return 0;
 }
@@ -522,7 +544,7 @@ __initfunc(void
 }
 
 __initfunc(void setup_arch(char **cmdline_p,
-                          unsigned long * memory_start_p, unsigned long * memory_end_p))
+               unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
        extern int panic_timeout;
        extern char _etext[], _edata[];
@@ -532,8 +554,11 @@ __initfunc(void setup_arch(char **cmdline_p,
 
 #ifdef CONFIG_XMON
        extern void xmon_map_scc(void);
+       char *p;
+
        xmon_map_scc();
-       if (strstr(cmd_line, "xmon"))
+       p = strstr(cmd_line, "xmon");
+       if (p != NULL && (p == cmd_line || p[-1] == ' '))
                xmon(0);
 #endif /* CONFIG_XMON */
  
@@ -547,6 +572,7 @@ __initfunc(void setup_arch(char **cmdline_p,
 
        /* Save unparsed command line copy for /proc/cmdline */
        strcpy(saved_command_line, cmd_line);
+
        *cmdline_p = cmd_line;
 
        *memory_start_p = find_available_memory();
index cd338558eaf63cf01d0b54cc582917ed68db54ca..bff308e2bfe2da6aae9acbacab750a111e26c0d7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.164.2.5 1999/09/07 00:59:22 paulus Exp $
+ *  $Id: init.c,v 1.164.2.7 1999/10/19 04:32:39 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -149,6 +149,9 @@ unsigned long inline p_mapped_by_bats(unsigned long);
  */
 int __map_without_bats = 0;
 
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
@@ -1296,7 +1299,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
        int i;
        
        /* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (256<<20)
+#define RAM_LIMIT (768<<20)
 
        memory_node = find_devices("memory");
        if (memory_node == NULL) {
@@ -1329,8 +1332,12 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
         * to our nearest IO area.
         * -- Cort
         */
-       if ( phys_mem.regions[0].size >= RAM_LIMIT )
-               phys_mem.regions[0].size = RAM_LIMIT;
+       if (__max_memory == 0 || __max_memory > RAM_LIMIT)
+               __max_memory = RAM_LIMIT;
+       if (phys_mem.regions[0].size >= __max_memory) {
+               phys_mem.regions[0].size = __max_memory;
+               phys_mem.n_regions = 1;
+       }
        total = phys_mem.regions[0].size;
        
        if (phys_mem.n_regions > 1) {
@@ -1343,20 +1350,15 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
        if (boot_infos == 0) {
                /* record which bits the prom is using */
                get_mem_prop("available", &phys_avail);
+               prom_mem = phys_mem;
+               for (i = 0; i < phys_avail.n_regions; ++i)
+                       remove_mem_piece(&prom_mem,
+                                        phys_avail.regions[i].address,
+                                        phys_avail.regions[i].size, 0);
        } else {
                /* booted from BootX - it's all available (after klimit) */
                phys_avail = phys_mem;
-       }
-       prom_mem = phys_mem;
-       for (i = 0; i < phys_avail.n_regions; ++i)
-       {
-               if ( phys_avail.regions[i].address >= RAM_LIMIT )
-                       continue;
-               if ( (phys_avail.regions[i].address+phys_avail.regions[i].size)
-                    >= RAM_LIMIT )
-                       phys_avail.regions[i].size = RAM_LIMIT - phys_avail.regions[i].address;
-               remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
-                                phys_avail.regions[i].size, 1);
+               prom_mem.n_regions = 0;
        }
 
        /*
index 57bfb9a49f07693f373b21dc712b8035e08f8f65..f9a4853718690b152a2733aeabb10e01612959e2 100644 (file)
@@ -115,9 +115,13 @@ xmon(struct pt_regs *excp)
 {
        struct pt_regs regs;
        int msr, cmd;
+       static int entered = 0;
+
+       if (!entered) {
+               entered = 1;
+               printk("Entering xmon kernel debugger.\n");
+       }
 
-       printk("Entering xmon kernel debugger.\n");
-       
        if (excp == NULL) {
                asm volatile ("stw      0,0(%0)\n\
                        lwz     0,0(1)\n\
@@ -230,7 +234,7 @@ at_breakpoint(unsigned pc)
 
        if (dabr.enabled && pc == dabr.instr)
                return &dabr;
-       if (iabr.enabled && pc == iabr.address)
+       if (iabr.enabled && ((pc ^ iabr.address) & ~3) == 0)
                return &iabr;
        bp = bpts;
        for (i = 0; i < NBPTS; ++i, ++bp)
@@ -254,7 +258,9 @@ insert_bpts()
                        printf("Couldn't insert breakpoint at %x, disabling\n",
                               bp->address);
                        bp->enabled = 0;
+                       continue;
                }
+               store_inst((void *) bp->address);
        }
        if (dabr.enabled)
                set_dabr(dabr.address);
@@ -277,9 +283,12 @@ remove_bpts()
                        continue;
                if (mread(bp->address, &instr, 4) == 4
                    && instr == bpinstr
-                   && mwrite(bp->address, &bp->instr, 4) != 4)
+                   && mwrite(bp->address, &bp->instr, 4) != 4) {
                        printf("Couldn't remove breakpoint at %x\n",
                               bp->address);
+                       continue;
+               }
+               store_inst((void *) bp->address);
        }
 }
 
index 38d7a475ccf4db905a44d9dd91377b7aa6b00f60..3c9dee4de4bc6fc2e9c179070fe3f293c395ae3d 100644 (file)
@@ -131,7 +131,9 @@ dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PAR
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
 fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+if [ "$CONFIG_PCI" = "y" ]; then
+  tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+fi
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
index 63dba9e5db415bfab359c581304144f7e105a2db..dacaaecf133a484e9861e7f3de7871f77d880877 100644 (file)
@@ -784,8 +784,11 @@ static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
        label = (struct sun_disklabel *) bh->b_data;
        p = label->partitions;
        if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
+#if 0
+               /* There is no error here - it is just not a sunlabel. */
                printk("Dev %s Sun disklabel: bad magic %04x\n",
                       kdevname(dev), be16_to_cpu(label->magic));
+#endif
                brelse(bh);
                return 0;
        }
@@ -856,8 +859,11 @@ static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sec
        p = &label->partitions[0];
        magic = label->magic_mushroom;
        if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
+#if 0
+               /* There is no error here - it is just not an sgilabel. */
                printk("Dev %s SGI disklabel: bad magic %08x\n",
                       kdevname(dev), magic);
+#endif
                brelse(bh);
                return 0;
        }
index 14ad6269ec2f76336a0db3c06489f2b24ebddf24..cd37e6a720e25fb637e0e799425b27d51a9a76ff 100644 (file)
@@ -88,30 +88,35 @@ static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsign
  */
 static int lba_capacity_is_ok (struct hd_driveid *id)
 {
-       unsigned long lba_sects   = id->lba_capacity;
-       unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
-       unsigned long _10_percent = chs_sects / 10;
+       unsigned long lba_sects, chs_sects, head, tail;
 
        /*
-        * very large drives (8GB+) may lie about the number of cylinders
-        * This is a split test for drives 8 Gig and Bigger only.
+        * The ATA spec tells large drives to return
+        * C/H/S = 16383/16/63 independent of their size.
+        * Some drives can be jumpered to use 15 heads instead of 16.
         */
-       if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
-           (id->heads == 16) && (id->sectors == 63)) {
-               id->cyls = lba_sects / (16 * 63); /* correct cyls */
-               return 1;       /* lba_capacity is our only option */
-       }
+       if (id->cyls == 16383 && id->sectors == 63 &&
+           (id->heads == 15 || id->heads == 16) &&
+           id->lba_capacity >= 16383*63*id->heads)
+               return 1;
+
+       lba_sects   = id->lba_capacity;
+       chs_sects   = id->cyls * id->heads * id->sectors;
+
        /* 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 */
-       }
+       if ((lba_sects - chs_sects) < chs_sects/10)
+               return 1;
+
        /* some drives have the word order reversed */
-       lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-       if ((lba_sects - chs_sects) < _10_percent) {
-               id->lba_capacity = lba_sects;   /* fix it */
+       head = ((lba_sects >> 16) & 0xffff);
+       tail = (lba_sects & 0xffff);
+       lba_sects = (head | (tail << 16));
+       if ((lba_sects - chs_sects) < chs_sects/10) {
+               id->lba_capacity = lba_sects;
                return 1;       /* lba_capacity is (now) good */
        }
-       return 0;       /* lba_capacity value is bad */
+
+       return 0;       /* lba_capacity value may be bad */
 }
 
 /*
@@ -446,7 +451,6 @@ 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;
                }
@@ -721,9 +725,9 @@ static void idedisk_setup (ide_drive_t *drive)
                if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
                        id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
                }
-               drive->cyl  = id->cur_cyls    = id->cyls;
-               drive->head = id->cur_heads   = id->heads;
-               drive->sect = id->cur_sectors = id->sectors;
+               drive->cyl  = id->cyls;
+               drive->head = id->heads;
+               drive->sect = id->sectors;
        }
 
        /* calculate drive capacity, and select LBA if possible */
@@ -733,21 +737,19 @@ static void idedisk_setup (ide_drive_t *drive)
         * if possible, give fdisk access to more of the drive,
         * by correcting bios_cyls:
         */
-       if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
-           (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
-               drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#ifdef DEBUG
-               printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
-                       drive->id->cur_cyls,
-                       drive->id->cur_heads,
-                       drive->id->cur_sectors,
-                       drive->bios_cyl,
-                       drive->bios_head,
-                       drive->bios_sect);
-#endif
-               drive->id->cur_cyls    = drive->bios_cyl;
-               drive->id->cur_heads   = drive->bios_head;
-               drive->id->cur_sectors = drive->bios_sect;
+       if (!drive->forced_geom &&
+           capacity > drive->bios_cyl * drive->bios_sect * drive->bios_head) {
+               unsigned long cylsize;
+               cylsize = drive->bios_sect * drive->bios_head;
+               if (cylsize == 0 || capacity/cylsize > 65535) {
+                       drive->bios_sect = 63;
+                       drive->bios_head = 255;
+                       cylsize = 63*255;
+               }
+               if (capacity/cylsize > 65535)
+                       drive->bios_cyl = 65535;
+               else
+                       drive->bios_cyl = capacity/cylsize;
        }
 
 #if 0  /* done instead for entire identify block in arch/ide.h stuff */
@@ -771,19 +773,6 @@ static void idedisk_setup (ide_drive_t *drive)
        }
        printk("\n");
 
-       if (drive->select.b.lba) {
-               if (*(int *)&id->cur_capacity0 < id->lba_capacity) {
-#ifdef DEBUG
-                       printk("     CurSects=%d, LBASects=%d, ",
-                               *(int *)&id->cur_capacity0, id->lba_capacity);
-#endif
-                       *(int *)&id->cur_capacity0 = id->lba_capacity;
-#ifdef DEBUG
-                       printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
-#endif
-               }
-       }
-
        drive->mult_count = 0;
        if (id->max_multsect) {
 #if 1  /* original, pre IDE-NFG, per request of AC */
index 26a56e7406904116f38cb9824264e59d077b50c9..a2bc04c477989b6aefbdde668ede4616615c60b1 100644 (file)
@@ -516,8 +516,10 @@ int proc_ide_read_geometry
        char            *out = page;
        int             len;
 
-       out += sprintf(out,"physical     %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
-       out += sprintf(out,"logical      %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+       out += sprintf(out,"physical     %d/%d/%d\n",
+                      drive->cyl, drive->head, drive->sect);
+       out += sprintf(out,"logical      %d/%d/%d\n",
+                      drive->bios_cyl, drive->bios_head, drive->bios_sect);
        len = out - page;
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
index 68c2640774c6c5d91535fabf7a56d08bc7e50958..c5be768fa4fb958e1fdae91d355ac36a8b8ef5e6 100644 (file)
@@ -403,7 +403,7 @@ static void writeee(struct i2c_bus *bus, unsigned char *eedata)
        }
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
         
@@ -422,7 +422,7 @@ void attach_inform(struct i2c_bus *bus, int id)
        }
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
 
index 34628a13b94fd5709f0c771503b819fcf60f642b..447767ab0c387fd5fcf52c777c3c1b2d9898eb74 100644 (file)
@@ -374,13 +374,13 @@ static int i2c_getdataline(struct i2c_bus *bus)
        return (btread(ZR36057_I2CBR) >> 1) & 1;
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
        DEBUG(struct zoran *zr = (struct zoran *) bus->data);
        DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
        DEBUG(struct zoran *zr = (struct zoran *) bus->data);
        DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
index 99c1b92bcaf3975d7d03ee97ccdeef9713c9ada9..48c7b163e708bf190f963afcd8c52271ea13fa69 100644 (file)
@@ -195,7 +195,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
        if (inb(io) & 2)        /* bit set = no signal present  */
                return 0;
index 37ae10a2a40ca192a46b8f53d989955f6bdb6957..7404083be2bf16b9b79ed49a56028bcc188d940b 100644 (file)
@@ -39,6 +39,7 @@ struct timer_list tunertimer,rdstimer,readtimer;
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
 static int cadet_lock=0;
+static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
index 793548839803a84a879e7d4667641938c4293038..29912a62e663472206e948dae458434049f9279f 100644 (file)
@@ -89,7 +89,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
        return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
        if (inb(io) & 2)        /* bit set = no signal present  */
                return 0;
index 540167bbfc030dfcbf65283da875afeb0992e3f9..7b88ecc149d2e04dbd4c3f617763b1e69bb2dfa1 100644 (file)
@@ -7,8 +7,6 @@ L_TARGET := fc4.a
 M_OBJS   :=
 MOD_LIST_NAME := FC4_MODULES
 
-include ../../.config
-
 ifeq ($(CONFIG_FC4),y)
   FC4 = fc.o
   ifeq ($(CONFIG_MODULES),y)
index 2fb1b6cbb37c3ff012e63d43b8bc6074389e47e3..e2942e133fc24ce94f94c9d88c000e3e37a47863 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
index 576b9e2003c7a09677809148aadf73b8c4a0e6c0..4553616d2520269da7f0b082371f253af438e00d 100644 (file)
@@ -6,7 +6,9 @@
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
- * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $
+ * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
+ *
+ * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
  */
 
 #include <linux/config.h>
@@ -28,6 +30,7 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
+#include <linux/slab.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -42,6 +45,7 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#include <asm/dbdma.h>
 
 #include "macserial.h"
 
@@ -53,6 +57,8 @@ static struct pmu_sleep_notifier serial_sleep_notifier = {
 };
 #endif
 
+#define SUPPORT_SERIAL_DMA
+
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -128,6 +134,13 @@ static void change_speed(struct mac_serial *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int set_scc_power(struct mac_serial * info, int state);
 static int setup_scc(struct mac_serial * info);
+static void dbdma_reset(volatile struct dbdma_regs *dma);
+static void dbdma_flush(volatile struct dbdma_regs *dma);
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void dma_init(struct mac_serial * info);
+static void rxdma_start(struct mac_serial * info, int current);
+static void rxdma_to_tty(struct mac_serial * info);
 
 static struct tty_struct *serial_table[NUM_CHANNELS];
 static struct termios *serial_termios[NUM_CHANNELS];
@@ -153,7 +166,7 @@ static struct semaphore tmp_buf_sem = MUTEX;
 __openfirmware
 #endif /* MODULE */
 static inline int serial_paranoia_check(struct mac_serial *info,
-                                       dev_t device, const char *routine)
+                                       dev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
        static const char *badmagic =
@@ -177,7 +190,7 @@ static inline int serial_paranoia_check(struct mac_serial *info,
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct mac_zschannel *channel,
-                                      unsigned char reg)
+                                      unsigned char reg)
 {
        unsigned char retval;
        unsigned long flags;
@@ -197,7 +210,7 @@ static inline unsigned char read_zsreg(struct mac_zschannel *channel,
 }
 
 static inline void write_zsreg(struct mac_zschannel *channel,
-                              unsigned char reg, unsigned char value)
+                              unsigned char reg, unsigned char value)
 {
        unsigned long flags;
 
@@ -289,6 +302,39 @@ static inline void rs_recv_clear(struct mac_zschannel *zsc)
        write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
 }
 
+/*
+ * Reset a Descriptor-Based DMA channel.
+ */
+static void dbdma_reset(volatile struct dbdma_regs *dma)
+{
+       int i;
+
+       out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+       /*
+        * Yes this looks peculiar, but apparently it needs to be this
+        * way on some machines.  (We need to make sure the DBDMA
+        * engine has actually got the write above and responded
+        * to it. - paulus)
+        */
+       for (i = 200; i > 0; --i)
+               if (ld_le32(&dma->control) & RUN)
+                       udelay(1);
+}
+
+/*
+ * Tells a DBDMA channel to stop and write any buffered data
+ * it might have to memory.
+ */
+static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
+{
+       int i = 0;
+
+       out_le32(&dma->control, (FLUSH << 16) | FLUSH);
+       while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
+               udelay(1);
+}
+
 /*
  * ----------------------------------------------------------------------
  *
@@ -312,6 +358,22 @@ static _INLINE_ void rs_sched_event(struct mac_serial *info,
        mark_bh(MACSERIAL_BH);
 }
 
+/* Work out the flag value for a z8530 status value. */
+static _INLINE_ int stat_to_flag(int stat)
+{
+       int flag;
+
+       if (stat & Rx_OVR) {
+               flag = TTY_OVERRUN;
+       } else if (stat & FRM_ERR) {
+               flag = TTY_FRAME;
+       } else if (stat & PAR_ERR) {
+               flag = TTY_PARITY;
+       } else
+               flag = 0;
+       return flag;
+}
+
 static _INLINE_ void receive_chars(struct mac_serial *info,
                                   struct pt_regs *regs)
 {
@@ -349,14 +411,7 @@ static _INLINE_ void receive_chars(struct mac_serial *info,
                        if (flip_max_cnt < tty->flip.count)
                                flip_max_cnt = tty->flip.count;
                }
-               if (stat & Rx_OVR) {
-                       flag = TTY_OVERRUN;
-               } else if (stat & FRM_ERR) {
-                       flag = TTY_FRAME;
-               } else if (stat & PAR_ERR) {
-                       flag = TTY_PARITY;
-               } else
-                       flag = 0;
+               flag = stat_to_flag(stat);
                if (flag)
                        /* reset the error indication */
                        write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -452,6 +507,32 @@ static _INLINE_ void status_handle(struct mac_serial *info)
        info->read_reg_zero = status;
 }
 
+static _INLINE_ void receive_special_dma(struct mac_serial *info)
+{
+       unsigned char stat, flag;
+       volatile struct dbdma_regs *rd = &info->rx->dma;
+       int where = RX_BUF_SIZE;
+
+       spin_lock(&info->rx_dma_lock);
+       if ((ld_le32(&rd->status) & ACTIVE) != 0)
+               dbdma_flush(rd);
+       if (in_le32(&rd->cmdptr)
+           == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
+               where -= in_le16(&info->rx->res_count);
+       where--;
+       
+       stat = read_zsreg(info->zs_channel, R1);
+
+       flag = stat_to_flag(stat);
+       if (flag) {
+               info->rx_flag_buf[info->rx_cbuf][where] = flag;
+               /* reset the error indication */
+               write_zsreg(info->zs_channel, 0, ERR_RES);
+       }
+
+       spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * This is the serial driver's generic interrupt routine
  */
@@ -461,6 +542,12 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        unsigned char zs_intreg;
        int shift;
 
+       if (!(info->flags & ZILOG_INITIALIZED)) {
+               printk("rs_interrupt: irq %d, port not initialized\n", irq);
+               disable_irq(irq);
+               return;
+       }
+
        /* NOTE: The read register 3, which holds the irq status,
         *       does so for both channels on each chip.  Although
         *       the status value itself must be read from the A
@@ -477,19 +564,21 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        for (;;) {
                zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
 #ifdef SERIAL_DEBUG_INTR
-               printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+               printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
+                      irq, (int)zs_intreg);
 #endif 
 
                if ((zs_intreg & CHAN_IRQMASK) == 0)
                        break;
 
-               if (!(info->flags & ZILOG_INITIALIZED)) {
-                       printk("rs_interrupt: irq %d, port not initialized\n", irq);
-                       break;
+               if (zs_intreg & CHBRxIP) {
+                       /* If we are doing DMA, we only ask for interrupts
+                          on characters with errors or special conditions. */
+                       if (info->dma_initted)
+                               receive_special_dma(info);
+                       else
+                               receive_chars(info, regs);
                }
-
-               if (zs_intreg & CHBRxIP)
-                       receive_chars(info, regs);
                if (zs_intreg & CHBTxIP)
                        transmit_chars(info);
                if (zs_intreg & CHBEXT)
@@ -497,6 +586,39 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        }
 }
 
+/* Transmit DMA interrupt - not used at present */
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/*
+ * Receive DMA interrupt.
+ */
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct mac_serial *info = (struct mac_serial *) dev_id;
+       volatile struct dbdma_cmd *cd;
+
+       if (!info->dma_initted)
+               return;
+       spin_lock(&info->rx_dma_lock);
+       /* First, confirm that this interrupt is, indeed, coming */
+       /* from Rx DMA */
+       cd = info->rx_cmds[info->rx_cbuf] + 2;
+       if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
+               spin_unlock(&info->rx_dma_lock);
+               return;
+       }
+       if (info->rx_fbuf != RX_NO_FBUF) {
+               info->rx_cbuf = info->rx_fbuf;
+               if (++info->rx_fbuf == info->rx_nbuf)
+                       info->rx_fbuf = 0;
+               if (info->rx_fbuf == info->rx_ubuf)
+                       info->rx_fbuf = RX_NO_FBUF;
+       }
+       spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * -------------------------------------------------------------------
  * Here ends the serial interrupt routines.
@@ -592,10 +714,6 @@ static void do_softint(void *private_)
        }
 }
 
-static void rs_timer(void)
-{
-}
-
 static int startup(struct mac_serial * info, int can_sleep)
 {
        int delay;
@@ -631,6 +749,10 @@ static int startup(struct mac_serial * info, int can_sleep)
 
        info->flags |= ZILOG_INITIALIZED;
        enable_irq(info->irq);
+       if (info->dma_initted) {
+//             enable_irq(info->tx_dma_irq);
+               enable_irq(info->rx_dma_irq);
+       }
 
        if (delay) {
                if (can_sleep) {
@@ -644,6 +766,187 @@ static int startup(struct mac_serial * info, int can_sleep)
        return 0;
 }
 
+static _INLINE_ void rxdma_start(struct mac_serial * info, int current)
+{
+       volatile struct dbdma_regs *rd = &info->rx->dma;
+       volatile struct dbdma_cmd *cd = info->rx_cmds[current];
+
+//printk(KERN_DEBUG "SCC: rxdma_start\n");
+
+       st_le32(&rd->cmdptr, virt_to_bus(cd));
+       out_le32(&rd->control, (RUN << 16) | RUN);
+}
+
+static void rxdma_to_tty(struct mac_serial *info)
+{
+       struct tty_struct       *tty = info->tty;
+       volatile struct dbdma_regs *rd = &info->rx->dma;
+       unsigned long flags;
+       int residue, available, space, do_queue;
+
+       if (!tty)
+               return;
+
+       do_queue = 0;
+       spin_lock_irqsave(&info->rx_dma_lock, flags);
+more:
+       space = TTY_FLIPBUF_SIZE - tty->flip.count;
+       if (!space) {
+               do_queue++;
+               goto out;
+       }
+       residue = 0;
+       if (info->rx_ubuf == info->rx_cbuf) {
+               if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+                       dbdma_flush(rd);
+                       if (in_le32(&rd->cmdptr)
+                           == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
+                               residue = in_le16(&info->rx->res_count);
+               }
+       }
+       available = RX_BUF_SIZE - residue - info->rx_done_bytes;
+       if (available > space)
+               available = space;
+       if (available) {
+               memcpy(tty->flip.char_buf_ptr,
+                      info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
+                      available);
+               memcpy(tty->flip.flag_buf_ptr,
+                      info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+                      available);
+               tty->flip.char_buf_ptr += available;
+               tty->flip.count += available;
+               tty->flip.flag_buf_ptr += available;
+               memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+                      0, available);
+               info->rx_done_bytes += available;
+               do_queue++;
+       }
+       if (info->rx_done_bytes == RX_BUF_SIZE) {
+               volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
+
+               if (info->rx_ubuf == info->rx_cbuf)
+                       goto out;
+               /* mark rx_char_buf[rx_ubuf] free */
+               st_le16(&cd->command, DBDMA_NOP);
+               cd++;
+               st_le32(&cd->cmd_dep, 0);
+               st_le32((unsigned int *)&cd->res_count, 0);
+               cd++;
+               st_le16(&cd->xfer_status, 0);
+
+               if (info->rx_fbuf == RX_NO_FBUF) {
+                       info->rx_fbuf = info->rx_ubuf;
+                       if (!(ld_le32(&rd->status) & ACTIVE)) {
+                               dbdma_reset(&info->rx->dma);
+                               rxdma_start(info, info->rx_ubuf);
+                               info->rx_cbuf = info->rx_ubuf;
+                       }
+               }
+               info->rx_done_bytes = 0;
+               if (++info->rx_ubuf == info->rx_nbuf)
+                       info->rx_ubuf = 0;
+               if (info->rx_fbuf == info->rx_ubuf)
+                       info->rx_fbuf = RX_NO_FBUF;
+               goto more;
+       }
+out:
+       spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+       if (do_queue)
+               queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static void poll_rxdma(void *private_)
+{
+       struct mac_serial       *info = (struct mac_serial *) private_;
+       unsigned long flags;
+
+       rxdma_to_tty(info);
+       spin_lock_irqsave(&info->rx_dma_lock, flags);
+       mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
+       spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+}
+
+static void dma_init(struct mac_serial * info)
+{
+       int i, size;
+       volatile struct dbdma_cmd *cd;
+       unsigned char *p;
+
+//printk(KERN_DEBUG "SCC: dma_init\n");
+
+       info->rx_nbuf = 8;
+
+       /* various mem set up */
+       size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
+               + (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
+                  + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
+               * info->rx_nbuf;
+       info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
+       if (info->dma_priv == NULL)
+               return;
+       memset(info->dma_priv, 0, size);
+
+       info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
+       info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
+       info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
+       p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
+       for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+               info->rx_char_buf[i] = p;
+       for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+               info->rx_flag_buf[i] = p;
+
+       /* a bit of DMA programming */
+       cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
+       st_le16(&cd->command, DBDMA_NOP);
+       cd++;
+       st_le16(&cd->req_count, RX_BUF_SIZE);
+       st_le16(&cd->command, INPUT_MORE);
+       st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
+       cd++;
+       st_le16(&cd->req_count, 4);
+       st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+       st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+       st_le32(&cd->cmd_dep, DBDMA_STOP);
+       for (i = 1; i < info->rx_nbuf; i++) {
+               info->rx_cmds[i] = ++cd;
+               st_le16(&cd->command, DBDMA_NOP);
+               cd++;
+               st_le16(&cd->req_count, RX_BUF_SIZE);
+               st_le16(&cd->command, INPUT_MORE);
+               st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
+               cd++;
+               st_le16(&cd->req_count, 4);
+               st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+               st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+               st_le32(&cd->cmd_dep, DBDMA_STOP);
+       }
+       cd++;
+       st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
+       st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
+
+       /* setup DMA to our liking */
+       dbdma_reset(&info->rx->dma);
+       st_le32(&info->rx->dma.intr_sel, 0x10001);
+       st_le32(&info->rx->dma.br_sel, 0x10001);
+       out_le32(&info->rx->dma.wait_sel, 0x10001);
+
+       /* set various flags */
+       info->rx_ubuf = 0;
+       info->rx_cbuf = 0;
+       info->rx_fbuf = info->rx_ubuf + 1;
+       if (info->rx_fbuf == info->rx_nbuf)
+               info->rx_fbuf = RX_NO_FBUF;
+       info->rx_done_bytes = 0;
+
+       /* setup polling */
+       init_timer(&info->poll_dma_timer);
+       info->poll_dma_timer.function = (void *)&poll_rxdma;
+       info->poll_dma_timer.data = (unsigned long)info;
+
+       info->dma_initted = 1;
+}
+
 static int setup_scc(struct mac_serial * info)
 {
        unsigned long flags;
@@ -668,6 +971,12 @@ static int setup_scc(struct mac_serial * info)
        ZS_CLEARFIFO(info->zs_channel);
        info->xmit_fifo_size = 1;
 
+       /*
+        * Reset DMAs
+        */
+       if (info->has_dma)
+               dma_init(info);
+
        /*
         * Clear the interrupt registers.
         */
@@ -682,7 +991,23 @@ static int setup_scc(struct mac_serial * info)
        /*
         * Finally, enable sequencing and interrupts
         */
-       info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+       if (!info->dma_initted) {
+               /* interrupt on ext/status changes, all received chars,
+                  transmit ready */
+               info->curregs[1] = (info->curregs[1] & ~0x18)
+                               | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+       } else {
+               /* interrupt on ext/status changes, W/Req pin is
+                  receive DMA request */
+               info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
+                               | (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+               write_zsreg(info->zs_channel, 1, info->curregs[1]);
+               /* enable W/Req pin */
+               info->curregs[1] |= WT_RDY_ENAB;
+               write_zsreg(info->zs_channel, 1, info->curregs[1]);
+               /* enable interrupts on transmit ready and receive errors */
+               info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
+       }
        info->pendregs[1] = info->curregs[1];
        info->curregs[3] |= (RxENABLE | Rx8);
        info->pendregs[3] = info->curregs[3];
@@ -708,6 +1033,14 @@ static int setup_scc(struct mac_serial * info)
 
        restore_flags(flags);
 
+       if (info->dma_initted) {
+               spin_lock_irqsave(&info->rx_dma_lock, flags);
+               rxdma_start(info, 0);
+               info->poll_dma_timer.expires = RX_DMA_TIMER;
+               add_timer(&info->poll_dma_timer);
+               spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+       }
+
        return 0;
 }
 
@@ -729,7 +1062,14 @@ static void shutdown(struct mac_serial * info)
        
                return;
        }
-       
+
+       if (info->has_dma) {
+               del_timer(&info->poll_dma_timer);
+               dbdma_reset(info->tx_dma);
+               dbdma_reset(&info->rx->dma);
+               disable_irq(info->tx_dma_irq);
+               disable_irq(info->rx_dma_irq);
+       }
        disable_irq(info->irq);
 
        info->pendregs[1] = info->curregs[1] = 0;
@@ -755,6 +1095,12 @@ static void shutdown(struct mac_serial * info)
                info->xmit_buf = 0;
        }
 
+       if (info->has_dma && info->dma_priv) {
+               kfree(info->dma_priv);
+               info->dma_priv = NULL;
+               info->dma_initted = 0;
+       }
+
        memset(info->curregs, 0, sizeof(info->curregs));
        memset(info->curregs, 0, sizeof(info->pendregs));
 
@@ -1052,7 +1398,6 @@ static int rs_write(struct tty_struct * tty, int from_user,
        if (!tty || !info->xmit_buf || !tmp_buf)
                return 0;
 
-       save_flags(flags);
        if (from_user) {
                down(&tmp_buf_sem);
                while (1) {
@@ -1068,6 +1413,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                                        ret = -EFAULT;
                                break;
                        }
+                       save_flags(flags);
                        cli();
                        c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                       SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1083,6 +1429,7 @@ static int rs_write(struct tty_struct * tty, int from_user,
                up(&tmp_buf_sem);
        } else {
                while (1) {
+                       save_flags(flags);
                        cli();          
                        c = MIN(count,
                                MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
@@ -1104,7 +1451,6 @@ static int rs_write(struct tty_struct * tty, int from_user,
        if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
            && !info->tx_active)
                transmit_chars(info);
-       restore_flags(flags);
        return ret;
 }
 
@@ -1133,12 +1479,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
                return;
-       cli();
+       save_flags(flags); cli();
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       sti();
+       restore_flags(flags);
        wake_up_interruptible(&tty->write_wait);
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
            tty->ldisc.write_wakeup)
@@ -1158,7 +1505,6 @@ static void rs_throttle(struct tty_struct * tty)
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
        
        printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1195,7 +1541,6 @@ static void rs_unthrottle(struct tty_struct * tty)
        struct mac_serial *info = (struct mac_serial *)tty->driver_data;
        unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-       char    buf[64];
        
        printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1473,6 +1818,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        save_flags(flags); cli();
        
        if (tty_hung_up_p(filp)) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
@@ -1498,6 +1844,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                info->count = 0;
        }
        if (info->count) {
+               MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
        }
@@ -1518,8 +1865,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
 #endif
        tty->closing = 1;
-       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+       if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
+               restore_flags(flags);
                tty_wait_until_sent(tty, info->closing_wait);
+               save_flags(flags); cli();
+       }
+
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receiver and receive interrupts.
@@ -1539,7 +1890,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 #ifdef SERIAL_DEBUG_OPEN
                printk("waiting end of Rx...\n");
 #endif
+               restore_flags(flags);
                rs_wait_until_sent(tty, info->timeout);
+               save_flags(flags); cli();
        }
 
        shutdown(info);
@@ -1565,6 +1918,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
                         ZILOG_CLOSING);
        wake_up_interruptible(&info->close_wait);
+       MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1603,7 +1957,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                char_time = MIN(char_time, timeout);
        while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;   /* make us low-priority */
                schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
@@ -1775,14 +2128,19 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        int                     retval, line;
        unsigned long           page;
 
+       MOD_INC_USE_COUNT;
        line = MINOR(tty->device) - tty->driver.minor_start;
-       if ((line < 0) || (line >= zs_channels_found))
+       if ((line < 0) || (line >= zs_channels_found)) {
+               MOD_DEC_USE_COUNT;
                return -ENODEV;
+       }
        info = zs_soft + line;
 
 #ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
+       if (info->kgdb_channel) {
+               MOD_DEC_USE_COUNT;
                return -ENODEV;
+       }
 #endif
        if (serial_paranoia_check(info, tty->device, "rs_open"))
                return -ENODEV;
@@ -1865,7 +2223,58 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       printk("PowerMac Z8530 serial driver version 1.01\n");
+       printk("PowerMac Z8530 serial driver version 2.0\n");
+}
+
+/*
+ * Initialize one channel, both the mac_serial and mac_zschannel
+ * structs.  We use the dev_node field of the mac_serial struct.
+ */
+static void
+chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
+         struct mac_zschannel *zs_chan_a)
+{
+       struct device_node *ch = zss->dev_node;
+       char *conn;
+       int len;
+
+       zss->irq = ch->intrs[0].line;
+       zss->has_dma = 0;
+#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
+       if (ch->n_addrs == 3 && ch->n_intrs == 3)
+               zss->has_dma = 1;
+#endif
+       zss->dma_initted = 0;
+
+       zs_chan->control = (volatile unsigned char *)
+               ioremap(ch->addrs[0].address, 0x1000);
+       zs_chan->data = zs_chan->control + 0x10;
+       spin_lock_init(&zs_chan->lock);
+       zs_chan->parent = zss;
+       zss->zs_channel = zs_chan;
+       zss->zs_chan_a = zs_chan_a;
+
+       /* setup misc varariables */
+       zss->kgdb_channel = 0;
+       zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+
+       /* XXX tested only with wallstreet PowerBook,
+          should do no harm anyway */
+       conn = get_property(ch, "AAPL,connector", &len);
+       zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+
+       if (zss->has_dma) {
+               zss->dma_priv = NULL;
+               /* it seems that the last two addresses are the
+                  DMA controllers */
+               zss->tx_dma = (volatile struct dbdma_regs *)
+                       ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
+               zss->rx = (volatile struct mac_dma *)
+                       ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
+               zss->tx_dma_irq = ch->intrs[1].line;
+               zss->rx_dma_irq = ch->intrs[2].line;
+               spin_lock_init(&zss->rx_dma_lock);
+       }
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -1874,51 +2283,63 @@ probe_sccs()
 {
        struct device_node *dev, *ch;
        struct mac_serial **pp;
-       int n, lenp;
-       char *conn;
+       int n, chip, nchan;
+       struct mac_zschannel *zs_chan;
+       int chan_a_index;
 
        n = 0;
        pp = &zs_chain;
+       zs_chan = zs_channels;
        for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+               nchan = 0;
+               chip = n;
                if (n >= NUM_CHANNELS) {
                        printk("Sorry, can't use %s: no more channels\n",
                               dev->full_name);
                        continue;
                }
+               chan_a_index = 0;
                for (ch = dev->child; ch != 0; ch = ch->sibling) {
+                       if (nchan >= 2) {
+                               printk(KERN_WARNING "SCC: Only 2 channels per "
+                                       "chip are supported\n");
+                               break;
+                       }
                        if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
                                printk("Can't use %s: %d addrs %d intrs\n",
                                      ch->full_name, ch->n_addrs, ch->n_intrs);
                                continue;
                        }
-                       zs_channels[n].control = (volatile unsigned char *)
-                               ioremap(ch->addrs[0].address, 0x1000);
-                       zs_channels[n].data = zs_channels[n].control + 0x10;
-                       spin_lock_init(&zs_channels[n].lock);
-                       zs_soft[n].zs_channel = &zs_channels[n];
-                       zs_soft[n].dev_node = ch;
-                       zs_soft[n].irq = ch->intrs[0].line;
-                       zs_soft[n].zs_channel->parent = &zs_soft[n];
-                       zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
-
-                       /* XXX tested only with wallstreet PowerBook,
-                          should do no harm anyway */
-                       conn = get_property(ch, "AAPL,connector", &lenp);
-                       zs_soft[n].is_pwbk_ir =
-                               conn && (strcmp(conn, "infrared") == 0);
-
-                       /* XXX this assumes the prom puts chan A before B */
-                       if (n & 1)
-                               zs_soft[n].zs_chan_a = &zs_channels[n-1];
-                       else
-                               zs_soft[n].zs_chan_a = &zs_channels[n];
 
+                       /* The channel with the higher address
+                          will be the A side. */
+                       if (nchan > 0 &&
+                           ch->addrs[0].address
+                           > zs_soft[n-1].dev_node->addrs[0].address)
+                               chan_a_index = 1;
+
+                       /* minimal initialization for now */
+                       zs_soft[n].dev_node = ch;
                        *pp = &zs_soft[n];
                        pp = &zs_soft[n].zs_next;
+                       ++nchan;
                        ++n;
                }
+               if (nchan == 0)
+                       continue;
+
+               /* set up A side */
+               chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan);
+               ++zs_chan;
+
+               /* set up B side, if it exists */
+               if (nchan > 1)
+                       chan_init(&zs_soft[chip + 1 - chan_a_index],
+                                 zs_chan, zs_chan - 1);
+               ++zs_chan;
        }
        *pp = 0;
+
        zs_channels_found = n;
 #ifdef CONFIG_PMAC_PBOOK
        if (n)
@@ -1935,8 +2356,6 @@ int macserial_init(void)
 
        /* Setup base handler, and timer table. */
        init_bh(MACSERIAL_BH, do_serial_bh);
-       timer_table[RS_TIMER].fn = rs_timer;
-       timer_table[RS_TIMER].expires = 0;
 
        /* Find out how many Z8530 SCCs we have */
        if (zs_chain == 0)
@@ -1948,6 +2367,18 @@ int macserial_init(void)
        /* Register the interrupt handler for each one */
        save_flags(flags); cli();
        for (i = 0; i < zs_channels_found; ++i) {
+               if (zs_soft[i].has_dma) {
+                       if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
+                                       "SCC-txdma", &zs_soft[i]))
+                               printk(KERN_ERR "macserial: can't get irq %d\n",
+                                      zs_soft[i].tx_dma_irq);
+                       disable_irq(zs_soft[i].tx_dma_irq);
+                       if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
+                                       "SCC-rxdma", &zs_soft[i]))
+                               printk(KERN_ERR "macserial: can't get irq %d\n",
+                                      zs_soft[i].rx_dma_irq);
+                       disable_irq(zs_soft[i].rx_dma_irq);
+               }
                if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
                                "SCC", &zs_soft[i]))
                        printk(KERN_ERR "macserial: can't get irq %d\n",
@@ -2107,8 +2538,13 @@ void cleanup_module(void)
        for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
                set_scc_power(info, 0);
        save_flags(flags); cli();
-       for (i = 0; i < zs_channels_found; ++i)
+       for (i = 0; i < zs_channels_found; ++i) {
                free_irq(zs_soft[i].irq, &zs_soft[i]);
+               if (zs_soft[i].has_dma) {
+                       free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
+                       free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
+               }
+       }
        restore_flags(flags);
        tty_unregister_driver(&callout_driver);
        tty_unregister_driver(&serial_driver);
@@ -2238,6 +2674,8 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
        if (zs_chain == 0)
                return -1;
 
+       set_scc_power(info, 1);
+
        /* Reset the channel */
        write_zsreg(info->zs_channel, R9, CHRA);
 
@@ -2481,14 +2919,13 @@ __initfunc(void zs_kgdb_hook(int tty_num))
        if (zs_chain == 0)
                probe_sccs();
 
-       set_scc_power(&zs_soft[n], 1);
+       set_scc_power(&zs_soft[tty_num], 1);
        
        zs_kgdbchan = zs_soft[tty_num].zs_channel;
        zs_soft[tty_num].change_needed = 0;
        zs_soft[tty_num].clk_divisor = 16;
        zs_soft[tty_num].zs_baud = 38400;
        zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-       zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
 
        /* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
index 39b55a4d635ae368d0c8692a2c1f3f23da1c3dbc..188589d1955d1a3f5cff5bc518e093eca299689e 100644 (file)
@@ -92,6 +92,13 @@ struct mac_zschannel {
        struct mac_serial*      parent;
 };
 
+struct mac_dma {
+       volatile struct dbdma_regs      dma;
+       volatile unsigned short         res_count;
+       volatile unsigned short         command;
+       volatile unsigned int           buf_addr;
+};
+
 struct mac_serial {
        struct mac_serial *zs_next;     /* For IRQ servicing chain */
        struct mac_zschannel *zs_channel; /* Channel registers */
@@ -156,6 +163,28 @@ struct mac_serial {
        struct termios          callout_termios;
        struct wait_queue       *open_wait;
        struct wait_queue       *close_wait;
+
+       volatile struct dbdma_regs *tx_dma;
+       int                     tx_dma_irq;
+       volatile struct dbdma_cmd *tx_cmds;
+       volatile struct mac_dma *rx;
+       int                     rx_dma_irq;
+       volatile struct dbdma_cmd **rx_cmds;
+       unsigned char           **rx_char_buf;
+       unsigned char           **rx_flag_buf;
+#define        RX_BUF_SIZE     256
+       int                     rx_nbuf;
+       int                     rx_done_bytes;
+       int                     rx_ubuf;
+       int                     rx_fbuf;
+#define        RX_NO_FBUF      (-1)
+       int                     rx_cbuf;
+       spinlock_t              rx_dma_lock;
+       int                     has_dma;
+       int                     dma_initted;
+       void                    *dma_priv;
+       struct timer_list       poll_dma_timer;
+#define RX_DMA_TIMER   (jiffies + 10*HZ/1000)
 };
 
 
@@ -226,9 +255,9 @@ struct mac_serial {
 #define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
 #define        INT_ERR_Rx      0x18    /* Int on error only */
 
-#define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
-#define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */
-#define        WT_RDY_ENAB     0x80    /* Wait/Ready Enable */
+#define        WT_RDY_RT       0x20    /* W/Req reflects recv if 1, xmit if 0 */
+#define        WT_FN_RDYFN     0x40    /* W/Req pin is DMA request if 1, wait if 0 */
+#define        WT_RDY_ENAB     0x80    /* Enable W/Req pin */
 
 /* Write Register #2 (Interrupt Vector) */
 
@@ -286,6 +315,9 @@ struct mac_serial {
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (Some enhanced feature control) */
+#define        ENEXREAD        0x40    /* Enable read of some write registers */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -346,7 +378,9 @@ struct mac_serial {
 #define        SNRZI   0xe0    /* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define        EN85C30 1       /* Enable some 85c30-enhanced registers */
 #define        ZCIE    2       /* Zero count IE */
+#define        ENSTFIFO 4      /* Enable status FIFO (SDLC) */
 #define        DCDIE   8       /* DCD IE */
 #define        SYNCIE  0x10    /* Sync/hunt IE */
 #define        CTSIE   0x20    /* CTS IE */
@@ -382,6 +416,15 @@ struct mac_serial {
 #define        END_FR          0x80    /* End of Frame (SDLC) */
 
 /* Read Register 2 (channel b only) - Interrupt vector */
+#define        CHB_Tx_EMPTY    0x00
+#define        CHB_EXT_STAT    0x02
+#define        CHB_Rx_AVAIL    0x04
+#define        CHB_SPECIAL     0x06
+#define        CHA_Tx_EMPTY    0x08
+#define        CHA_EXT_STAT    0x0a
+#define        CHA_Rx_AVAIL    0x0c
+#define        CHA_SPECIAL     0x0e
+#define        STATUS_MASK     0x06
 
 /* Read Register 3 (interrupt pending register) ch a only */
 #define        CHBEXT  0x1             /* Channel B Ext/Stat IP */
index 5220588d8ee3eab5f93020ebc278b8ce4314b5e5..19d5a73a1aa6a22839299707916cbe2574d0df88 100644 (file)
@@ -94,6 +94,12 @@ int media_bay_count = 0;
  */
 #define MB_IDE_WAIT    1500
 
+/*
+ * Wait at least this many ticks after resetting an IDE device before
+ * believing its ready bit.
+ */
+#define MB_IDE_MINWAIT 250
+
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
 static int media_bay_task(void *);
@@ -285,7 +291,10 @@ media_bay_task(void *x)
 #endif
                        }
 #ifdef CONFIG_BLK_DEV_IDE
-               } else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i))
+               } else if (bay->cd_timer
+                          && (--bay->cd_timer == 0
+                              || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
+                                  && MB_IDE_READY(i)))
                           && bay->cd_index < 0) {
                        bay->cd_timer = 0;
                        printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
@@ -299,11 +308,13 @@ media_bay_task(void *x)
                }
 
                bay->previous_id = bay->content_id;
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
-               if (signal_pending(current))
-                       return 0;
-               i = (i+1)%media_bay_count;
+               if (++i >= media_bay_count) {
+                       i = 0;
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       if (signal_pending(current))
+                               return 0;
+               }
        }
 }
 
@@ -405,25 +416,25 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                        feature_set(bay->dev_node, FEATURE_Mediabay_enable);
                        /* I suppose this is enough delay to stabilize MB_CONTENT ... */
                        mdelay(10);
-                       /* We re-enable the bay using it's previous content only if
-                          it did not change */
-                       if (MB_CONTENTS(i) == bay->content_id) {
-                               set_media_bay(i, bay->content_id);
-                               if (bay->content_id != MB_NO) {
-                                       mdelay(400);
-                                       /* Clear the bay reset */
-                                       feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-                                       /* This small delay makes sure the device has time
-                                          to assert the BUSY bit (used by IDE sleep) */
-                                       udelay(100);
-                                       /* We reset the state machine timers in case we were in the
-                                          middle of a wait loop */
-                                       if (bay->reset_timer)
-                                               bay->reset_timer = MB_RESET_COUNT;
-                                       if (bay->cd_timer)
-                                               bay->cd_timer = MB_IDE_WAIT;
-                               }
-                       }
+                       /* We re-enable the bay using it's previous content
+                          only if it did not change */
+                       if (MB_CONTENTS(i) != bay->content_id)
+                               continue;
+                       set_media_bay(i, bay->content_id);
+                       if (bay->content_id == MB_NO)
+                               continue;
+                       mdelay(400);
+                       /* Clear the bay reset */
+                       feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+                       /* This small delay makes sure the device has time
+                          to assert the BUSY bit (used by IDE sleep) */
+                       udelay(100);
+                       /* We reset the state machine timers in case we were
+                          in the middle of a wait loop */
+                       if (bay->reset_timer)
+                               bay->reset_timer = MB_RESET_COUNT;
+                       if (bay->cd_timer)
+                               bay->cd_timer = MB_IDE_WAIT;
                }
                break;
        }
index 61716407532aa5b13712587e25762583da38e19c..205bd758acb56bfa749b19db55835eaf3095129f 100644 (file)
@@ -165,7 +165,9 @@ if [ "$CONFIG_FDDI" = "y" ]; then
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  if [ "$CONFIG_INET" = "y" ]; then
+    bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  fi
   if [ "$CONFIG_HIPPI" = "y" ]; then
     tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
     if [ "$CONFIG_ROADRUNNER" != "n" ]; then
index 2d48479e0ca72e6adaec5cad5bc99dc67021cd29..fedeb277924e8f4288dad8b36586cf85f2f2e8cc 100644 (file)
@@ -1,11 +1,11 @@
 #include <linux/config.h>
 #include "arlan.h"
+#include <linux/sysctl.h>
+#include <linux/version.h>
 
 #ifdef CONFIG_PROC_FS
 
 
-#include <linux/sysctl.h>
-#include <linux/version.h>
 
 /* void enableReceive(struct device* dev);
 */
@@ -1001,6 +1001,11 @@ static ctl_table arlan_table[MAX_ARLANS + 1] =
        {0}
 };
 #endif
+#else
+static ctl_table arlan_table[MAX_ARLANS + 1] =
+{
+       {0}
+};
 #endif
 
 static int mmtu = 1234;
index 1809dadf2e7acd51c3c32d955266c1c102b9ace8..869c3710078bf93c8481e2f1ec08043b8e2fff39 100644 (file)
@@ -29,4 +29,4 @@ if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
   bool '   soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
 fi
 
-tristate 'YAM driver for AX.25' CONFIG_YAM
+dep_tristate 'YAM driver for AX.25' CONFIG_YAM $CONFIG_AX25
index 68e87ebd408b3c9cd412f09493f9c547fa17c0ff..ac64e375989073ac0c27dbb7261a693be19085f8 100644 (file)
@@ -13,7 +13,7 @@
  *     This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -39,16 +39,18 @@ static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <asm/spinlock.h>
 
 static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
 
 static int pcnet32_debug = 1;
+static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
 
 #ifdef MODULE
 static struct device *pcnet32_dev = NULL;
 #endif
 
-static const int max_interrupt_work = 20;
+static const int max_interrupt_work = 80;
 static const int rx_copybreak = 200;
 
 #define PORT_AUI      0x00
@@ -156,6 +158,12 @@ static int full_duplex[MAX_UNITS] = {0, };
  *        Michael Richard <mcr@solidum.com>)
  *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
+ * v1.24   Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
+ *         underflows.  Added tx_start_pt module parameter. Increased
+ *         TX_RING_SIZE from 16 to 32.  Added #ifdef'd code to use DXSUFLO
+ *         for FAST[+] chipsets. <kaf@fc.hp.com>
+ * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
+ * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
  */
 
 
@@ -166,7 +174,7 @@ static int full_duplex[MAX_UNITS] = {0, };
  */
 #ifndef PCNET32_LOG_TX_BUFFERS
 #define PCNET32_LOG_TX_BUFFERS 4
-#define PCNET32_LOG_RX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 5
 #endif
 
 #define TX_RING_SIZE                   (1 << (PCNET32_LOG_TX_BUFFERS))
@@ -255,12 +263,17 @@ struct pcnet32_private {
     struct sk_buff *rx_skbuff[RX_RING_SIZE];
     struct pcnet32_access a;
     void *origmem;
-    int cur_rx, cur_tx;                        /* The next free ring entry */
-    int dirty_rx, dirty_tx;                    /* The ring entries to be free()ed. */
+    spinlock_t lock;                           /* Guard lock */
+    unsigned int cur_rx, cur_tx;               /* The next free ring entry */
+    unsigned int dirty_rx, dirty_tx;           /* The ring entries to be free()ed. */
     struct net_device_stats stats;
     char tx_full;
     int  options;
     int  shared_irq:1,                      /* shared irq possible */
+        ltint:1,
+#ifdef DO_DXSUFLO
+        dxsuflo:1,                         /* disable transmit stop on uflo */
+#endif
          full_duplex:1,                     /* full duplex possible */
          mii:1;                             /* mii port available */
 #ifdef MODULE
@@ -299,6 +312,10 @@ static struct pcnet32_pci_id_info pcnet32_tbl[] = {
        PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
        PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
        pcnet32_probe1},
+    { "AMD PCnetPCI series (IBM)",
+       PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+       PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+       pcnet32_probe1},
     { "AMD PCnetHome series",
        PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
        PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
@@ -448,8 +465,8 @@ int __init pcnet32_probe (struct device *dev)
            int chip_idx;
            u16 sdid,svid;
 
-           pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
-           pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
+           pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+           pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
            for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
                if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
                    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
@@ -514,6 +531,10 @@ pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line,
 {
     struct pcnet32_private *lp;
     int i,media,fdx = 0, mii = 0;
+#ifdef DO_DXSUFLO
+    int dxsuflo = 0;
+#endif
+    int ltint = 0;
     int chip_version;
     char *chipname;
     char *priv;
@@ -532,12 +553,14 @@ pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line,
            return ENODEV;
     }
 
+
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
        printk("  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
        return ENODEV;
     chip_version = (chip_version >> 12) & 0xffff;
+
     switch (chip_version) {
      case 0x2420:
        chipname = "PCnet/PCI 79C970";
@@ -554,11 +577,33 @@ pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line,
        break;
      case 0x2623:
        chipname = "PCnet/FAST 79C971";
+       /* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+       /* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+       /* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+       /* Set CSR80:XMTSP, Tx start point = 20|64|128|248 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
        fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+       dxsuflo = 1;
+#endif
+       ltint = 1;
        break;
      case 0x2624:
        chipname = "PCnet/FAST+ 79C972";
+       /* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+       /* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+       /* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+       /* Set CSR80:XMTSP, Tx start point = 20|64|128|220 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
        fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+       dxsuflo = 1;
+#endif
+       ltint = 1;
        break;
      case 0x2625:
        chipname = "PCnet/FAST III 79C973";
@@ -602,6 +647,29 @@ pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line,
     for (i = 0; i < 6; i++)
       printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
+    if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
+        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+       printk("\n    tx_start_pt(0x%04x):",i);
+       switch(i>>10) {
+           case 0: printk("  20 bytes,"); break;
+           case 1: printk("  64 bytes,"); break;
+           case 2: printk(" 128 bytes,"); break;
+           case 3: printk("~220 bytes,"); break;
+       }
+        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+        printk(" BCR18(%x):",i&0xffff);
+       if (i & (1<<5)) printk("BurstWrEn ");
+       if (i & (1<<6)) printk("BurstRdEn ");
+       if (i & (1<<7)) printk("DWordIO ");
+       if (i & (1<<11)) printk("NoUFlow ");
+        i = a->read_bcr(ioaddr, 25);
+        printk("\n    SRAMSIZE=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 26);
+        printk(" SRAM_BND=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 27);
+       if (i & (1<<14)) printk("LowLatRx,");
+    }
+
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
@@ -615,10 +683,17 @@ pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line,
     lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
       
     memset(lp, 0, sizeof(*lp));
+    
+    spin_lock_init(&lp->lock);
+    
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->full_duplex = fdx;
+#ifdef DO_DXSUFLO
+    lp->dxsuflo = dxsuflo;
+#endif
+    lp->ltint = ltint;
     lp->mii = mii;
     if (options[card_idx] > sizeof (options_mapping))
        lp->options = PORT_ASEL;
@@ -746,7 +821,7 @@ pcnet32_open(struct device *dev)
        lp->a.write_bcr (ioaddr, 9, val);
     }
     
-    /* set/reset GPSI bit in test register */
+    /* NOOP ??? set/reset GPSI bit in test register */
     val = lp->a.read_csr (ioaddr, 124) & ~0x10;
     if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
        val |= 0x10;
@@ -760,6 +835,19 @@ pcnet32_open(struct device *dev)
            val |= 0x08;
        lp->a.write_bcr (ioaddr, 32, val);
     }
+
+#ifdef DO_DXSUFLO 
+    if (lp->dxsuflo) { /* Disable transmit stop on underflow */
+        val = lp->a.read_csr (ioaddr, 3);
+       val |= 0x40;
+        lp->a.write_csr (ioaddr, 3, val);
+    }
+#endif
+    if (lp->ltint) { /* Enable TxDone-intr inhibitor */
+        val = lp->a.read_csr (ioaddr, 5);
+       val |= (1<<14);
+        lp->a.write_csr (ioaddr, 5, val);
+    }
     
     lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
     lp->init_block.filter[0] = 0x00000000;
@@ -890,6 +978,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
 {
     struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
     unsigned int ioaddr = dev->base_addr;
+    u16 status;
     int entry;
     unsigned long flags;
 
@@ -937,8 +1026,23 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
        return 1;
     }
 
-    save_flags (flags);
-    cli ();
+    spin_lock_irqsave(&lp->lock, flags);
+
+    /* Default status -- will not enable Successful-TxDone
+     * interrupt when that option is available to us.
+     */
+    status = 0x8300;
+    if ((lp->ltint) &&
+       ((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) ||
+        (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2)))
+    {
+       /* Enable Successful-TxDone interrupt if we have
+        * 1/2 of, or nearly all of, our ring buffer Tx'd
+        * but not yet cleaned up.  Thus, most of the time,
+        * we will not enable Successful-TxDone interrupts.
+        */
+       status = 0x9300;
+    }
 
     /* Fill in a Tx ring entry */
 
@@ -954,7 +1058,8 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
 
     lp->tx_skbuff[entry] = skb;
     lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
-    lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+
+    lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
     lp->stats.tx_bytes += skb->len;
@@ -968,7 +1073,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
        clear_bit (0, (void *)&dev->tbusy);
     else
        lp->tx_full = 1;
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
     return 0;
 }
 
@@ -990,6 +1095,9 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 
     ioaddr = dev->base_addr;
     lp = (struct pcnet32_private *)dev->priv;
+
+    spin_lock(&lp->lock);
+
     if (dev->interrupt)
        printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
@@ -1010,7 +1118,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
            pcnet32_rx(dev);
 
        if (csr0 & 0x0200) {            /* Tx-done interrupt */
-           int dirty_tx = lp->dirty_tx;
+           unsigned int dirty_tx = lp->dirty_tx;
 
            while (dirty_tx < lp->cur_tx) {
                int entry = dirty_tx & TX_RING_MOD_MASK;
@@ -1028,14 +1136,27 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
                    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
                    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
                    if (err_status & 0x40000000) {
-                       /* Ackk!  On FIFO errors the Tx unit is turned off! */
                        lp->stats.tx_fifo_errors++;
+                       /* Ackk!  On FIFO errors the Tx unit is turned off! */
                        /* Remove this verbosity later! */
-                       printk("%s: Tx FIFO error! Status %4.4x.\n",
-                              dev->name, csr0);
+                       printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+                                           dev->name, csr0);
                        must_restart = 1;
                                        }
+#else
+                   if (err_status & 0x40000000) {
+                       lp->stats.tx_fifo_errors++;
+                       if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
+                           /* Ackk!  On FIFO errors the Tx unit is turned off! */
+                           /* Remove this verbosity later! */
+                           printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+                                               dev->name, csr0);
+                           must_restart = 1;
+                       }
+                   }
+#endif
                } else {
                    if (status & 0x1800)
                        lp->stats.collisions++;
@@ -1104,6 +1225,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
               dev->name, lp->a.read_csr (ioaddr, 0));
 
     dev->interrupt = 0;
+
+    spin_unlock(&lp->lock);
     return;
 }
 
@@ -1252,12 +1375,11 @@ pcnet32_get_stats(struct device *dev)
     u16 saved_addr;
     unsigned long flags;
 
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&lp->lock, flags);
     saved_addr = lp->a.read_rap(ioaddr);
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
     lp->a.write_rap(ioaddr, saved_addr);
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
 
     return &lp->stats;
 }
@@ -1371,18 +1493,22 @@ static int pcnet32_mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 MODULE_PARM(debug, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(tx_start_pt, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
                                             
 
 /* An additional parameter that may be passed in... */
 static int debug = -1;
+static int tx_start_pt = -1;
 
 int
 init_module(void)
 {
     if (debug > 0)
        pcnet32_debug = debug;
+    if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
+       tx_start = tx_start_pt;
     
     pcnet32_dev = NULL;
     return pcnet32_probe(NULL);
index 402da03e6b84da4460f152c7d18ba9d00c0bf16d..fa751547394ae72c717e5569bac54bbe3c357c9a 100644 (file)
@@ -1,58 +1,28 @@
-/*****************************************************************************/
-/*      sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux.              */
-/*                                                                           */
-/*                Silicon Integrated System Corporation                      */ 
-/*                Revision:    1.05    Aug 7 1999                           */
-/*                                                                           */
-/*****************************************************************************/
-
-/*                                                                            
-      Modified from the driver which is originally written by Donald Becker. 
-
-      This software may be used and distributed according to the terms
-      of the GNU Public License (GPL), incorporated herein by reference.
-      Drivers based on this skeleton fall under the GPL and must retain
-      the authorship (implicit copyright) notice.
-
-      The author may be reached as becker@tidalwave.net, or
-      Donald Becker
-      312 Severn Ave. #W302
-      Annapolis MD 21403
-
-      Support and updates [to the original skeleton] available at
-      http://www.tidalwave.net/~becker/pci-skeleton.html
+/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
+   Silicon Integrated System Corporation 
+   Revision:   1.05    Aug 7 1999
+   
+   Modified from the driver which is originally written by Donald Becker. 
+   
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+   Drivers based on this skeleton fall under the GPL and must retain
+   the authorship (implicit copyright) notice.
+   
+   References:
+   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+   preliminary Rev. 1.0 Jan. 14, 1998
+   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+   preliminary Rev. 1.0 Nov. 10, 1998
+   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+   preliminary Rev. 1.0 Jan. 18, 1998
+   http://www.sis.com.tw/support/databook.htm
+   
+   Ollie Lho (ollie@sis.com.tw) 
+   Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
+   Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release
 */
 
-static const char *version =
-"sis900.c:v1.05  8/07/99\n";
-
-static int max_interrupt_work = 20;
-#define sis900_debug debug
-static int sis900_debug = 0;
-
-static int multicast_filter_limit = 128;
-
-#define MAX_UNITS 8             /* More are supported, limit only on options */
-static int speeds[MAX_UNITS] = {100, 100, 100, 100, 100, 100, 100, 100};
-static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1};
-
-#define TX_BUF_SIZE     1536
-#define RX_BUF_SIZE     1536
-
-#define TX_DMA_BURST    0
-#define RX_DMA_BURST    0
-#define TX_FIFO_THRESH  16
-#define TxDRNT_100      (1536>>5)
-#define TxDRNT_10       16 
-#define RxDRNT_100      8
-#define RxDRNT_10       8 
-#define TRUE            1
-#define FALSE           0
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -70,293 +40,59 @@ static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1};
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
-
-#define RUN_AT(x) (jiffies + (x))
-
 #include <linux/delay.h>
 
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
+#include "sis900.h"
 
-/* The I/O extent. */
-#define SIS900_TOTAL_SIZE 0x100
+static const char *version =
+"sis900.c:v1.05  8/07/99\n";
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-   Note the matching code -- the first table entry matchs all 56** cards but
-   second only the 1234 card.
-*/
+static int max_interrupt_work = 20;
+#define sis900_debug debug
+static int sis900_debug = 0;
 
-enum pci_flags_bit {
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-};
+static int multicast_filter_limit = 128;
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
 
-struct pci_id_info {
+struct mac_chip_info {
         const char *name;
-        u16     vendor_id, device_id, device_id_mask, flags;
-        int io_size;
-        struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-                         long ioaddr, int irq, int chip_idx, int fnd_cnt);
+        u16    vendor_id, device_id, flags;
+        int    io_size;
+        struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, 
+                                struct device * net_dev);
 };
-
-static struct device * sis900_probe1(int pci_bus, int pci_devfn,
-                                  struct device *dev, long ioaddr,
-                                  int irq, int chp_idx, int fnd_cnt);
-
-static struct pci_id_info pci_tbl[] =
-{{ "SiS 900 PCI Fast Ethernet",
-   0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
-  { "SiS 7016 PCI Fast Ethernet",
-   0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
- {0,},                                          /* 0 terminated list. */
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
+                                        struct device * net_dev);
+
+static struct mac_chip_info  mac_chip_table[] = {
+       { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
+         PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+       { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
+         PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+       {0,},                                          /* 0 terminated list. */
 };
 
-/* The capability table matches the chip table above. */
-enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
-static int sis_cap_tbl[] = {
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
+static struct mii_chip_info {
+       const char * name;
+       u16 phy_id0;
+       u16 phy_id1;
+} mii_chip_table[] = {
+       {"SiS 900 Internal MII PHY", 0x001d, 0x8000},
+       {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830},
+       {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9},
+       {"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8},
+       {0,},
 };
 
-/* The rest of these values should never change. */
-#define NUM_TX_DESC     16      /* Number of Tx descriptor registers. */
-#define NUM_RX_DESC     8       /* Number of Rx descriptor registers. */
-
-/* Symbolic offsets to registers. */
-enum SIS900_registers {
-        cr=0x0,                 //Command Register
-        cfg=0x4,                //Configuration Register
-        mear=0x8,               //EEPROM Access Register
-        ptscr=0xc,              //PCI Test Control Register
-        isr=0x10,               //Interrupt Status Register
-        imr=0x14,               //Interrupt Mask Register
-        ier=0x18,               //Interrupt Enable Register
-        epar=0x18,              //Enhanced PHY Access Register
-        txdp=0x20,              //Transmit Descriptor Pointer Register
-        txcfg=0x24,             //Transmit Configuration Register
-        rxdp=0x30,              //Receive Descriptor Pointer Register
-        rxcfg=0x34,             //Receive Configuration Register
-        flctrl=0x38,            //Flow Control Register
-        rxlen=0x3c,             //Receive Packet Length Register
-        rfcr=0x48,              //Receive Filter Control Register
-        rfdr=0x4C,              //Receive Filter Data Register
-        pmctrl=0xB0,            //Power Management Control Register
-        pmer=0xB4               //Power Management Wake-up Event Register
+struct mii_phy {
+       struct mii_phy * next;
+       struct mii_chip_info * chip_info;
+       int phy_addr;
+       u16 status;
 };
 
-#define RESET           0x00000100
-#define SWI             0x00000080
-#define RxRESET         0x00000020
-#define TxRESET         0x00000010
-#define RxDIS           0x00000008
-#define RxENA           0x00000004
-#define TxDIS           0x00000002
-#define TxENA           0x00000001
-
-#define BISE            0x80000000
-#define EUPHCOM         0x00000100
-#define REQALG          0x00000080
-#define SB              0x00000040
-#define POW             0x00000020
-#define EXD             0x00000010
-#define PESEL           0x00000008
-#define LPM             0x00000004
-#define BEM             0x00000001
-
-/* Interrupt register bits, using my own meaningful names. */
-#define WKEVT           0x10000000
-#define TxPAUSEEND      0x08000000
-#define TxPAUSE         0x04000000
-#define TxRCMP          0x02000000
-#define RxRCMP          0x01000000
-#define DPERR           0x00800000
-#define SSERR           0x00400000
-#define RMABT           0x00200000
-#define RTABT           0x00100000
-#define RxSOVR          0x00010000
-#define HIBERR          0x00008000
-#define SWINT           0x00001000
-#define MIBINT          0x00000800
-#define TxURN           0x00000400
-#define TxIDLE          0x00000200
-#define TxERR           0x00000100
-#define TxDESC          0x00000080
-#define TxOK            0x00000040
-#define RxORN           0x00000020
-#define RxIDLE          0x00000010
-#define RxEARLY         0x00000008
-#define RxERR           0x00000004
-#define RxDESC          0x00000002
-#define RxOK            0x00000001
-
-#define IE              0x00000001
-
-#define TxCSI           0x80000000
-#define TxHBI           0x40000000
-#define TxMLB           0x20000000
-#define TxATP           0x10000000
-#define TxIFG           0x0C000000
-#define TxMXF           0x03800000
-#define TxMXF_shift     0x23
-#define TxMXDMA         0x00700000
-#define TxMXDMA_shift   20
-#define TxRTCNT         0x000F0000
-#define TxRTCNT_shift   16
-#define TxFILLT         0x00007F00
-#define TxFILLT_shift   8
-#define TxDRNT          0x0000007F
-
-#define RxAEP           0x80000000
-#define RxARP           0x40000000
-#define RxATP           0x10000000
-#define RxAJAB          0x08000000
-#define RxMXF           0x03800000
-#define RxMXF_shift     23
-#define RxMXDMA         0x00700000
-#define RxMXDMA_shift   20
-#define RxDRNT          0x0000007F
-
-#define RFEN            0x80000000
-#define RFAAB           0x40000000
-#define RFAAM           0x20000000
-#define RFAAP           0x10000000
-#define RFPromiscuous   (RFAAB|RFAAM|RFAAP)
-#define RFAA_shift      28
-#define RFEP            0x00070000
-#define RFEP_shift      16
-
-#define RFDAT           0x0000FFFF
-
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-
-#define SUPCRC          0x10000000
-#define ABORT           0x04000000
-#define UNDERRUN        0x02000000
-#define NOCARRIER       0x01000000
-#define DEFERD          0x00800000
-#define EXCDEFER        0x00400000
-#define OWCOLL          0x00200000
-#define EXCCOLL         0x00100000
-#define COLCNT          0x000F0000
-
-#define INCCRC          0x10000000
-//      ABORT           0x04000000
-#define OVERRUN         0x02000000
-#define DEST            0x01800000
-#define BCAST           0x01800000
-#define MCAST           0x01000000
-#define UNIMATCH        0x00800000
-#define TOOLONG         0x00400000
-#define RUNT            0x00200000
-#define RXISERR         0x00100000
-#define CRCERR          0x00080000
-#define FAERR           0x00040000
-#define LOOPBK          0x00020000
-#define RXCOL           0x00010000
-
-#define EuphLiteEEMACAddr               0x08
-#define EuphLiteEEVendorID              0x02
-#define EuphLiteEEDeviceID              0x03
-#define EuphLiteEECardTypeRev           0x0b
-#define EuphLiteEEPlexusRev             0x0c
-#define EuphLiteEEChecksum              0x0f
-
-#define RXSTS_shift     18
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII NWAY Register Bits ...
-** valid for the ANAR (Auto-Negotiation Advertisement) and
-** ANLPAR (Auto-Negotiation Link Partner) registers */
-#define MII_NWAY_NODE_SEL       0x001f
-#define MII_NWAY_CSMA_CD        0x0001
-#define MII_NWAY_T              0x0020
-#define MII_NWAY_T_FDX          0x0040
-#define MII_NWAY_TX             0x0080
-#define MII_NWAY_TX_FDX         0x0100
-#define MII_NWAY_T4             0x0200
-#define MII_NWAY_RF             0x2000
-#define MII_NWAY_ACK            0x4000
-#define MII_NWAY_NP             0x8000
-
-/* MII Auto-Negotiation Expansion Register Bits */
-#define MII_ANER_PDF            0x0010
-#define MII_ANER_LP_NP_ABLE     0x0008
-#define MII_ANER_NP_ABLE        0x0004
-#define MII_ANER_RX_PAGE        0x0002
-#define MII_ANER_LP_AN_ABLE     0x0001
-#define HALF_DUPLEX                     1
-#define FDX_CAPABLE_DUPLEX_UNKNOWN      2
-#define FDX_CAPABLE_HALF_SELECTED       3
-#define FDX_CAPABLE_FULL_SELECTED       4
-#define HW_SPEED_UNCONFIG       0
-#define HW_SPEED_10_MBPS        10
-#define HW_SPEED_100_MBPS       100
-#define HW_SPEED_DEFAULT        (HW_SPEED_10_MBPS)
-
-#define ACCEPT_ALL_PHYS         0x01
-#define ACCEPT_ALL_MCASTS       0x02
-#define ACCEPT_ALL_BCASTS       0x04
-#define ACCEPT_ALL_ERRORS       0x08
-#define ACCEPT_CAM_QUALIFIED    0x10
-#define MAC_LOOPBACK            0x20
-//#define FDX_CAPABLE_FULL_SELECTED     4
-#define CRC_SIZE                4
-#define MAC_HEADER_SIZE         14
-
 typedef struct _EuphLiteDesc {
         u32     llink;
         unsigned char*  buf;
@@ -368,19 +104,15 @@ typedef struct _EuphLiteDesc {
 } EuphLiteDesc;
 
 struct sis900_private {
-        char devname[8];                /* Used only for kernel debugging. */
-        const char *product_name;
         struct device *next_module;
-        int chip_id;
-        int chip_revision;
-        unsigned char pci_bus, pci_devfn;
-#if LINUX_VERSION_CODE > 0x20139
         struct net_device_stats stats;
-#else
-        struct enet_statistics stats;
-#endif
-        struct timer_list timer;        /* Media selection timer. */
-        unsigned int cur_rx;    /* Index into the Rx buffer of next Rx pkt. */
+       struct pci_dev * pci_dev;
+
+       struct mac_chip_info * mac;
+       struct mii_phy * mii;
+
+        struct timer_list timer;                       /* Media selection timer. */
+        unsigned int cur_rx;                   /* Index into the Rx buffer of next Rx pkt. */
         unsigned int cur_tx, dirty_tx, tx_flag;
 
         /* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -388,15 +120,12 @@ struct sis900_private {
         EuphLiteDesc tx_buf[NUM_TX_DESC];       /* Tx bounce buffers */
         EuphLiteDesc rx_buf[NUM_RX_DESC];
         unsigned char *rx_bufs;
-        unsigned char *tx_bufs;                 /* Tx bounce buffer region. */
-        char phys[4];                           /* MII device addresses.    */
-        int phy_idx;                            /* Support Max 4 PHY        */
-        u16 pmd_status;
-        unsigned int tx_full;                   /* The Tx queue is full.    */
-       int MediaSpeed;                         /* user force speed         */
-       int MediaDuplex;                        /* user force duplex        */
-        int full_duplex;                        /* Full/Half-duplex.        */
-        int speeds;                             /* 100/10 Mbps.             */
+       unsigned char *tx_bufs;                         /* Tx bounce buffer region. */
+        unsigned int tx_full;                  /* The Tx queue is full.    */
+       int MediaSpeed;                                 /* user force speed         */
+       int MediaDuplex;                                /* user force duplex        */
+        int full_duplex;                               /* Full/Half-duplex.        */
+        int speeds;                                    /* 100/10 Mbps.             */
         u16 LinkOn;
         u16 LinkChange;
 };
@@ -414,8 +143,10 @@ MODULE_PARM(debug, "i");
 #endif
 
 static int sis900_open(struct device *dev);
+static int sis900_mii_probe (struct device * dev);
+static void sis900_init_rxfilter (struct device * dev);
 static u16 read_eeprom(long ioaddr, int location);
-static int mdio_read(struct device *dev, int phy_id, int location);
+static u16 mdio_read(struct device *dev, int phy_id, int location);
 static void mdio_write(struct device *dev, int phy_id, int location, int val);
 static void sis900_timer(unsigned long data);
 static void sis900_tx_timeout(struct device *dev);
@@ -431,314 +162,199 @@ static void sis900_reset(struct device *dev);
 static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed);
 static void elSetCapability(struct device *dev, int phy_id, int duplex, int speed);
 static u16 elPMDreadMode(struct device *dev, int phy_id, int *speed, int *duplex);
-static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value);
+static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, 
+                                       u16 polarity, u16 *value);
 static void elSetMediaType(struct device *dev, int speed, int duplex);
 
 /* A list of all installed SiS900 devices, for removing the driver module. */
 static struct device *root_sis900_dev = NULL;
 
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   SiS 900 cards in slot order. */
-
-int sis900_probe(struct device *dev)
+/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
+int sis900_probe (struct device * net_dev)
 {
-        int cards_found = 0;
-        int pci_index = 0;
-        unsigned char pci_bus, pci_device_fn;
-
-        if ( ! pcibios_present())
-                return -ENODEV;
-
-        for (;pci_index < 0xff; pci_index++) {
-                u16 vendor, device, pci_command, new_command;
-                int chip_idx, irq;
-                long ioaddr;
-
-                if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-                                                pci_index,
-                                                &pci_bus, &pci_device_fn)
-                                != PCIBIOS_SUCCESSFUL) {
-                        break;
-                }
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID,
-                                                        &vendor);
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID,
-                                                        &device);
-
-                for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-                        if (vendor == pci_tbl[chip_idx].vendor_id &&
-                                (device & pci_tbl[chip_idx].device_id_mask) ==
-                                pci_tbl[chip_idx].device_id)
-                                break;
-                if (pci_tbl[chip_idx].vendor_id == 0)   /* Compiled out! */
-                        continue;
-
-        {
-#if defined(PCI_SUPPORT_VER2)
-                struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-                ioaddr = pdev->base_address[0] & ~3;
-                irq = pdev->irq;
-#else
-                u32 pci_ioaddr;
-                u8 pci_irq_line;
-                pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                         PCI_INTERRUPT_LINE, &pci_irq_line);
-                pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
-                ioaddr = pci_ioaddr & ~3;
-                irq = pci_irq_line;
-#endif
-        }
-
-                if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
-                        check_region(ioaddr, pci_tbl[chip_idx].io_size))
-                        continue;
-
-                /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-                pcibios_read_config_word(pci_bus, pci_device_fn,
-                                         PCI_COMMAND, &pci_command);
-                new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-                if (pci_command != new_command) {
-                        printk(KERN_INFO "  The PCI BIOS has not enabled the"
-                                   " device at %d/%d!"
-                                   "Updating PCI command %4.4x->%4.4x.\n",
-                                        pci_bus, pci_device_fn,
-                                        pci_command, new_command);
-
-                        pcibios_write_config_word(pci_bus, pci_device_fn,
-                                                  PCI_COMMAND, new_command);
-                }
-
-                dev = pci_tbl[chip_idx].probe1(pci_bus,
-                                                pci_device_fn,
-                                                dev,
-                                                ioaddr,
-                                                irq,
-                                                chip_idx,
-                                                cards_found);
-
-                if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-                        u8 pci_latency;
-
-                        pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                        PCI_LATENCY_TIMER, &pci_latency);
-
-                        if (pci_latency < 32) {
-                           printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
-                           "unreasonably low at %d.  Setting to 64 clocks.\n",
-                                           pci_latency);
-                           pcibios_write_config_byte(pci_bus, pci_device_fn,
-                                          PCI_LATENCY_TIMER, 64);
-                        }
-                }
-                dev = 0;
-                cards_found++;
-        }
-        return cards_found ? 0 : -ENODEV;
+       int found = 0;
+       struct pci_dev * pci_dev = NULL;
+               
+       if (!pci_present())
+               return -ENODEV;
+               
+       while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) {
+               /* pci_dev contains all ethernet devices */
+               u32 pci_io_base;
+               struct mac_chip_info * mac;
+
+               for (mac = mac_chip_table; mac->vendor_id; mac++) {
+                       /* try to match our card list */
+                       if (pci_dev->vendor == mac->vendor_id &&
+                           pci_dev->device == mac->device_id)
+                               break;
+               }
+               
+               if (mac->vendor_id == 0)
+                       /* pci_dev does not match any of our cards */
+                       continue;
+               
+               /* now, pci_dev should be either 900 or 7016 */
+               pci_io_base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+               if ((mac->flags & PCI_COMMAND_IO ) && 
+                   check_region(pci_io_base, mac->io_size))
+                       continue;
+               
+               /* setup various bits in PCI command register */
+               pci_set_master(pci_dev);
+
+               /* do the real low level jobs */
+               net_dev = mac->probe(mac, pci_dev, net_dev);
+               
+               if (net_dev != NULL) {
+                       found++;
+               }
+               net_dev = NULL;
+       }
+       return found ? 0 : -ENODEV;
 }
 
-static struct device * sis900_probe1(   int pci_bus,
-                                        int pci_devfn,
-                                        struct device *dev,
-                                        long ioaddr,
-                                        int irq,
-                                        int chip_idx,
-                                        int found_cnt)
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, 
+                                        struct device * net_dev)
 {
-        static int did_version = 0;     /* Already printed version info. */
-        struct sis900_private *tp;
-       u16    status;
-        int    duplex = found_cnt < MAX_UNITS ? full_duplex[found_cnt] : 0 ;
-        int    speed  = found_cnt < MAX_UNITS ? speeds[found_cnt] : 0 ;
-        int    phy=0, phy_idx=0, i;
-
-        if (did_version++ == 0)
-                printk(KERN_INFO "%s", version);
-
-        dev = init_etherdev(dev, 0);
-        
-        if(dev==NULL)
-               return NULL;
-
-        printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-                   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
-        if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) {
-                for (i = 0; i < 3; i++)
-                        ((u16 *)(dev->dev_addr))[i] =
-                                        read_eeprom(ioaddr,i+EuphLiteEEMACAddr);
-                for (i = 0; i < 5; i++)
-                        printk("%2.2x:", (u8)dev->dev_addr[i]);
-                printk("%2.2x.\n", dev->dev_addr[i]);
-        } else
-                printk(KERN_INFO "Error EEPROM read\n");
-
-        /* We do a request_region() to register /proc/ioports info. */
-        request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
-        dev->base_addr = ioaddr;
-        dev->irq = irq;
-
-        /* Some data structures must be quadword aligned. */
-        tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-        if(tp==NULL)
-        {
-               release_region(ioaddr, pci_tbl[chip_idx].io_size);
-               return NULL;
-        }
-        memset(tp, 0, sizeof(*tp));
-        dev->priv = tp;
-
-        tp->next_module = root_sis900_dev;
-        root_sis900_dev = dev;
-
-        tp->chip_id = chip_idx;
-        tp->pci_bus = pci_bus;
-        tp->pci_devfn = pci_devfn;
-
-        /* Find the connected MII xcvrs.
-           Doing this in open() would allow detecting external xcvrs later, but
-           takes too much time. */
-        if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) {
-                for (phy = 0, phy_idx = 0;
-                        phy < 32 && phy_idx < sizeof(tp->phys); phy++)
-                {
-                        int mii_status ;
-                       mii_status = mdio_read(dev, phy, MII_STATUS);
-
-                        if (mii_status != 0xffff && mii_status != 0x0000) {
-                                tp->phy_idx = phy_idx;
-                                tp->phys[phy_idx++] = phy;
-                                tp->pmd_status=mdio_read(dev, phy, MII_STATUS);
-                                printk(KERN_INFO "%s: MII transceiver found "
-                                                 "at address %d.\n",
-                                                 dev->name, phy);
-                                break;
-                        }
-                }
+       struct sis900_private *sis_priv;
+       long ioaddr = pci_dev->base_address[0] & ~3;
+       int irq = pci_dev->irq;
+       static int did_version = 0;
+       u16 signature;
+       int i;
+
+       if (did_version++ == 0)
+               printk(KERN_INFO "%s", version);
+
+       /* check to see if  we have sane EEPROM */
+       signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
+       if (signature == 0xffff || signature == 0x0000) {
+               printk (KERN_INFO "Error EERPOM read %x\n", signature);
+               return NULL;
+       }
 
-                if (phy_idx == 0) {
-                        printk(KERN_INFO "%s: No MII transceivers found!\n",
-                                        dev->name);
-                        tp->phys[0] = -1;
-                       tp->pmd_status = 0;
-                }
-        } else {
-                        tp->phys[0] = -1;
-                       tp->pmd_status = 0;
-        }
+       if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
+               return NULL;
+
+       printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
+              ioaddr, irq);
+
+       /* get MAC address from EEPROM */
+       for (i = 0; i < 3; i++)
+               ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+       for (i = 0; i < 5; i++)
+               printk("%2.2x:", (u8)net_dev->dev_addr[i]);
+       printk("%2.2x.\n", net_dev->dev_addr[i]);
+
+       if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL)
+           /* FIXME: possible mem leak here */
+           return NULL;
+
+       sis_priv = net_dev->priv;
+       memset(sis_priv, 0, sizeof(struct sis900_private));
+
+       /* We do a request_region() to register /proc/ioports info. */
+       request_region(ioaddr, mac->io_size, net_dev->name);
+       net_dev->base_addr = ioaddr;
+       net_dev->irq = irq;
+       sis_priv->pci_dev = pci_dev;
+       sis_priv->mac = mac;
+
+       /* probe for mii transciver */
+       if (sis900_mii_probe(net_dev) == 0) {
+               /* FIXME: how to clean up this */
+               release_region (ioaddr, mac->io_size);
+               return NULL;
+       }
 
-        if ((tp->pmd_status > 0) && (phy_idx > 0)) {
-               if (sis900_debug > 1) {
-                       printk(KERN_INFO "duplex=%d, speed=%d\n",
-                                               duplex, speed);
-               }
-               if (!duplex && !speed) {  
-                       // auto-config media type
-                       // Set full capability
-                       if (sis900_debug > 1) {
-                               printk(KERN_INFO "Auto Config ...\n");
-                       }
-                       elSetCapability(dev, tp->phys[tp->phy_idx], 1, 100);
-                       tp->pmd_status=elAutoNegotiate(dev,
-                                                              tp->phys[tp->phy_idx],
-                                                      &tp->full_duplex,
-                                                      &tp->speeds);
-               } else {
-                       tp->MediaSpeed = speed;
-                       tp->MediaDuplex = duplex;
-                       elSetCapability(dev, tp->phys[tp->phy_idx],
-                                       duplex, speed);
-                       elAutoNegotiate(dev, tp->phys[tp->phy_idx],
-                                       &tp->full_duplex,
-                                       &tp->speeds);
-                       status = mdio_read(dev, phy, MII_ANLPAR);
-                       if ( !(status & (MII_NWAY_T  | MII_NWAY_T_FDX |
-                                        MII_NWAY_TX | MII_NWAY_TX_FDX )))
-                       {
-                               u16 cmd=0;
-                               cmd |= ( speed == 100 ?
-                                        MIICNTL_SPEED : 0 );
-                               cmd |= ( duplex ? MIICNTL_FDX : 0 );
-                               mdio_write(dev, phy, MII_CONTROL, cmd);
-                               elSetMediaType(dev, speed==100 ? 
-                                                   HW_SPEED_100_MBPS :
-                                                   HW_SPEED_10_MBPS,
-                                                   duplex ?
-                                                   FDX_CAPABLE_FULL_SELECTED:
-                                                   FDX_CAPABLE_HALF_SELECTED);
-                               elMIIpollBit(dev, phy, MII_STATUS,
-                                               MIISTAT_LINK, TRUE, &status);
-                       } else {
-                               status = mdio_read(dev, phy, MII_STATUS);
-                       }
-               }
+       sis_priv->next_module = root_sis900_dev;
+       root_sis900_dev = net_dev;
 
-                if (tp->pmd_status & MIISTAT_LINK) 
-                               tp->LinkOn = TRUE;
-               else
-                        tp->LinkOn = FALSE;
+       /* The SiS900-specific entries in the device structure. */
+       net_dev->open = &sis900_open;
+       net_dev->hard_start_xmit = &sis900_start_xmit;
+       net_dev->stop = &sis900_close;
+       net_dev->get_stats = &sis900_get_stats;
+       net_dev->set_multicast_list = &set_rx_mode;
+       net_dev->do_ioctl = &mii_ioctl;
 
-               tp->LinkChange = FALSE;
-       
-        }
+       return net_dev;
+}
 
-       if (sis900_debug > 1) {
-               if (tp->full_duplex == FDX_CAPABLE_FULL_SELECTED) {
-                       printk(KERN_INFO "%s: Media type is Full Duplex.\n",
-                                               dev->name);
-               } else {
-                       printk(KERN_INFO "%s: Media type is Half Duplex.\n",
-                                               dev->name);
-               }
-               if (tp->speeds == HW_SPEED_100_MBPS) {
-                       printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name);
-               } else {
-                       printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name);
-               }
+static int sis900_mii_probe (struct device * net_dev)
+{
+       struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv;
+       int phy_addr;
+       
+       sis_priv->mii = NULL;
+       
+       /* search for total of 32 possible mii phy address */
+       for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+               u16 mii_status;
+               u16 phy_id0, phy_id1;
+               int i;
+               
+               mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
+               if (mii_status == 0xffff || mii_status == 0x0000)
+                       /* the mii is not accessable, try next one */
+                       continue;
+               
+               phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
+               phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
+               
+               /* search our mii table for the current mii */ 
+               for (i = 0; mii_chip_table[i].phy_id1; i++)
+                       if (phy_id0 == mii_chip_table[i].phy_id0) {
+                               struct mii_phy * mii_phy;
+                               
+                               printk(KERN_INFO 
+                                      "%s: %s transceiver found at address %d.\n",
+                                      net_dev->name, mii_chip_table[i].name, 
+                                      phy_addr);;
+                               if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) {
+                                       mii_phy->chip_info = mii_chip_table+i;
+                                       mii_phy->phy_addr = phy_addr;
+                                       mii_phy->status = mdio_read(net_dev, phy_addr, 
+                                                                   MII_STATUS);
+                                       mii_phy->next = sis_priv->mii;
+                                       sis_priv->mii = mii_phy;
+                               }
+                               /* the current mii is on our mii_info_table, quit searching (table) */
+                               break;
+                       }
+       }
+       
+       if (sis_priv->mii == NULL) {
+               printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name);
+               return 0;
        }
 
-        /* The SiS900-specific entries in the device structure. */
-        dev->open = &sis900_open;
-        dev->hard_start_xmit = &sis900_start_xmit;
-        dev->stop = &sis900_close;
-        dev->get_stats = &sis900_get_stats;
-        dev->set_multicast_list = &set_rx_mode;
-        dev->do_ioctl = &mii_ioctl;
-
-        return dev;
+       /* FIXME: AMD stuff should be added */
+       /* auto negotiate FIXME: not completed */
+       elSetCapability(net_dev, sis_priv->mii->phy_addr, 1, 100);
+       sis_priv->mii->status = elAutoNegotiate(net_dev, sis_priv->mii->phy_addr,
+                                               &sis_priv->full_duplex, 
+                                               &sis_priv->speeds);
+       
+       if (sis_priv->mii->status & MIISTAT_LINK) 
+               sis_priv->LinkOn = TRUE;
+       else
+               sis_priv->LinkOn = FALSE;
+       
+       sis_priv->LinkChange = FALSE;
+       
+       return 1;
 }
 
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EECLK           0x00000004      /* EEPROM shift clock. */
-#define EECS            0x00000008      /* EEPROM chip select. */
-#define EEDO            0x00000002      /* EEPROM chip data out. */
-#define EEDI            0x00000001      /* EEPROM chip data in. */
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
+/* Delay between EEPROM clock transitions. */
 #define eeprom_delay()  inl(ee_addr)
 
-/* The EEPROM commands include the alway-set leading bit. */
-#define EEread          0x0180
-#define EEwrite         0x0140
-#define EEerase         0x01C0
-#define EEwriteEnable   0x0130
-#define EEwriteDisable  0x0100
-#define EEeraseAll      0x0120
-#define EEwriteAll      0x0110
-#define EEaddrMask      0x013F
-#define EEcmdShift      16
-
+/* Read Serial EEPROM through EEPROM Access Register, Note that location is 
+   in word (16 bits) unit */
 static u16 read_eeprom(long ioaddr, int location)
 {
-        int i;
+       int i;
         u16 retval = 0;
         long ee_addr = ioaddr + mear;
         u32 read_cmd = location | EEread;
@@ -748,7 +364,7 @@ static u16 read_eeprom(long ioaddr, int location)
         outl(EECLK, ee_addr);
         eeprom_delay();
 
-        /* Shift the read command bits out. */
+        /* Shift the read command (9) bits out. */
         for (i = 8; i >= 0; i--) {
                 u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
                 outl(dataval, ee_addr);
@@ -759,6 +375,7 @@ static u16 read_eeprom(long ioaddr, int location)
         outb(EECS, ee_addr);
         eeprom_delay();
 
+       /* read the 16-bits data in */
         for (i = 16; i > 0; i--) {
                 outl(EECS, ee_addr);
                 eeprom_delay();
@@ -767,39 +384,21 @@ static u16 read_eeprom(long ioaddr, int location)
                 retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
                 eeprom_delay();
         }
-
+               
         /* Terminate the EEPROM access. */
         outl(0, ee_addr);
         eeprom_delay();
         outl(EECLK, ee_addr);
+
         return (retval);
 }
 
-/* MII serial management: mostly bogus for now. */
 /* Read and write the MII management registers using software-generated
-   serial MDIO protocol.
-   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
+   serial MDIO protocol. Note that the command bits and data bits are
+   send out seperately */
 
 #define mdio_delay()    inl(mdio_addr)
 
-#define MIIread         0x6000
-#define MIIwrite        0x6002
-#define MIIpmdMask      0x0F80
-#define MIIpmdShift     7
-#define MIIregMask      0x007C
-#define MIIregShift     2
-#define MIIturnaroundBits       2
-#define MIIcmdLen       16
-#define MIIcmdShift     16
-#define MIIreset        0xFFFFFFFF
-#define MIIwrLen        32
-
-#define MDC             0x00000040
-#define MDDIR           0x00000020
-#define MDIO            0x00000010
-
 static void mdio_idle(long mdio_addr)
 {
         outl(MDIO | MDDIR, mdio_addr);
@@ -821,11 +420,11 @@ static void mdio_reset(long mdio_addr)
         return;
 }
 
-static int mdio_read(struct device *dev, int phy_id, int location)
+static u16 mdio_read(struct device *dev, int phy_id, int location)
 {
         long mdio_addr = dev->base_addr + mear;
         int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
-        int retval = 0;
+        u16 retval = 0;
         int i;
 
         mdio_reset(mdio_addr);
@@ -834,13 +433,15 @@ static int mdio_read(struct device *dev, int phy_id, int location)
         for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outl(dataval, mdio_addr);
+               mdio_delay();
                 outl(dataval | MDC, mdio_addr);
+               mdio_delay();
         }
 
-        /* Read the two transition, 16 data, and wire-idle bits. */
+        /* Read the 16 data bits. */
         for (i = 16; i > 0; i--) {
                 outl(0, mdio_addr);
-                //mdio_delay();
+                mdio_delay();
                 retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
                 outl(MDC, mdio_addr);
                 mdio_delay();
@@ -858,7 +459,7 @@ static void mdio_write(struct device *dev, int phy_id, int location, int value)
         mdio_idle(mdio_addr);
 
         /* Shift the command bits out. */
-        for (i = 31; i >= 0; i--) {
+        for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outb(dataval, mdio_addr);
                 mdio_delay();
@@ -866,6 +467,17 @@ static void mdio_write(struct device *dev, int phy_id, int location, int value)
                 mdio_delay();
         }
         mdio_delay();
+
+       /* Shift the value bits out. */
+       for (i = 15; i >= 0; i--) {
+               int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
+               outl(dataval, mdio_addr);
+               mdio_delay();
+               outl(dataval | MDC, mdio_addr);
+               mdio_delay();
+       }
+       mdio_delay();
+       
         /* Clear out extra bits. */
         for (i = 2; i > 0; i--) {
                 outb(0, mdio_addr);
@@ -879,110 +491,62 @@ static void mdio_write(struct device *dev, int phy_id, int location, int value)
 static int
 sis900_open(struct device *dev)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        struct sis900_private *sis_priv = (struct sis900_private *)dev->priv;
         long ioaddr = dev->base_addr;
-
-        if (sis900_debug > 0)
-                printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n",
-                                dev->name, (unsigned int)ioaddr, dev->irq);
+       int i = 0;
+       u32 status = TxRCMP | RxRCMP;
 
         /* Soft reset the chip. */
-        outl(0, ioaddr + imr);
-        outl(0, ioaddr + ier);
-        outl(0, ioaddr + rfcr);
-        outl(RESET | RxRESET | TxRESET, ioaddr + cr);
+       sis900_reset(dev);
 
-        if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev))
-        {
+        if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev)) {
                 return -EAGAIN;
         }
 
         MOD_INC_USE_COUNT;      
 
-        tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
-        tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
-        if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) {
-                if (tp->tx_bufs)
-                        kfree(tp->tx_bufs);
-                if (tp->rx_bufs)
-                        kfree(tp->rx_bufs);
-               if (!tp->tx_bufs) {
-                     printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n",
-                                   dev->name, TX_BUF_SIZE * NUM_TX_DESC);
-               }
-               if (!tp->rx_bufs) {
-                     printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n",
-                                   dev->name, RX_BUF_SIZE * NUM_RX_DESC);
-               }
-                return -ENOMEM;
-        }
+        if ((sis_priv->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n",
+                      dev->name, TX_BUF_SIZE * NUM_TX_DESC);
+               return -ENOMEM;
+       }
+       if ((sis_priv->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL)) == NULL) {
+               kfree (sis_priv->tx_buf);
+               printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n",
+                      dev->name, RX_BUF_SIZE * NUM_RX_DESC);
+               return -ENOMEM;
+       }
 
-        {
-                u32 rfcrSave;
-                u32 w;
-                u32 i;
-
-                rfcrSave = inl(rfcr);
-                outl(rfcrSave & ~RFEN, rfcr);
-                for (i=0 ; i<3 ; i++) {
-                        w = (u16)*((u16*)(dev->dev_addr)+i);
-                        outl((((u32) i) << RFEP_shift), ioaddr + rfcr);
-                        outl((u32)w, ioaddr + rfdr);
-                        if (sis900_debug > 4) {
-                                printk(KERN_INFO "Filter Addr[%d]=%x\n",
-                                        i, inl(ioaddr + rfdr));
-                        }
-                }
-                outl(rfcrSave, rfcr);
-        }
+       sis900_init_rxfilter(dev);
 
-        sis900_init_ring(dev);
-        outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp);
-        outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp);
+       sis900_reset_tx_ring(dev);
+       sis900_reset_rx_ring(dev);
 
         if (sis900_debug > 4)
-                printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp));
-
-        /* Check that the chip has finished the reset. */
-        {
-                u32 status;
-                int j=0;
-                status = TxRCMP | RxRCMP;
-                while (status && (j++ < 30000)) {
-                        status ^= (inl(isr) & status);
-                }
+                printk(KERN_INFO "%s: txdp:%8.8x\n", dev->name, inl(ioaddr + txdp));
+
+       /* Check that the chip has finished the reset. */
+       while (status && (i++ < 30000)) {
+               status ^= (inl(isr + ioaddr) & status);
         }
 
         outl(PESEL, ioaddr + cfg);
 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-         *      #define TX_DMA_BURST    0
-         *      #define RX_DMA_BURST    0
-         *      #define TX_FIFO_THRESH  16
-         *      #define TxDRNT_100      (1536>>5)
-         *      #define TxDRNT_10       (1536>>5)
-         *      #define RxDRNT_100      (1536>>5)
-         *      #define RxDRNT_10       (1536>>5)
-         */
-        outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg);
-        outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10,
-                                                ioaddr + txcfg);
-        if (sis900_debug > 1)
-        {
-               if (tp->LinkOn) {
-                       printk(KERN_INFO"%s: Media Type %s%s-duplex.\n",
-                                dev->name,
-                                tp->speeds==HW_SPEED_100_MBPS ?
-                                       "100mbps " : "10mbps ",
-                                tp->full_duplex== FDX_CAPABLE_FULL_SELECTED ?
-                                       "full" : "half");
-               }
-               else
-               {
-                       printk(KERN_INFO"%s: Media Link Off\n", dev->name);
-               }
+       /* FIXME: should be removed, and replaced by AutoNeogotiate stuff */
+        outl((RX_DMA_BURST << RxMXDMA_shift) | (RxDRNT_10 << RxDRNT_shift), 
+            ioaddr + rxcfg);
+        outl(TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift) | TxDRNT_10,
+            ioaddr + txcfg);
+
+       if (sis_priv->LinkOn) {
+               printk(KERN_INFO "%s: Media Type %s%s-duplex.\n",
+                      dev->name, 
+                      sis_priv->speeds == HW_SPEED_100_MBPS ? "100mbps " : "10mbps ",
+                      sis_priv->full_duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half");
+       } else {
+               printk(KERN_INFO "%s: Media Link Off\n", dev->name);
        }
+
         set_rx_mode(dev);
 
         dev->tbusy = 0;
@@ -990,56 +554,77 @@ sis900_open(struct device *dev)
         dev->start = 1;
 
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
+        outl((RxRCMP|RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
         outl(RxENA, ioaddr + cr);
         outl(IE, ioaddr + ier);
 
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n",
-                           dev->name, ioaddr, dev->irq);
-
         /* Set the timer to switch to check for link beat and perhaps switch
            to an alternate media type. */
-        init_timer(&tp->timer);
-        tp->timer.expires = RUN_AT((24*HZ)/10);         /* 2.4 sec. */
-        tp->timer.data = (unsigned long)dev;
-        tp->timer.function = &sis900_timer;             /* timer handler */
-        add_timer(&tp->timer);
+        init_timer(&sis_priv->timer);
+        sis_priv->timer.expires = jiffies + 2*HZ;
+        sis_priv->timer.data = (unsigned long)dev;
+        sis_priv->timer.function = &sis900_timer;
+        add_timer(&sis_priv->timer);
 
         return 0;
 }
 
+/* set receive filter address to our MAC address */
+static void
+sis900_init_rxfilter (struct device * net_dev)
+{
+       long ioaddr = net_dev->base_addr;
+       u32 rfcrSave;
+       u32 i;
+       
+       rfcrSave = inl(rfcr + ioaddr);
+
+       /* disable packet filtering before setting filter */
+       outl(rfcrSave & ~RFEN, rfcr);
+
+       for (i = 0 ; i < 3 ; i++) {
+               u32 w;
+
+               w = (u32) *((u16 *)(net_dev->dev_addr)+i);
+               outl((i << RFADDR_shift), ioaddr + rfcr);
+               outl(w, ioaddr + rfdr);
+
+               if (sis900_debug > 4) {
+                       printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n",
+                              net_dev->name, i, inl(ioaddr + rfdr));
+               }
+       }
+       outl(rfcrSave, rfcr + ioaddr);
+}
+
 static void sis900_timer(unsigned long data)
 {
         struct device *dev = (struct device *)data;
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        int next_tick = 0;
+        int next_tick = 2*HZ;
         u16 status;
 
+       /* FIXME: call auto negotiate routine to detect link status */
         if (!tp->LinkOn) {
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
+                status = mdio_read(dev, tp->mii->phy_addr, MII_STATUS);
                if (status & MIISTAT_LINK) {
-                       elPMDreadMode(dev, tp->phys[tp->phy_idx],
-                                        &tp->speeds, &tp->full_duplex);
+                       elPMDreadMode(dev, tp->mii->phy_addr,
+                                     &tp->speeds, &tp->full_duplex);
                        tp->LinkOn = TRUE;
-                        printk(KERN_INFO "%s: Media Link On %s%s-duplex ",
-                                   dev->name,
-                                   tp->speeds == HW_SPEED_100_MBPS ?
-                                               "100mbps " : "10mbps ",
-                                   tp->full_duplex==FDX_CAPABLE_FULL_SELECTED ?
-                                               "full" : "half");
+                        printk(KERN_INFO "%s: Media Link On %s%s-duplex \n", dev->name,
+                              tp->speeds == HW_SPEED_100_MBPS ? "100mbps " : "10mbps ",
+                              tp->full_duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half");
                }
         } else { // previous link on
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
+                status = mdio_read(dev, tp->mii->phy_addr, MII_STATUS);
                if (!(status & MIISTAT_LINK)) {
                        tp->LinkOn = FALSE;
                         printk(KERN_INFO "%s: Media Link Off\n", dev->name);
                }
         }
-        next_tick = 2*HZ;
 
         if (next_tick) {
-                tp->timer.expires = RUN_AT(next_tick);
+                tp->timer.expires = jiffies + next_tick;
                 add_timer(&tp->timer);
         }
 }
@@ -1068,20 +653,9 @@ static void sis900_tx_timeout(struct device *dev)
                                " (queue head)" : "");
        }
 
-        /* Soft reset the chip. */
-        //outb(RESET, ioaddr + cr);
-        /* Check that the chip has finished the reset. */
-        /*
-        for (i = 1000; i > 0; i--)
-                if ((inb(ioaddr + cr) & RESET) == 0)
-                        break;
-        */
 
         tp->cur_rx = 0; 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-        set_rx_mode(dev);
-        */
+
         {       /* Save the unsent Tx packets. */
                 struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
                 int j;
@@ -1095,11 +669,6 @@ static void sis900_tx_timeout(struct device *dev)
                         memcpy((unsigned char*)(tp->tx_buf[i].buf),
                                                 skb->data, skb->len);
                         tp->tx_buf[i].cmdsts = OWN | skb->len;
-                        /* Note: the chip doesn't have auto-pad! */
-                        /*
-                        outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN),
-                                 ioaddr + TxStatus0 + i*4);
-                        */
                 }
                 outl(TxENA, ioaddr + cr);
                 tp->cur_tx = i;
@@ -1116,28 +685,27 @@ static void sis900_tx_timeout(struct device *dev)
         dev->trans_start = jiffies;
         tp->stats.tx_errors++;
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
+        outl((RxRCMP|RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
         return;
 }
 
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+/* Reset (Initialize) the Tx rings, along with various 'dev' bits. */
 static void
-sis900_init_ring(struct device *dev)
+sis900_reset_tx_ring(struct device *dev)
 {
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        long ioaddr = dev->base_addr; 
         int i;
-
+       
         tp->tx_full = 0;
-        tp->cur_rx = 0;
         tp->dirty_tx = tp->cur_tx = 0;
-
+       
         /* Tx Buffer */
         for (i = 0; i < NUM_TX_DESC; i++) {
-                tp->tx_skbuff[i] = 0;
-                tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE];
+               tp->tx_skbuff[i] = 0;
+               tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE];
                 tp->tx_buf[i].bufPhys =
-                                virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]);
+                       virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]);
         }
 
         /* Tx Descriptor */
@@ -1152,6 +720,19 @@ sis900_init_ring(struct device *dev)
                 tp->tx_buf[i].cmdsts=0;
         }
 
+        outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp); 
+}
+
+/* Reset (Initialize) the Rx rings, along with various 'dev' bits. */ 
+static void 
+sis900_reset_rx_ring(struct device *dev) 
+{ 
+        struct sis900_private *tp = (struct sis900_private *)dev->priv; 
+        long ioaddr = dev->base_addr; 
+        int i; 
+        tp->cur_rx = 0; 
+
         /* Rx Buffer */
         for (i = 0; i < NUM_RX_DESC; i++) {
                 tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE];
@@ -1170,6 +751,8 @@ sis900_init_ring(struct device *dev)
                                 virt_to_bus(&(tp->rx_buf[i].plink));
                 tp->rx_buf[i].cmdsts=RX_BUF_SIZE;
         }
+
+        outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp); 
 }
 
 static int
@@ -1241,7 +824,8 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
 #if defined(__i386__)
         /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-        if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+        if (test_and_set_bit(0, (void*)&dev->interrupt)
+) {
                 printk(KERN_INFO "%s: SMP simultaneous entry of "
                                 "an interrupt handler.\n", dev->name);
                 dev->interrupt = 0;     /* Avoid halting machine. */
@@ -1258,8 +842,6 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
         do {
                 status = inl(ioaddr + isr);
-                /* Acknowledge all of the current interrupt sources ASAP. */
-                outl(status, ioaddr + isr); // ?????
 
                 if (sis900_debug > 4)
                         printk(KERN_INFO "%s: interrupt  status=%#4.4x "
@@ -1267,6 +849,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                 dev->name, status, inl(ioaddr + isr));
 
                 if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) {
+                       /* nothing intresting happened */
                         break;
                 }
 
@@ -1354,7 +937,7 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                 /* Free the original skb. */
                                 if (sis900_debug > 2)
                                         printk(KERN_INFO "Free original skb\n");
-                                dev_free_skb(tp->tx_skbuff[entry]);
+                                dev_kfree_skb(tp->tx_skbuff[entry]);
                                 tp->tx_skbuff[entry] = 0;
                         } // for dirty
 
@@ -1419,8 +1002,6 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
         return;
 }
 
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
 static int sis900_rx(struct device *dev)
 {
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
@@ -1533,6 +1114,7 @@ static int sis900_rx(struct device *dev)
                            dev->name, cur_rx,
                            inb(ioaddr + cr));
         tp->cur_rx = cur_rx;
+       outl( RxENA , ioaddr + cr );  /* LCS */
         return 0;
 }
 
@@ -1546,10 +1128,6 @@ sis900_close(struct device *dev)
         dev->start = 0;
         dev->tbusy = 1;
 
-        if (sis900_debug > 1)
-                printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
-                           dev->name, inl(ioaddr + isr));
-
         /* Disable interrupts by clearing the interrupt mask. */
         outl(0x0000, ioaddr + imr);
 
@@ -1562,7 +1140,7 @@ sis900_close(struct device *dev)
 
         for (i = 0; i < NUM_TX_DESC; i++) {
                 if (tp->tx_skbuff[i])
-                        dev_free_skb(tp->tx_skbuff[i]);
+                        dev_kfree_skb(tp->tx_skbuff[i]);
                 tp->tx_skbuff[i] = 0;
         }
         kfree(tp->rx_bufs);
@@ -1581,13 +1159,13 @@ static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
         u16 *data = (u16 *)&rq->ifr_data;
 
         switch(cmd) {
-        case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
-                data[0] = tp->phys[tp->phy_idx];
+        case SIOCDEVPRIVATE:                   /* Get the address of the PHY in use. */
+                data[0] = tp->mii->phy_addr;
                 /* Fall Through */
-        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+        case SIOCDEVPRIVATE+1:                 /* Read the specified MII register. */
                 data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
                 return 0;
-        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+        case SIOCDEVPRIVATE+2:                 /* Write the specified MII register */
                 if (!suser())
                         return -EPERM;
                 mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
@@ -1727,17 +1305,17 @@ static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *spe
         retnVal = elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO,
                                FALSE,&status);
        if (!retnVal) {
-               printk(KERN_INFO "Not wait for Reset Complete\n");
+               printk(KERN_INFO "%s: Not wait for Reset Complete\n", dev->name);
        }
         retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE,
                                TRUE, &status);
        if (!retnVal) {
-               printk(KERN_INFO "Not wait for AutoNego Complete\n");
+               printk(KERN_INFO "%s: Not wait for AutoNego Complete\n", dev->name);
        }
         retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK,
                                TRUE, &status);
        if (!retnVal) {
-               printk(KERN_INFO "Not wait for Link Complete\n");
+               printk(KERN_INFO "%s: Not wait for Link Complete\n", dev->name);
        }
         if (status & MIISTAT_LINK) {
                 elPMDreadMode(dev, phy_id, speed, duplex);
@@ -1814,9 +1392,8 @@ static void set_rx_mode(struct device *dev)
                 for (i=0 ; i<8 ; i++)
                         mc_filter[i]=0xffff;
         } else if ((dev->mc_count > multicast_filter_limit)
-                           ||  (dev->flags & IFF_ALLMULTI)) {
-                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS |
-                                ACCEPT_CAM_QUALIFIED;
+                                  ||  (dev->flags & IFF_ALLMULTI)) {
+                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | ACCEPT_CAM_QUALIFIED;
                 for (i=0 ; i<8 ; i++)
                         mc_filter[i]=0xffff;
         } else {
@@ -1875,49 +1452,40 @@ static void set_rx_mode(struct device *dev)
 static void sis900_reset(struct device *dev)
 {
         long ioaddr = dev->base_addr;
-
+       
         outl(0, ioaddr + ier);
         outl(0, ioaddr + imr);
         outl(0, ioaddr + rfcr);
 
         outl(RxRESET | TxRESET | RESET, ioaddr + cr);
         outl(PESEL, ioaddr + cfg);
-
+       
         set_rx_mode(dev);
 }
 
 #ifdef MODULE
 int init_module(void)
 {
-        return sis900_probe(0);
+        return sis900_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-        struct device *next_dev;
-
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-        while (root_sis900_dev) {
-                struct sis900_private *tp =
-                        (struct sis900_private *)root_sis900_dev->priv;
-                next_dev = tp->next_module;
-                unregister_netdev(root_sis900_dev);
-                release_region(root_sis900_dev->base_addr,
-                                           pci_tbl[tp->chip_id].io_size);
-                kfree(tp);
-                kfree(root_sis900_dev);
-                root_sis900_dev = next_dev;
+       /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+       while (root_sis900_dev) {
+               struct sis900_private *tp =
+                       (struct sis900_private *)root_sis900_dev->priv;
+               struct device *next_dev = tp->next_module;
+               
+               unregister_netdev(root_sis900_dev);
+               release_region(root_sis900_dev->base_addr,
+                              tp->mac->io_size);
+               kfree(tp);
+               kfree(root_sis900_dev);
+
+               root_sis900_dev = next_dev;
         }
 }
 
 #endif  /* MODULE */
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
new file mode 100644 (file)
index 0000000..e3adaae
--- /dev/null
@@ -0,0 +1,256 @@
+/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900 
+ * Copyrigth 1999 Silicon Integrated System Corporation
+ * References:
+ *   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+ *     preliminary Rev. 1.0 Jan. 14, 1998
+ *   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+ *     preliminary Rev. 1.0 Nov. 10, 1998
+ *   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+ *     preliminary Rev. 1.0 Jan. 18, 1998
+ *   http://www.sis.com.tw/support/databook.htm
+ */
+
+/* MAC operationl registers of SiS 7016 and SiS 900 ehternet controller */
+/* The I/O extent, SiS 900 needs 256 bytes of io address */
+#define SIS900_TOTAL_SIZE 0x100
+
+/* Symbolic offsets to registers. */
+enum SIS900_registers {
+       cr=0x0,                 //Command Register
+       cfg=0x4,                //Configuration Register
+       mear=0x8,               //EEPROM Access Register
+       ptscr=0xc,              //PCI Test Control Register
+       isr=0x10,               //Interrupt Status Register
+       imr=0x14,               //Interrupt Mask Register
+       ier=0x18,               //Interrupt Enable Register
+       epar=0x18,              //Enhanced PHY Access Register
+       txdp=0x20,              //Transmit Descriptor Pointer Register
+        txcfg=0x24,             //Transmit Configuration Register
+        rxdp=0x30,              //Receive Descriptor Pointer Register
+        rxcfg=0x34,             //Receive Configuration Register
+        flctrl=0x38,            //Flow Control Register
+        rxlen=0x3c,             //Receive Packet Length Register
+        rfcr=0x48,              //Receive Filter Control Register
+        rfdr=0x4C,              //Receive Filter Data Register
+        pmctrl=0xB0,            //Power Management Control Register
+        pmer=0xB4               //Power Management Wake-up Event Register
+};
+
+/* Symbolic names for bits in various registers */
+enum sis900_command_register_bits {
+       RESET   = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020,
+       TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004,
+       TxDIS   = 0x00000002, TxENA = 0x00000001
+};
+
+enum sis900_configuration_register_bits {
+       DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
+       SB    = 0x00000040, POW = 0x00000020, EXD = 0x00000010, 
+       PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001
+};
+
+enum sis900_eeprom_access_reigster_bits {
+       MDC  = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */ 
+       EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002,
+       EEDI = 0x00000001
+};
+
+enum sis900_interrupt_register_bits {
+       WKEVT  = 0x10000000, TxPAUSEEND = 0x08000000, TxPAUSE = 0x04000000,
+       TxRCMP = 0x02000000, RxRCMP = 0x01000000, DPERR = 0x00800000,
+       SSERR  = 0x00400000, RMABT  = 0x00200000, RTABT = 0x00100000,
+       RxSOVR = 0x00010000, HIBERR = 0x00008000, SWINT = 0x00001000,
+       MIBINT = 0x00000800, TxURN  = 0x00000400, TxIDLE  = 0x00000200,
+       TxERR  = 0x00000100, TxDESC = 0x00000080, TxOK  = 0x00000040,
+       RxORN  = 0x00000020, RxIDLE = 0x00000010, RxEARLY = 0x00000008,
+       RxERR  = 0x00000004, RxDESC = 0x00000002, RxOK  = 0x00000001
+};
+
+enum sis900_interrupt_enable_reigster_bits {
+       IE = 0x00000001
+};
+
+/* maximum dma burst fro transmission and receive*/
+#define MAX_DMA_RANGE  7       /* actually 0 means MAXIMUM !! */
+#define TxMXDMA_shift          20
+#define RxMXDMA_shift    20
+#define TX_DMA_BURST           0
+#define RX_DMA_BURST           0
+
+/* transmit FIFO threshholds */
+#define TX_FILL_THRESH   16
+#define TxFILLT_shift          8
+#define TxDRNT_shift           0
+#define TxDRNT_100      (1536>>5)
+#define TxDRNT_10              16 
+
+enum sis900_transmit_config_register_bits {
+       TxCSI = 0x80000000, TxHBI = 0x40000000, TxMLB = 0x20000000,
+       TxATP = 0x10000000, TxIFG = 0x0C000000, TxFILLT = 0x00003F00,
+       TxDRNT = 0x0000003F
+};
+
+/* recevie FFIFO thresholds */
+#define RxDRNT_shift     1
+#define RxDRNT_100     8
+#define RxDRNT_10              8 
+
+enum sis900_reveive_config_register_bits {
+       RxAEP  = 0x80000000, RxARP = 0x40000000, RxATP   = 0x10000000,
+       RxAJAB = 0x08000000, RxDRNT = 0x0000007F
+};
+
+#define RFAA_shift      28
+#define RFADDR_shift    16
+
+enum sis900_receive_filter_control_register_bits {
+       RFEN  = 0x80000000, RFAAB = 0x40000000, RFAAM = 0x20000000,
+       RFAAP = 0x10000000, RFPromiscuous = (RFAAB|RFAAM|RFAAP)
+};
+
+enum sis900_reveive_filter_data_mask {
+       RFDAT =  0x0000FFFF
+};
+
+/* EEPROM Addresses */
+enum sis900_eeprom_address {
+       EEPROMSignature = 0x00, EEPROMVendorID = 0x02, EEPROMDeviceID = 0x03,
+       EEPROMMACAddr   = 0x08, EEPROMChecksum = 0x0b
+};
+
+/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
+enum sis900_eeprom_command {
+       EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0, 
+       EEwriteEnable = 0x0130, EEwriteDisable = 0x0100,
+       EEeraseAll = 0x0120, EEwriteAll = 0x0110, 
+       EEaddrMask = 0x013F, EEcmdShift = 16
+};
+
+/* Manamgement Data I/O (mdio) frame */
+#define MIIread         0x6000
+#define MIIwrite        0x5002
+#define MIIpmdShift     7
+#define MIIregShift     2
+#define MIIcmdLen       16
+#define MIIcmdShift     16
+
+/* Buffer Descriptor */
+#define OWN             0x80000000
+#define MORE            0x40000000
+#define INTR            0x20000000
+#define OK              0x08000000
+#define DSIZE           0x00000FFF
+
+#define SUPCRC          0x10000000
+#define ABORT           0x04000000
+#define UNDERRUN        0x02000000
+#define NOCARRIER       0x01000000
+#define DEFERD          0x00800000
+#define EXCDEFER        0x00400000
+#define OWCOLL          0x00200000
+#define EXCCOLL         0x00100000
+#define COLCNT          0x000F0000
+
+#define INCCRC          0x10000000
+//      ABORT           0x04000000
+#define OVERRUN         0x02000000
+#define DEST            0x01800000
+#define BCAST           0x01800000
+#define MCAST           0x01000000
+#define UNIMATCH        0x00800000
+#define TOOLONG         0x00400000
+#define RUNT            0x00200000
+#define RXISERR         0x00100000
+#define CRCERR          0x00080000
+#define FAERR           0x00040000
+#define LOOPBK          0x00020000
+#define RXCOL           0x00010000
+
+#define RXSTS_shift     18
+
+/* MII register offsets */
+#define MII_CONTROL             0x0000
+#define MII_STATUS              0x0001
+#define MII_PHY_ID0             0x0002
+#define MII_PHY_ID1             0x0003
+#define MII_ANAR                0x0004
+#define MII_ANLPAR              0x0005
+#define MII_ANER                0x0006
+/* MII Control register bit definitions. */
+#define MIICNTL_FDX             0x0100
+#define MIICNTL_RST_AUTO        0x0200
+#define MIICNTL_ISOLATE         0x0400
+#define MIICNTL_PWRDWN          0x0800
+#define MIICNTL_AUTO            0x1000
+#define MIICNTL_SPEED           0x2000
+#define MIICNTL_LPBK            0x4000
+#define MIICNTL_RESET           0x8000
+/* MII Status register bit significance. */
+#define MIISTAT_EXT             0x0001
+#define MIISTAT_JAB             0x0002
+#define MIISTAT_LINK            0x0004
+#define MIISTAT_CAN_AUTO        0x0008
+#define MIISTAT_FAULT           0x0010
+#define MIISTAT_AUTO_DONE       0x0020
+#define MIISTAT_CAN_T           0x0800
+#define MIISTAT_CAN_T_FDX       0x1000
+#define MIISTAT_CAN_TX          0x2000
+#define MIISTAT_CAN_TX_FDX      0x4000
+#define MIISTAT_CAN_T4          0x8000
+/* MII NWAY Register Bits ...
+** valid for the ANAR (Auto-Negotiation Advertisement) and
+** ANLPAR (Auto-Negotiation Link Partner) registers */
+#define MII_NWAY_NODE_SEL       0x001f
+#define MII_NWAY_CSMA_CD        0x0001
+#define MII_NWAY_T              0x0020
+#define MII_NWAY_T_FDX          0x0040
+#define MII_NWAY_TX             0x0080
+#define MII_NWAY_TX_FDX         0x0100
+#define MII_NWAY_T4             0x0200
+#define MII_NWAY_RF             0x2000
+#define MII_NWAY_ACK            0x4000
+#define MII_NWAY_NP             0x8000
+
+/* MII Auto-Negotiation Expansion Register Bits */
+#define MII_ANER_PDF            0x0010
+#define MII_ANER_LP_NP_ABLE     0x0008
+#define MII_ANER_NP_ABLE        0x0004
+#define MII_ANER_RX_PAGE        0x0002
+#define MII_ANER_LP_AN_ABLE     0x0001
+#define HALF_DUPLEX                     1
+#define FDX_CAPABLE_DUPLEX_UNKNOWN      2
+#define FDX_CAPABLE_HALF_SELECTED       3
+#define FDX_CAPABLE_FULL_SELECTED       4
+#define HW_SPEED_UNCONFIG       0
+#define HW_SPEED_10_MBPS        10
+#define HW_SPEED_100_MBPS       100
+#define HW_SPEED_DEFAULT        (HW_SPEED_10_MBPS)
+
+#define ACCEPT_ALL_PHYS         0x01
+#define ACCEPT_ALL_MCASTS       0x02
+#define ACCEPT_ALL_BCASTS       0x04
+#define ACCEPT_ALL_ERRORS       0x08
+#define ACCEPT_CAM_QUALIFIED    0x10
+#define MAC_LOOPBACK            0x20
+
+//#define FDX_CAPABLE_FULL_SELECTED     4
+#define CRC_SIZE                4
+#define MAC_HEADER_SIZE         14
+
+#define TX_BUF_SIZE     1536
+#define RX_BUF_SIZE     1536
+
+#define NUM_TX_DESC     16             /* Number of Tx descriptor registers. */
+#define NUM_RX_DESC     8              /* Number of Rx descriptor registers. */
+
+#define TRUE            1
+#define FALSE           0
+
+/* PCI stuff, should be move to pic.h */
+#define PCI_DEVICE_ID_SI_900   0x900   
+#define PCI_DEVICE_ID_SI_7016  0x7016  
+
+/* ioctl for accessing MII transveiver */
+#define SIOCGMIIPHY (SIOCDEVPRIVATE)           /* Get the PHY in use. */
+#define SIOCGMIIREG (SIOCDEVPRIVATE+1)         /* Read a PHY register. */
+#define SIOCSMIIREG (SIOCDEVPRIVATE+2)         /* Write a PHY register */
index 7fef134f5d47382132f07307482d50690f8eeed5..66e489a9a07ffc354ca6f06046cb8373f3f27205 100644 (file)
@@ -526,6 +526,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( INTEL,          INTEL_82441,    "82441FX Natoma"),
        DEVICE( INTEL,          INTEL_82380FB,  "82380FB Mobile"),
        DEVICE( INTEL,          INTEL_82439,    "82439HX Triton II"),
+       DEVICE( INTEL,          INTEL_MEGARAID, "OEM MegaRAID Controller"),
        DEVICE( INTEL,          INTEL_82371SB_0,"82371SB PIIX3 ISA"),
        DEVICE( INTEL,          INTEL_82371SB_1,"82371SB PIIX3 IDE"),
        DEVICE( INTEL,          INTEL_82371SB_2,"82371SB PIIX3 USB"),
@@ -536,13 +537,16 @@ struct pci_dev_info dev_info[] = {
        DEVICE( INTEL,          INTEL_82371AB_2,"82371AB PIIX4 USB"),
        DEVICE( INTEL,          INTEL_82371AB_3,"82371AB PIIX4 ACPI"),
        DEVICE( INTEL,          INTEL_82443LX_0,"440LX - 82443LX PAC Host"),
-       DEVICE( COMPUTONE,      COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
        DEVICE( INTEL,          INTEL_82443LX_1,"440LX - 82443LX PAC AGP"),
        DEVICE( INTEL,          INTEL_82443BX_0,"440BX - 82443BX Host"),
        DEVICE( INTEL,          INTEL_82443BX_1,"440BX - 82443BX AGP"),
        DEVICE( INTEL,          INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
        DEVICE( INTEL,          INTEL_P6,       "Orion P6"),
-       DEVICE( INTEL,          INTEL_82450GX,  "82450GX Orion P6"),
+       DEVICE( INTEL,          INTEL_82450GX,  "450KX/GX [Orion] - 82454KX/GX PCI Bridge"),
+       DEVICE( INTEL,          INTEL_82453GX,  "450KX/GX [Orion] - 82453KX/GX Memory Controller"),
+       DEVICE( INTEL,          INTEL_82451NX,  "450NX - 82451NX Memory & I/O Controller"),
+       DEVICE( INTEL,          INTEL_82454NX,  "450NX - 82454NX PCI Expander Bridge"),
+       DEVICE( COMPUTONE,      COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
        DEVICE( KTI,            KTI_ET32P2,     "ET32P2"),
        DEVICE( ADAPTEC,        ADAPTEC_7810,   "AIC-7810 RAID"),
        DEVICE( ADAPTEC,        ADAPTEC_7821,   "AIC-7860"),
index 760b3fbc5617389c2df5ef16b2ba88ceb9da3de5..b7b6d64b9575358f1090d4d6db5ae0ab2bd542a5 100644 (file)
@@ -875,6 +875,8 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
    int              retcode;
    struct Scsi_Host *shpnt;
 #if DO_DETECT
+   int i = 0;
+   int j = 0;
    const int        buflen = 255;
    Scsi_Cmnd        SCinit;
    unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
index 340adf5aeaf54a093cb72e0a5f176f5936beaa74..6d77ef1ae9c7c2cfb00b084d4b9e1967674ae2fd 100644 (file)
 #define HIGH_PRI        0x08
 
 /* data directions */
+#ifndef HOSTS_C
 #define DATA_IN         0x01000000L             /* data from target */
 #define DATA_OUT        0x00000000L             /* data to target */
+#endif
 
 /* BMIC registers (EISA controllers) */
 #define ID0REG          0x0c80                  /* board ID */
index 964cd432f673faa97a9f5bd2613846d3baa70e5e..af3e7f1129f6d95c44f97b6c664c04e7b8c06814 100644 (file)
 /*
  * DCDB Table Equates
  */
+#ifndef HOSTS_C 
    #define NO_DISCONNECT                0x00
    #define DISCONNECT_ALLOWED           0x80
    #define NO_AUTO_REQUEST_SENSE        0x40
    #define TIMEOUT10                    0x10
    #define TIMEOUT60                    0x20
    #define TIMEOUT20M                   0x30
-
 /*
  * Host adapter Flags (bit numbers)
  */
  */
    #define SCB_ACTIVE                   0x00001
    #define SCB_WAITING                  0x00002
-
+#endif /* HOSTS_C */
 /*
  * Passthru stuff
  */
@@ -590,6 +590,8 @@ typedef struct _SUBSYS_PARAM {
 /*
  * Inquiry Data Format
  */
+#ifndef HOSTS_C
+
 typedef struct {
    u8        DeviceType:5;
    u8        DeviceTypeQualifier:3;
@@ -614,6 +616,7 @@ typedef struct {
    u8        Reserved3[40];
 } INQUIRYDATA, *PINQUIRYDATA;
 
+#endif
 /*
  * Read Capacity Data Format
  */
index 83fe02785b4719e92cd2f4d7f051ac69c4bb27ef..8a801c8336ef509e499b2193ed367e2ede90da74 100644 (file)
@@ -11,6 +11,7 @@
 #define BOARD_QUARTZ            0x08000000L
 #define BOARD_40LD              0x04000000L
 
+#ifndef HOSTS_C
 #define SCB_FREE     0x0
 #define SCB_ACTIVE   0x1
 #define SCB_WAITQ    0x2
@@ -18,6 +19,7 @@
 #define SCB_COMPLETE 0x4
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
+#endif
 
 #define MEGA_CMD_TIMEOUT        10
 
index 1aed96ec7d47f40eff7d9bf38fe8175e10199a26..306dad4fe3aa1bd5b4469e9ea0baba729cbebae6 100644 (file)
@@ -211,6 +211,8 @@ typedef     struct _READ_CAPACITY_DATA
        }       READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
 
 // SCSI inquiry data
+#ifndef HOSTS_C
+
 typedef struct _INQUIRYDATA
        {
        UCHAR DeviceType                        :5;
@@ -235,6 +237,7 @@ typedef struct _INQUIRYDATA
     UCHAR VendorSpecific[20];
     UCHAR Reserved3[40];
        }       INQUIRYDATA, *PINQUIRYDATA;
+#endif
 
 // IDE IDENTIFY data
 typedef struct _IDENTIFY_DATA
index cf00d442efb968c643b7fec359cadf2a6493f64f..7f91fa4bd8fbb532a6b17060664b7050c82e45a0 100644 (file)
@@ -1855,7 +1855,7 @@ static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *co
 
 static int isp2x00_init(struct Scsi_Host *sh)
 {
-       u_int io_base;
+       u_long io_base;
        struct isp2x00_hostdata *hostdata;
        u_char revision;
        u_int irq;
index 8744bb8ab1c6c0f1992d0753050070ed92e9436a..27837d71710a933d831ca170f9f2cebec07926a7 100644 (file)
@@ -1262,6 +1262,13 @@ static int isp1020_init(struct Scsi_Host *sh)
                pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
        }
 #endif
+#ifdef __alpha__
+       /* Force ALPHA to use bus I/O and not bus MEM. 
+          This is to avoid having to use HAE_MEM registers,
+          which is broken on some platforms and with SMP.
+       */
+       command &= ~PCI_COMMAND_MEMORY;
+#endif
 
        if ((command & PCI_COMMAND_MEMORY) &&
            ((mem_base & 1) == 0)) {
index 49abc83cac7a8195bc511065afffdf37e5cd915f..67e6240aa45deb11a7f72d2ceb407eae2cbe1eb8 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/version.h>
 #endif
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #include <linux/types.h>
 #include <linux/kdev_t.h>
index f45cd0824b31ee7ef58f9d98f1b5ea1d96aa3eaa..c1e43efec1a719afc0c58feca20fa9ed9fc986a8 100644 (file)
@@ -66,8 +66,9 @@
 #endif
 #include <linux/config.h>
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
+#endif
 /*
  * NCR PQS/PDS special device support.
  */
index 943b8cbb3cc89aa6b9892e4b68eca28480136b65..c97d29bcb6d54517f81a0c234150a558ea9b6f00 100644 (file)
@@ -18,7 +18,9 @@ int u14_34f_biosparam(Disk *, kdev_t, int *);
 
 #define U14_34F_VERSION "4.33.00"
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
 
index 5d2a848c9751d198ca6d05dc10701d32b9a47cb6..d4bcd1ae2951a060cba64b5f0379c4eda3cec468 100644 (file)
@@ -115,8 +115,6 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
       int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
   fi
   
-  dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
-  
   dep_tristate 'Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then
       bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 
index 255b6793b11723b33ee11582322092ef3dd6b422..fe8ae5e5998647fb62d1a0bf2dd691f9cda79be9 100644 (file)
@@ -43,7 +43,6 @@ obj-          :=
 obj-$(CONFIG_SOUND)            += soundcore.o
 obj-$(CONFIG_DMASOUND)         += dmasound.o
 obj-$(CONFIG_SOUND_OSS)                += sound.o
-obj-$(CONFIG_SOUND_ADLIB)      += adlib_card.o opl3.o
 obj-$(CONFIG_SOUND_CS4232)     += cs4232.o ad1848.o 
 
 # In theory, there's probably no reason to include the uart401 code
index 3269337d510ba32300dc9e1e6184bdcc58cc8d36..490d69f880733878d76ef4f922de2f48038827b9 100644 (file)
 
 /* registers 0x0028 - 0x0058 are reserved */
 
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID       0x0028  /* Extended Audio ID */
+#define AC97_EXTENDED_STATUS   0x002A  /* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C  /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE  0x002E  /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE   0x0030  /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE   0x0032  /* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE   0x0034  /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER  0x0036  /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER    0x0038  /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A       0x003A  /* Reserved */
+/* range 0x3c-0x58 - MODEM */
+
 /* registers 0x005a - 0x007a are vendor reserved */
 
 #define  AC97_VENDOR_ID1         0x007c
index b21d7316eed71940ec06467cf0bc41dc4c1bae8a..9bd6cc1c53ccbfd9d47398952e9fe8a386e0d8f4 100644 (file)
@@ -16,8 +16,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 void attach_adlib_card(struct address_info *hw_config)
 {
        hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp);
@@ -70,4 +68,3 @@ void cleanup_module(void)
 }
 
 #endif
-#endif
index 7f53acc68a05f1eaf66c4397ae3835c6c40ccb19..4b72ef1bf8c45c742abf239cae41cc39495222a6 100644 (file)
  *    15.06.99   0.23  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.24  Add pci_set_master
+ *    02.08.99   0.25  Added workaround for the "phantom write" bug first
+ *                     documented by Dave Sharpless from Anchor Games
+ *    03.08.99   0.26  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+ *    12.08.99   0.27  module_init/__setup fixes
+ *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.99   0.29  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.30  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  * some important things missing in Ensoniq documentation:
  *
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #define ES1370_REG_DAC2_SCOUNT    0x28
 #define ES1370_REG_ADC_SCOUNT     0x2c
 
-#define ES1370_REG_DAC1_FRAMEADR  0xc30
-#define ES1370_REG_DAC1_FRAMECNT  0xc34
-#define ES1370_REG_DAC2_FRAMEADR  0xc38
-#define ES1370_REG_DAC2_FRAMECNT  0xc3c
-#define ES1370_REG_ADC_FRAMEADR   0xd30
-#define ES1370_REG_ADC_FRAMECNT   0xd34
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
 
 #define ES1370_FMT_U8_MONO     0
 #define ES1370_FMT_U8_STEREO   1
@@ -360,6 +372,13 @@ struct es1370_state {
 
 static struct es1370_state *devs = NULL;
 
+/*
+ * The following buffer is used to point the phantom write channel to,
+ * so that it cannot wreak havoc. The attribute makes sure it doesn't
+ * cross a page boundary and ensures dword alignment for the DMA engine
+ */
+static unsigned char bugbuf[16] __attribute__ ((aligned (16)));
+
 /* --------------------------------------------------------------------- */
 
 extern inline unsigned ld2(unsigned int x)
@@ -779,10 +798,36 @@ static const struct {
        [SOUND_MIXER_OGAIN]  = { 9, 0xf, 0x0, 0, 0x0000, 1 }    /* mono out */
 };
 
+static void set_recsrc(struct es1370_state *s, unsigned int val)
+{
+       unsigned int i, j;
+
+       for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+               if (!(val & (1 << i)))
+                       continue;
+               if (!mixtable[i].recmask) {
+                       val &= ~(1 << i);
+                       continue;
+               }
+               j |= mixtable[i].recmask;
+       }
+       s->mix.recsrc = val;
+       wrcodec(s, 0x12, j & 0xd5);
+       wrcodec(s, 0x13, j & 0xaa);
+       wrcodec(s, 0x14, (j >> 8) & 0x17);
+       wrcodec(s, 0x15, (j >> 8) & 0x0f);
+       i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+       if (!s->mix.imix) {
+               i &= 0xff60;  /* mute record and line monitor */
+       }
+       wrcodec(s, 0x10, i);
+       wrcodec(s, 0x11, i >> 8);
+}
+
 static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
 {
        unsigned long flags;
-       int i, val, j;
+       int i, val;
        unsigned char l, r, rl, rr;
 
        VALIDATE_STATE(s);
@@ -887,34 +932,13 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
        switch (_IOC_NR(cmd)) {
 
        case SOUND_MIXER_IMIX:
-               if (arg == 0) 
-                       return -EFAULT;
-               get_user_ret(s->mix.imix,(int *)arg, -EFAULT);
-               val = s->mix.recsrc;
-               /* fall through */
+               get_user_ret(s->mix.imix, (int *)arg, -EFAULT);
+               set_recsrc(s, s->mix.recsrc);
+               return 0;
 
        case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
                get_user_ret(val, (int *)arg, -EFAULT);
-               for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-                       if (!(val & (1 << i)))
-                               continue;
-                       if (!mixtable[i].recmask) {
-                               val &= ~(1 << i);
-                               continue;
-                       }
-                       j |= mixtable[i].recmask;
-               }
-               s->mix.recsrc = val;
-               wrcodec(s, 0x12, j & 0xd5);
-               wrcodec(s, 0x13, j & 0xaa);
-               wrcodec(s, 0x14, (j >> 8) & 0x17);
-               wrcodec(s, 0x15, (j >> 8) & 0x0f);
-               i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
-               if (!s->mix.imix) {
-                    i &= 0xff60;  /* mute record and line monitor */
-               }
-               wrcodec(s, 0x10, i);
-               wrcodec(s, 0x11, i >> 8);
+               set_recsrc(s, val);
                return 0;
 
        default:
@@ -1033,7 +1057,7 @@ static /*const*/ struct file_operations es1370_mixer_fops = {
 
 static int drain_dac1(struct es1370_state *s, int nonblock)
 {
-        struct wait_queue wait = { current, NULL };
+       struct wait_queue wait = { current, NULL };
        unsigned long flags;
        int count, tmo;
        
@@ -1054,9 +1078,10 @@ static int drain_dac1(struct es1370_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+               tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
+                       / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
                tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
+               if (!schedule_timeout(tmo + 1))
                        DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
@@ -1089,9 +1114,10 @@ static int drain_dac2(struct es1370_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
+               tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
+                       / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
                tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
+               if (!schedule_timeout(tmo + 1))
                        DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
@@ -2049,6 +2075,7 @@ static /*const*/ struct file_operations es1370_dac_fops = {
 static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
        struct es1370_state *s = (struct es1370_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -2059,7 +2086,10 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l
                return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.ird;
@@ -2070,15 +2100,25 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.iwait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIINBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.ird = ptr;
@@ -2087,13 +2127,17 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l
                count -= cnt;
                buffer += cnt;
                ret += cnt;
+               break;
        }
+       current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.iwait, &wait);
        return ret;
 }
 
 static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
        struct es1370_state *s = (struct es1370_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -2104,7 +2148,10 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c
                return -ESPIPE;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.owr;
@@ -2117,15 +2164,25 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.owait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIOUTBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.owr = ptr;
@@ -2138,6 +2195,8 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c
                es1370_handle_midi(s);
                spin_unlock_irqrestore(&s->lock, flags);
        }
+       current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.owait, &wait);
        return ret;
 }
 
@@ -2217,7 +2276,7 @@ static int es1370_midi_open(struct inode *inode, struct file *file)
 static int es1370_midi_release(struct inode *inode, struct file *file)
 {
        struct es1370_state *s = (struct es1370_state *)file->private_data;
-        struct wait_queue wait = { current, NULL };
+       struct wait_queue wait = { current, NULL };
        unsigned long flags;
        unsigned count, tmo;
 
@@ -2321,7 +2380,7 @@ __initfunc(int init_es1370(void))
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "es1370: version v0.30 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
                if (pcidev->base_address[0] == 0 || 
@@ -2341,6 +2400,7 @@ __initfunc(int init_es1370(void))
                init_waitqueue(&s->midi.iwait);
                init_waitqueue(&s->midi.owait);
                s->open_sem = MUTEX;
+               spin_lock_init(&s->lock);
                s->magic = ES1370_MAGIC;
                s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
                s->irq = pcidev->irq;
@@ -2385,6 +2445,10 @@ __initfunc(int init_es1370(void))
                /* initialize the chips */
                outl(s->ctrl, s->io+ES1370_REG_CONTROL);
                outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+               /* point phantom write channel to "bugbuf" */
+               outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+               outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
+               outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
                pci_set_master(pcidev);  /* enable bus mastering */
                wrcodec(s, 0x16, 3); /* no RST, PD */
                wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
index cc7dfadfa951e89acf4e6ff5b721bf73cc671794..68c3a34af10d0a9bdc6dcadb3c99d84e1acaabba 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
  *    15.06.99   0.12  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.13  Add pci_set_master
- *    21.07.99   0.14  S/PDIF module option for cards revision >= 4. Initial version
- *                     by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *    03.08.99   0.14  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1371=joystickaddr"
+ *                     removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
+ *    10.08.99   0.15  (Re)added S/PDIF module option for cards revision >= 4.
+ *                     Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *                     module_init/__setup fixes
+ *    08.16.99   0.16  Joe Cotellese <joec@ensoniq.com>
+ *                     Added detection for ES1371 revision ID so that we can
+ *                     detect the ES1373 and later parts.
+ *                     added AC97 #defines for readability
+ *                     added a /proc file system for dumping hardware state
+ *                     updated SRC and CODEC w/r functions to accomodate bugs
+ *                     in some versions of the ES137x chips.
+ *    31.08.99   0.17  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.18  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    21.10.99   0.19  Round sampling rates, requested by
+ *                     Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include "ac97.h"
 
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
+#undef ES1371_DEBUG
 
 /* --------------------------------------------------------------------- */
 
 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
 #endif
 
+/* ES1371 chip ID */
+/* This is a little confusing because all ES1371 compatible chips have the
+   same DEVICE_ID, the only thing differentiating them is the REV_ID field.
+   This is only significant if you want to enable features on the later parts.
+   Yes, I know it's stupid and why didn't we use the sub IDs?
+*/
+#define ES1371REV_ES1373_A  0x04
+#define ES1371REV_ES1373_B  0x06
+#define ES1371REV_CT5880_A  0x07
+#define ES1371REV_ES1371_B  0x09
+
+
 #define ES1371_MAGIC  ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
 
 #define ES1371_EXTENT             0x40
@@ -206,14 +239,22 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 #define UCTRL_CNTRL_SWR 0x03        /* software reset command */
 
 /* sample rate converter */
+#define SRC_OKSTATE        1
+
 #define SRC_RAMADDR_MASK   0xfe000000
 #define SRC_RAMADDR_SHIFT  25
+#define SRC_DAC1FREEZE     (1UL << 21)
+#define SRC_DAC2FREEZE      (1UL << 20)
+#define SRC_ADCFREEZE      (1UL << 19)
+
+
 #define SRC_WE             0x01000000  /* read/write control for SRC RAM */
 #define SRC_BUSY           0x00800000  /* SRC busy */
 #define SRC_DIS            0x00400000  /* 1 = disable SRC */
 #define SRC_DDAC1          0x00200000  /* 1 = disable accum update for DAC1 */
 #define SRC_DDAC2          0x00100000  /* 1 = disable accum update for DAC2 */
 #define SRC_DADC           0x00080000  /* 1 = disable accum update for ADC2 */
+#define SRC_CTLMASK        0x00780000
 #define SRC_RAMDATA_MASK   0x0000ffff
 #define SRC_RAMDATA_SHIFT  0
 
@@ -293,7 +334,7 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
 
 /* misc stuff */
-
+#define POLL_COUNT   0x1000
 #define FMODE_DAC         4           /* slight misuse of mode_t */
 
 /* MIDI buffer sizes */
@@ -352,8 +393,13 @@ struct es1371_state {
        /* hardware resources */
        unsigned long io; /* long for SPARC */
        unsigned int irq;
-
-       /* mixer registers; there is no HW readback */
+        u8 rev; /* the chip revision */
+        
+#ifdef ES1371_DEBUG
+        /* debug /proc entry */
+       struct proc_dir_entry *ps;
+#endif /* ES1371_DEBUG */
+        /* mixer registers; there is no HW readback */
        struct {
                unsigned short codec_id;
                unsigned int modcnt;
@@ -437,32 +483,13 @@ extern inline unsigned ld2(unsigned int x)
        return r;
 }
 
-/* --------------------------------------------------------------------- */
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
 /* --------------------------------------------------------------------- */
 
 static unsigned wait_src_ready(struct es1371_state *s)
 {
        unsigned int t, r;
 
-       for (t = 0; t < 1000; t++) {
+       for (t = 0; t < POLL_COUNT; t++) {
                if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY))
                        return r;
                udelay(1);
@@ -473,29 +500,53 @@ static unsigned wait_src_ready(struct es1371_state *s)
 
 static unsigned src_read(struct es1371_state *s, unsigned reg)
 {
-       unsigned int r;
+        unsigned int temp,i,orig;
+
+        /* wait for ready */
+        temp = wait_src_ready (s);
+
+        /* we can only access the SRC at certain times, make sure
+           we're allowed to before we read */
+           
+        orig = temp;
+        /* expose the SRC state bits */
+        outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL,
+               s->io + ES1371_REG_SRCONV);
+
+        /* now, wait for busy and the correct time to read */
+        temp = wait_src_ready (s);
+
+        if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){
+                /* wait for the right state */
+                for (i=0; i<POLL_COUNT; i++){
+                        temp = inl (s->io + ES1371_REG_SRCONV);
+                        if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 ))
+                                break;
+                }
+        }
 
-       r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
-       r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
-       outl(r, s->io + ES1371_REG_SRCONV);
-       return (wait_src_ready(s) & SRC_RAMDATA_MASK) >> SRC_RAMDATA_SHIFT;
+        /* hide the state bits */
+        outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV);
+        return temp;
+                        
+                
 }
 
-
 static void src_write(struct es1371_state *s, unsigned reg, unsigned data)
 {
+      
        unsigned int r;
 
        r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
        r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
        r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK;
        outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);
+
 }
 
 /* --------------------------------------------------------------------- */
 
 /* most of the following here is black magic */
-
 static void set_adc_rate(struct es1371_state *s, unsigned rate)
 {
        unsigned long flags;
@@ -532,6 +583,7 @@ static void set_adc_rate(struct es1371_state *s, unsigned rate)
        spin_unlock_irqrestore(&s->lock, flags);
 }
 
+
 static void set_dac1_rate(struct es1371_state *s, unsigned rate)
 {
        unsigned long flags;
@@ -541,8 +593,8 @@ static void set_dac1_rate(struct es1371_state *s, unsigned rate)
                rate = 48000;
        if (rate < 4000)
                rate = 4000;
-        freq = (rate << 15) / 3000;
-       s->dac1rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+       s->dac1rate = (freq * 3000 + 16384) >> 15;
        spin_lock_irqsave(&s->lock, flags);
        r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1;
        outl(r, s->io + ES1371_REG_SRCONV);
@@ -564,8 +616,8 @@ static void set_dac2_rate(struct es1371_state *s, unsigned rate)
                rate = 48000;
        if (rate < 4000)
                rate = 4000;
-        freq = (rate << 15) / 3000;
-       s->dac2rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+       s->dac2rate = (freq * 3000 + 16384) >> 15;
        spin_lock_irqsave(&s->lock, flags);
        r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
        outl(r, s->io + ES1371_REG_SRCONV);
@@ -580,26 +632,80 @@ static void set_dac2_rate(struct es1371_state *s, unsigned rate)
 
 /* --------------------------------------------------------------------- */
 
+static void __init src_init(struct es1371_state *s)
+{
+        unsigned int i;
+
+        /* before we enable or disable the SRC we need
+           to wait for it to become ready */
+        wait_src_ready(s);
+
+        outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
+
+        for (i = 0; i < 0x80; i++)
+                src_write(s, i, 0);
+
+        src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_VOL_ADC, 1 << 12);
+        src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
+        set_adc_rate(s, 22050);
+        set_dac1_rate(s, 22050);
+        set_dac2_rate(s, 22050);
+
+        /* WARNING:
+         * enabling the sample rate converter without properly programming
+         * its parameters causes the chip to lock up (the SRC busy bit will
+         * be stuck high, and I've found no way to rectify this other than
+         * power cycle)
+         */
+        wait_src_ready(s);
+        outl(0, s->io+ES1371_REG_SRCONV);
+}
+
+/* --------------------------------------------------------------------- */
+
 static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data)
 {
        unsigned long flags;
        unsigned t, x;
-
-       for (t = 0; t < 0x1000; t++)
+        
+       for (t = 0; t < POLL_COUNT; t++)
                if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
                        break;
        spin_lock_irqsave(&s->lock, flags);
-       /* save the current state for later */
-       x = inl(s->io+ES1371_REG_SRCONV);
-       /* enable SRC state data in SRC mux */
-       outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
+
+        /* save the current state for later */
+        x = wait_src_ready(s);
+
+        /* enable SRC state data in SRC mux */
+       outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
             s->io+ES1371_REG_SRCONV);
-       /* wait for a SAFE time to write addr/data and then do it, dammit */
-       for (t = 0; t < 0x1000; t++)
-               if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-                       break;
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
        outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) |
             ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC);
+
        /* restore SRC reg */
        wait_src_ready(s);
        outl(x, s->io+ES1371_REG_SRCONV);
@@ -611,28 +717,50 @@ static unsigned rdcodec(struct es1371_state *s, unsigned addr)
        unsigned long flags;
        unsigned t, x;
 
+        /* wait for WIP to go away */
        for (t = 0; t < 0x1000; t++)
                if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
                        break;
        spin_lock_irqsave(&s->lock, flags);
+
        /* save the current state for later */
-       x = inl(s->io+ES1371_REG_SRCONV);
+       x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC));
+
        /* enable SRC state data in SRC mux */
-       outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
-            s->io+ES1371_REG_SRCONV);
-       /* wait for a SAFE time to write addr/data and then do it, dammit */
-       for (t = 0; t < 0x1000; t++)
-               if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-                       break;
+       outl( x | 0x00010000,
+              s->io+ES1371_REG_SRCONV);
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
        outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC);
        /* restore SRC reg */
        wait_src_ready(s);
        outl(x, s->io+ES1371_REG_SRCONV);
        spin_unlock_irqrestore(&s->lock, flags);
-       /* now wait for the stinkin' data (RDY) */
+
+        /* wait for WIP again */
        for (t = 0; t < 0x1000; t++)
+               if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
+                       break;
+        
+       /* now wait for the stinkin' data (RDY) */
+       for (t = 0; t < POLL_COUNT; t++)
                if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY)
                        break;
+        
        return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);
 }
 
@@ -993,6 +1121,21 @@ static const char invalid_magic[] = KERN_CRIT "es1371: invalid magic value\n";
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * AC97 Mixer Register to Connections mapping of the Concert 97 board
+ *
+ * AC97_MASTER_VOL_STEREO   Line Out
+ * AC97_MASTER_VOL_MONO     TAD Output
+ * AC97_PCBEEP_VOL          none
+ * AC97_PHONE_VOL           TAD Input (mono)
+ * AC97_MIC_VOL             MIC Input (mono)
+ * AC97_LINEIN_VOL          Line Input (stereo)
+ * AC97_CD_VOL              CD Input (stereo)
+ * AC97_VIDEO_VOL           none
+ * AC97_AUX_VOL             Aux Input (stereo)
+ * AC97_PCMOUT_VOL          Wave Output (stereo)
+ */
+
 #define AC97_PESSIMISTIC
 
 /*
@@ -1018,25 +1161,25 @@ static const unsigned int recsrc[8] =
 static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = 
 {
        /* 5 bit stereo */
-       [SOUND_MIXER_LINE] = 0x10,
-       [SOUND_MIXER_CD] = 0x12,
-       [SOUND_MIXER_VIDEO] = 0x14,
-       [SOUND_MIXER_LINE1] = 0x16,
-       [SOUND_MIXER_PCM] = 0x18,
+       [SOUND_MIXER_LINE] = AC97_LINEIN_VOL,
+       [SOUND_MIXER_CD] = AC97_CD_VOL,
+       [SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL,
+       [SOUND_MIXER_LINE1] = AC97_AUX_VOL,
+       [SOUND_MIXER_PCM] = AC97_PCMOUT_VOL,
        /* 6 bit stereo */
-       [SOUND_MIXER_VOLUME] = 0x02,
-       [SOUND_MIXER_PHONEOUT] = 0x04,
+       [SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO,
+       [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL,
        /* 6 bit mono */
-       [SOUND_MIXER_OGAIN] = 0x06,
-       [SOUND_MIXER_PHONEIN] = 0x0c,
+       [SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO,
+       [SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL,
        /* 4 bit mono but shifted by 1 */
-       [SOUND_MIXER_SPEAKER] = 0x08,
+       [SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE,
        /* 6 bit mono + preamp */
-       [SOUND_MIXER_MIC] = 0x0e,
+       [SOUND_MIXER_MIC] = AC97_MIC_VOL,
        /* 4 bit stereo */
-       [SOUND_MIXER_RECLEV] = 0x1c,
+       [SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN,
        /* 4 bit mono */
-       [SOUND_MIXER_IGAIN] = 0x1e
+       [SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
 };
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -1049,8 +1192,8 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
 
        switch (ch) {
        case SOUND_MIXER_MIC:
-               j = rdcodec(s, 0x0e);
-               if (j & 0x8000)
+               j = rdcodec(s, AC97_MIC_VOL);
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
                return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg);
@@ -1061,7 +1204,7 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
        case SOUND_MIXER_OGAIN:
        case SOUND_MIXER_PHONEIN:
                j = rdcodec(s, volreg[ch]);
-               if (j & 0x8000)
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
                return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg);
@@ -1075,7 +1218,7 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
                /* fall through */
        case SOUND_MIXER_VOLUME:
                j = rdcodec(s, volreg[ch]);
-               if (j & 0x8000)
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
                return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
@@ -1084,8 +1227,8 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
 #endif /* AC97_PESSIMISTIC */
                
        case SOUND_MIXER_SPEAKER:
-               j = rdcodec(s, 0x0a);
-               if (j & 0x8000)
+               j = rdcodec(s, AC97_PCBEEP_VOL);
+               if (j & AC97_MUTE
                        return put_user(0, (int *)arg);
                return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
                
@@ -1095,7 +1238,7 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
        case SOUND_MIXER_LINE1:
        case SOUND_MIXER_PCM:
                j = rdcodec(s, volreg[ch]);
-               if (j & 0x8000)
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
                return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
 
@@ -1103,23 +1246,23 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
        case SOUND_MIXER_TREBLE:
                if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE))
                        return -EINVAL;
-               j = rdcodec(s, 0x08);
+               j = rdcodec(s, AC97_MASTER_TONE);
                if (ch == SOUND_MIXER_BASS)
                        j >>= 8;
                return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg);
        
                /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
        case SOUND_MIXER_RECLEV:
-               j = rdcodec(s, 0x1c);
-               if (j & 0x8000)
+               j = rdcodec(s, AC97_RECORD_GAIN);
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
                return put_user((swab(j)  & 0xf0f) * 6 + 0xa0a, (int *)arg);
                
        case SOUND_MIXER_IGAIN:
                if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
                        return -EINVAL;
-               j = rdcodec(s, 0x1e);
-               if (j & 0x8000)
+               j = rdcodec(s, AC97_RECORD_GAIN_MIC);
+               if (j & AC97_MUTE)
                        return put_user(0, (int *)arg);
                return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg);
        
@@ -1174,7 +1317,7 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
        case SOUND_MIXER_LINE1:
        case SOUND_MIXER_PCM:
                if (l1 < 7 && r1 < 7) {
-                       wrcodec(s, volreg[ch], 0x8000);
+                       wrcodec(s, volreg[ch], AC97_MUTE);
                        return 0;
                }
                if (l1 < 7)
@@ -1191,7 +1334,7 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
        case SOUND_MIXER_VOLUME:
 #ifdef AC97_PESSIMISTIC
                if (l1 < 7 && r1 < 7) {
-                       wrcodec(s, volreg[ch], 0x8000);
+                       wrcodec(s, volreg[ch], AC97_MUTE);
                        return 0;
                }
                if (l1 < 7)
@@ -1202,7 +1345,7 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
                return 0;
 #else /* AC97_PESSIMISTIC */
                if (l1 < 4 && r1 < 4) {
-                       wrcodec(s, volreg[ch], 0x8000);
+                       wrcodec(s, volreg[ch], AC97_MUTE);
                        return 0;
                }
                if (l1 < 4)
@@ -1216,21 +1359,21 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
        case SOUND_MIXER_OGAIN:
        case SOUND_MIXER_PHONEIN:
 #ifdef AC97_PESSIMISTIC
-               wrcodec(s, volreg[ch], (l1 < 7) ? 0x8000 : (100 - l1) / 3);
+               wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3);
                return 0;
 #else /* AC97_PESSIMISTIC */
-               wrcodec(s, volreg[ch], (l1 < 4) ? 0x8000 : (2 * (100 - l1) / 3));
+               wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3));
                return 0;
 #endif /* AC97_PESSIMISTIC */
                        
        case SOUND_MIXER_SPEAKER:
-               wrcodec(s, 0x0a, (l1 < 10) ? 0x8000 : ((100 - l1) / 6) << 1);
+               wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1);
                return 0;
 
        case SOUND_MIXER_MIC:
 #ifdef AC97_PESSIMISTIC
                if (l1 < 11) {
-                       wrcodec(s, 0x0e, 0x8000);
+                       wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
                        return 0;
                }
                i = 0;
@@ -1240,11 +1383,11 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
                }
                if (l1 < 11) 
                        l1 = 11;
-               wrcodec(s, 0x0e, ((73 - l1) / 2) | i);
+               wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i);
                return 0;
 #else /* AC97_PESSIMISTIC */
                if (l1 < 9) {
-                       wrcodec(s, 0x0e, 0x8000);
+                       wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
                        return 0;
                }
                i = 0;
@@ -1254,37 +1397,37 @@ static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
                }
                if (l1 < 9) 
                        l1 = 9;
-               wrcodec(s, 0x0e, (((87 - l1) * 4) / 5) | i);
+               wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i);
                return 0;
 #endif /* AC97_PESSIMISTIC */
                
        case SOUND_MIXER_BASS:
                val = ((l1 * 15) / 100) & 0xf;
-               wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0x00ff) | (val << 8));
+               wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8));
                return 0;
 
        case SOUND_MIXER_TREBLE:
                val = ((l1 * 15) / 100) & 0xf;
-               wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0xff00) | val);
+               wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val);
                return 0;
                
                /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
        case SOUND_MIXER_RECLEV:
                if (l1 < 10 || r1 < 10) {
-                       wrcodec(s, 0x1c, 0x8000);
+                       wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE);
                        return 0;
                }
                if (l1 < 10)
                        l1 = 10;
                if (r1 < 10)
                        r1 = 10;
-               wrcodec(s, 0x1c, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
+               wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
                return 0;
 
        case SOUND_MIXER_IGAIN:
                if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
                        return -EINVAL;
-               wrcodec(s, 0x1e, (l1 < 10) ? 0x8000 : ((l1 - 10) / 6) & 0xf);
+               wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf);
                return 0;
                
        default:
@@ -1302,8 +1445,8 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a
                        return -EINVAL;
                get_user_ret(val, (int *)arg, -EFAULT);
                if (val & 1)
-                       wrcodec(s, 0x22, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
-               val = rdcodec(s, 0x22);
+                       wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
+               val = rdcodec(s, AC97_3D_CONTROL);
                return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg);
        }
         if (cmd == SOUND_MIXER_INFO) {
@@ -1330,7 +1473,7 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a
         if (_IOC_DIR(cmd) == _IOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-                       return put_user(recsrc[rdcodec(s, 0x1a) & 7], (int *)arg);
+                       return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg);
                        
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
                        return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
@@ -1377,10 +1520,10 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a
                 if (i == 0)
                         return 0; /*val = mixer_recmask(s);*/
                 else if (i > 1) 
-                        val &= ~recsrc[rdcodec(s, 0x1a) & 7];
+                        val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7];
                 for (i = 0; i < 8; i++) {
                        if (val & recsrc[i]) {
-                               wrcodec(s, 0x1a, 0x101 * i);
+                               wrcodec(s, AC97_RECORD_SELECT, 0x101 * i);
                                return 0;
                        }
                }
@@ -1485,10 +1628,10 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / s->dac1rate;
+               tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
                tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
-                       printk(KERN_DEBUG "es1371: dma timed out??\n");
+               if (!schedule_timeout(tmo + 1))
+                       printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1520,10 +1663,10 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / s->dac2rate;
+               tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
                tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
-                       printk(KERN_DEBUG "es1371: dma timed out??\n");
+               if (!schedule_timeout(tmo + 1))
+                       printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2467,6 +2610,7 @@ static /*const*/ struct file_operations es1371_dac_fops = {
 static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
        struct es1371_state *s = (struct es1371_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -2477,7 +2621,10 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l
                return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.ird;
@@ -2488,15 +2635,25 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.iwait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIINBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.ird = ptr;
@@ -2505,13 +2662,17 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l
                count -= cnt;
                buffer += cnt;
                ret += cnt;
+               break;
        }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&s->midi.iwait, &wait);
        return ret;
 }
 
 static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
        struct es1371_state *s = (struct es1371_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -2522,7 +2683,10 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c
                return -ESPIPE;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.owr;
@@ -2535,15 +2699,25 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.owait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIOUTBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.owr = ptr;
@@ -2556,6 +2730,8 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c
                es1371_handle_midi(s);
                spin_unlock_irqrestore(&s->lock, flags);
        }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&s->midi.owait, &wait);
        return ret;
 }
 
@@ -2697,6 +2873,44 @@ static /*const*/ struct file_operations es1371_midi_fops = {
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * for debugging purposes, we'll create a proc device that dumps the
+ *  CODEC chipstate
+ */
+
+#ifdef ES1371_DEBUG
+static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+        int len = 0;
+
+        struct es1371_state *s = devs;
+        int cnt;
+
+        /* print out header */
+        len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
+
+        /* print out CODEC state */
+        len += sprintf (buf + len, "AC97 CODEC state\n");
+        
+        for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+                len+= sprintf (buf + len, "reg:0x%02x  val:0x%04x\n", cnt, rdcodec(s , cnt));
+                
+        if (fpos >=len){
+                *start = buf;
+                *eof =1;
+                return 0;
+        }
+        *start = buf + fpos;
+        if ((len -= fpos) > length)
+                return length;
+        *eof =1;
+        return len;
+
+}
+#endif /* ES1371_DEBUG */
+
+/* --------------------------------------------------------------------- */
+
 /* maximum number of devices */
 #define NR_DEVICE 5
 
@@ -2740,12 +2954,11 @@ __initfunc(int init_es1371(void))
        struct pci_dev *pcidev = NULL;
        mm_segment_t fs;
        int i, val, val2, index = 0;
-       u8 revision;
        unsigned cssr;
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "es1371: version v0.19 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
                if (pcidev->base_address[0] == 0 || 
@@ -2765,9 +2978,11 @@ __initfunc(int init_es1371(void))
                init_waitqueue(&s->midi.iwait);
                init_waitqueue(&s->midi.owait);
                s->open_sem = MUTEX;
+               spin_lock_init(&s->lock);
                s->magic = ES1371_MAGIC;
                s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
                s->irq = pcidev->irq;
+               pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
                if (check_region(s->io, ES1371_EXTENT)) {
                        printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
                        goto err_region;
@@ -2788,6 +3003,13 @@ __initfunc(int init_es1371(void))
                        goto err_dev3;
                if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
                        goto err_dev4;
+#ifdef ES1371_DEBUG
+                /* intialize the debug proc device */
+                s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
+                if (s->ps)
+                        s->ps->read_proc = proc_es1371_dump;
+#endif /* ES1371_DEBUG */
+
                /* initialize codec registers */
                s->ctrl = 0;
                if ((joystick[index] & ~0x18) == 0x200) {
@@ -2800,14 +3022,13 @@ __initfunc(int init_es1371(void))
                s->sctrl = 0;
                cssr = 0;
                /* check to see if s/pdif mode is being requested */
-               pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision);
                if (spdif[index]) {
-                       if (revision >= 4) {
+                       if (s->rev >= 4) {
                                printk(KERN_INFO "es1371: enabling S/PDIF output\n");
                                cssr |= STAT_EN_SPDIF;
                                s->ctrl |= CTRL_SPDIFEN_B;
                        } else {
-                               printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", revision);
+                               printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
                        }
                }
                /* initialize the chips */
@@ -2820,35 +3041,12 @@ __initfunc(int init_es1371(void))
                udelay(2);
                outl(s->ctrl, s->io+ES1371_REG_CONTROL);
                /* init the sample rate converter */
-               outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
-               for (val = 0; val < 0x80; val++)
-                       src_write(s, val, 0);
-               src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
-               src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
-               src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
-               src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
-               src_write(s, SRCREG_VOL_ADC, 1 << 12);
-               src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
-               src_write(s, SRCREG_VOL_DAC1, 1 << 12);
-               src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
-               src_write(s, SRCREG_VOL_DAC2, 1 << 12);
-               src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
-               set_adc_rate(s, 22050);
-               set_dac1_rate(s, 22050);
-               set_dac2_rate(s, 22050);
-               /* WARNING:
-                * enabling the sample rate converter without properly programming
-                * its parameters causes the chip to lock up (the SRC busy bit will
-                * be stuck high, and I've found no way to rectify this other than
-                * power cycle)
-                */
-               wait_src_ready(s);
-               outl(0, s->io+ES1371_REG_SRCONV);
+                src_init(s);
                /* codec init */
-               wrcodec(s, 0x00, 0); /* reset codec */
-               s->mix.codec_id = rdcodec(s, 0x00);  /* get codec ID */
-               val = rdcodec(s, 0x7c);
-               val2 = rdcodec(s, 0x7e);
+               wrcodec(s, AC97_RESET, 0); /* reset codec */
+               s->mix.codec_id = rdcodec(s, AC97_RESET);  /* get codec ID */
+               val = rdcodec(s, AC97_VENDOR_ID1);
+               val2 = rdcodec(s, AC97_VENDOR_ID2);
                printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n", 
                       (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff);
                printk(KERN_INFO "es1371: codec features");
@@ -2875,6 +3073,7 @@ __initfunc(int init_es1371(void))
                printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
                val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
                printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown");
+
                fs = get_fs();
                set_fs(KERNEL_DS);
                val = SOUND_MASK_LINE;
@@ -2929,6 +3128,10 @@ void cleanup_module(void)
 
        while ((s = devs)) {
                devs = devs->next;
+#ifdef ES1371_DEBUG
+               if (s->ps)
+                       remove_proc_entry("es1371", NULL);
+#endif /* ES1371_DEBUG */
                outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
                outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
                synchronize_irq();
index c39fc95cc8725ba64e9331d8fda7e5a91caf7eea..6b602e77f6b0c9315442f6c8c8328c8c226171a9 100644 (file)
  *                     The fun part is that the Windows Solo1 driver doesn't
  *                     seem to do these tricks.
  *                     Bugs remaining: plops and clicks when starting/stopping playback
+ *    31.08.99   0.7   add spin_lock_init
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.8   change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    07.10.99   0.9   Fix initialization; complain if sequencer writes time out
+ *                     Revised resource grabbing for the FM synthesizer
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
 
 #define SOLO1_MAGIC  ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
 
-#define DDMABASE_OFFSET           0x10    /* chip bug workaround kludge */
+#define DDMABASE_OFFSET           0    /* chip bug workaround kludge */
 #define DDMABASE_EXTENT           16
 
 #define IOBASE_EXTENT             16
 #define MPUBASE_EXTENT            4
 #define GPBASE_EXTENT             4
 
+#define FMSYNTH_EXTENT            4
 
 /* MIDI buffer sizes */
 
 #define wait_queue_head_t struct wait_queue *
 #define init_waitqueue_head(w) *(w) = 0
 #define init_MUTEX(m) *(m) = MUTEX
+#define __set_current_state(x) do { current->state = (x); } while (0)
+#define set_current_state(x) __set_current_state(x)
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -226,7 +234,7 @@ extern inline void write_seq(struct solo1_state *s, unsigned char data)
 {
         int i;
        unsigned long flags;
-        
+
        /* the __cli stunt is to send the data within the command window */
         for (i = 0; i < 0xffff; i++) {
                __save_flags(flags);
@@ -238,6 +246,8 @@ extern inline void write_seq(struct solo1_state *s, unsigned char data)
                 }
                __restore_flags(flags);
        }
+       printk(KERN_ERR "esssolo1: write_seq timeout\n");
+       outb(data, s->sbbase+0xc);
 }
 
 extern inline int read_seq(struct solo1_state *s, unsigned char *data)
@@ -251,6 +261,7 @@ extern inline int read_seq(struct solo1_state *s, unsigned char *data)
                         *data = inb(s->sbbase+0xa);
                         return 1;
                 }
+       printk(KERN_ERR "esssolo1: read_seq timeout\n");
         return 0;
 }
 
@@ -952,7 +963,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
        
        if (s->dma_dac.mapped)
                return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -964,7 +975,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
                tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
@@ -976,7 +987,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
                         printk(KERN_DEBUG "solo1: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1622,6 +1633,7 @@ static void solo1_midi_timer(unsigned long data)
 static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
+       DECLARE_WAITQUEUE(wait, current);
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -1632,7 +1644,10 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo
                return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+       add_wait_queue(&s->midi.iwait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.ird;
@@ -1643,15 +1658,25 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.iwait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIINBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.ird = ptr;
@@ -1660,13 +1685,17 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo
                count -= cnt;
                buffer += cnt;
                ret += cnt;
+               break;
        }
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&s->midi.iwait, &wait);
        return ret;
 }
 
 static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
+       DECLARE_WAITQUEUE(wait, current);
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -1677,7 +1706,10 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co
                return -ESPIPE;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.owr;
@@ -1690,15 +1722,25 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.owait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIOUTBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.owr = ptr;
@@ -1711,6 +1753,8 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co
                solo1_handle_midi(s);
                spin_unlock_irqrestore(&s->lock, flags);
        }
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&s->midi.owait, &wait);
        return ret;
 }
 
@@ -1979,6 +2023,12 @@ static int solo1_dmfm_open(struct inode *inode, struct file *file)
                        return -ERESTARTSYS;
                down(&s->open_sem);
        }
+       if (check_region(s->sbbase, FMSYNTH_EXTENT)) {
+               up(&s->open_sem);
+               printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+               return -EBUSY;
+       }
+       request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1");
        /* init the stuff */
        outb(1, s->sbbase);
        outb(0x20, s->sbbase+1); /* enable waveforms */
@@ -2006,6 +2056,7 @@ static int solo1_dmfm_release(struct inode *inode, struct file *file)
                outb(regb, s->sbbase+2);
                outb(0, s->sbbase+3);
        }
+       release_region(s->sbbase, FMSYNTH_EXTENT);
        up(&s->open_sem);
        wake_up(&s->open_wait);
        MOD_DEC_USE_COUNT;
@@ -2062,7 +2113,7 @@ static struct initvol {
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "solo1: version v0.9 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
                if (pcidev->base_address[0] == 0 ||
@@ -2087,6 +2138,7 @@ static struct initvol {
                init_waitqueue_head(&s->midi.iwait);
                init_waitqueue_head(&s->midi.owait);
                init_MUTEX(&s->open_sem);
+               spin_lock_init(&s->lock);
                s->magic = SOLO1_MAGIC;
                s->pcidev = pcidev;
                s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2097,14 +2149,14 @@ static struct initvol {
                s->gpbase = pcidev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
                s->irq = pcidev->irq;
                if (check_region(s->iobase, IOBASE_EXTENT) ||
-                   check_region(s->sbbase+4, SBBASE_EXTENT-4) ||
+                   check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
                    check_region(s->ddmabase, DDMABASE_EXTENT) ||
                    check_region(s->mpubase, MPUBASE_EXTENT)) {
                        printk(KERN_ERR "solo1: io ports in use\n");
                        goto err_region;
                }
                request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
-               request_region(s->sbbase+4, SBBASE_EXTENT-4, "ESS Solo1");  /* allow OPL3 synth module */
+               request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");  /* allow OPL3 synth module */
                request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
                request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
                if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
@@ -2131,6 +2183,10 @@ static struct initvol {
                if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
                        goto err_dev4;
                /* initialize the chips */
+               if (!reset_ctrl(s)) {
+                       printk(KERN_ERR "esssolo1: cannot reset controller\n");
+                       goto err;
+               }
                outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
 
                /* initialize mixer regs */
@@ -2165,6 +2221,8 @@ static struct initvol {
                index++;
                continue;
 
+       err:
+               unregister_sound_dsp(s->dev_dmfm);
        err_dev4:
                unregister_sound_dsp(s->dev_midi);
        err_dev3:
@@ -2176,7 +2234,7 @@ static struct initvol {
                free_irq(s->irq, s);
        err_irq:
                release_region(s->iobase, IOBASE_EXTENT);
-               release_region(s->sbbase+4, SBBASE_EXTENT-4);
+               release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
                release_region(s->ddmabase, DDMABASE_EXTENT);
                release_region(s->mpubase, MPUBASE_EXTENT);
        err_region:
@@ -2206,7 +2264,7 @@ static void __exit cleanup_solo1(void)
                pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
                free_irq(s->irq, s);
                release_region(s->iobase, IOBASE_EXTENT);
-               release_region(s->sbbase+4, SBBASE_EXTENT-4);
+               release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
                release_region(s->ddmabase, DDMABASE_EXTENT);
                release_region(s->mpubase, MPUBASE_EXTENT);
                unregister_sound_dsp(s->dev_audio);
@@ -2223,4 +2281,3 @@ static void __exit cleanup_solo1(void)
 module_init(init_solo1);
 module_exit(cleanup_solo1);
 
-
index 9d64eaa1e36054ae72d02a75381087ffa55c8c06..f3547adf2b64f2c58c6dee3b022d9b7b458002f7 100644 (file)
@@ -1,6 +1,11 @@
+#ifdef CONFIG_ACI_MIXER
 extern int aci_implied_cmd(unsigned char opcode);
 extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
 extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
 extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
 extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
+#else
 
+#error Compiling a driver that needs the ACI-mixer but without ACI-mixer support
+
+#endif
index c70d8d94d0ac634bb0251907e6a3b18e5fcb7e3f..962f20e02a00c68209bb413520ecd9e2dc9ab05c 100644 (file)
@@ -46,6 +46,7 @@
 #  include <linux/init.h>
 #endif
 #include <asm/irq.h>
+#include <asm/io.h>
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
index bbdd483d298d701edca917d9756248c3dae96bf4..387c44416da9c8ee1b3ee45e81ec13affd06599f 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/delay.h>
+
 #include "sound_config.h"
 #include "soundmodule.h"
 #include "nm256.h"
index 8898c655a15f1beafc25f8009f6a9ea6ae0a0ceb..a36909b93584849bb812b36c26d2327ee1509ca2 100644 (file)
@@ -32,8 +32,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 #include "opl3.h"
 
 #define MAX_VOICE      18
@@ -1223,5 +1221,3 @@ void cleanup_module(void)
 EXPORT_SYMBOL(opl3_init);
 EXPORT_SYMBOL(opl3_detect);
 MODULE_PARM(io, "i");
-
-#endif
index cdf4a6955286c428d516b00780ee0cd27e55c50b..d9c710e596f5f07667e8537f228973126fa386e1 100644 (file)
  *    15.06.99   0.15  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.16  Add pci_set_master
+ *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+ *    12.08.99   0.18  module_init/__setup fixes
+ *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.99   0.20  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.21  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -1265,9 +1273,9 @@ static int drain_dac(struct sv_state *s, int nonblock)
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-               tmo = (count * HZ) / s->ratedac;
+               tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
                tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
-               if (!schedule_timeout(tmo ? : 1) && tmo)
+               if (!schedule_timeout(tmo + 1))
                        printk(KERN_DEBUG "sv: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
@@ -1870,6 +1878,7 @@ static /*const*/ struct file_operations sv_audio_fops = {
 static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
        struct sv_state *s = (struct sv_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -1880,7 +1889,10 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_
                return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+       add_wait_queue(&s->midi.iwait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.ird;
@@ -1891,15 +1903,25 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.iwait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                      if (file->f_flags & O_NONBLOCK) {
+                              if (!ret)
+                                      ret = -EAGAIN;
+                              break;
+                      }
+                      current->state = TASK_INTERRUPTIBLE;
+                      schedule();
+                      if (signal_pending(current)) {
+                              if (!ret)
+                                      ret = -ERESTARTSYS;
+                              break;
+                      }
                        continue;
                }
-               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIINBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.ird = ptr;
@@ -1908,13 +1930,17 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_
                count -= cnt;
                buffer += cnt;
                ret += cnt;
+               break;
        }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&s->midi.iwait, &wait);
        return ret;
 }
 
 static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
        struct sv_state *s = (struct sv_state *)file->private_data;
+       struct wait_queue wait = { current, NULL };
        ssize_t ret;
        unsigned long flags;
        unsigned ptr;
@@ -1925,7 +1951,10 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count
                return -ESPIPE;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
+       if (count == 0)
+               return 0;
        ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
        while (count > 0) {
                spin_lock_irqsave(&s->lock, flags);
                ptr = s->midi.owr;
@@ -1938,15 +1967,25 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count
                if (cnt > count)
                        cnt = count;
                if (cnt <= 0) {
-                       if (file->f_flags & O_NONBLOCK)
-                               return ret ? ret : -EAGAIN;
-                       interruptible_sleep_on(&s->midi.owait);
-                       if (signal_pending(current))
-                               return ret ? ret : -ERESTARTSYS;
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               break;
+                       }
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule();
+                       if (signal_pending(current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
                        continue;
                }
-               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-                       return ret ? ret : -EFAULT;
+               if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+                       if (!ret)
+                               ret = -EFAULT;
+                       break;
+               }
                ptr = (ptr + cnt) % MIDIOUTBUF;
                spin_lock_irqsave(&s->lock, flags);
                s->midi.owr = ptr;
@@ -1959,6 +1998,8 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count
                sv_handle_midi(s);
                spin_unlock_irqrestore(&s->lock, flags);
        }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&s->midi.owait, &wait);
        return ret;
 }
 
@@ -2324,7 +2365,7 @@ __initfunc(int init_sonicvibes(void))
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "sv: version v0.21 time " __TIME__ " " __DATE__ "\n");
 #if 0
        if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
                printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
@@ -2353,6 +2394,7 @@ __initfunc(int init_sonicvibes(void))
                init_waitqueue(&s->midi.iwait);
                init_waitqueue(&s->midi.owait);
                s->open_sem = MUTEX;
+               spin_lock_init(&s->lock);
                s->magic = SV_MAGIC;
                s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
                s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2423,8 +2465,8 @@ __initfunc(int init_sonicvibes(void))
                wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
                wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
                outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-               //outb(0xff, s->iodmaa + SV_DMA_RESET);
-               //outb(0xff, s->iodmac + SV_DMA_RESET);
+               /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+               /* outb(0xff, s->iodmac + SV_DMA_RESET); */
                inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
                wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
                wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
@@ -2524,8 +2566,8 @@ void cleanup_module(void)
                synchronize_irq();
                inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
                wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-               //outb(0, s->iodmaa + SV_DMA_RESET);
-               //outb(0, s->iodmac + SV_DMA_RESET);
+               /*outb(0, s->iodmaa + SV_DMA_RESET);*/
+               /*outb(0, s->iodmac + SV_DMA_RESET);*/
                free_irq(s->irq, s);
                release_region(s->iodmac, SV_EXTENT_DMA);
                release_region(s->iodmaa, SV_EXTENT_DMA);
index ec8a2e396b91719750d98dbd668547de24ef1675..e8a53f6d4c09c66c04328481e38bb7fefdc4ce2f 100644 (file)
@@ -311,6 +311,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
        unsigned long fd_offset;
        unsigned long rlim;
        int retval;
+       static int warnings = 0;
 
        ex = *((struct exec *) bprm->buf);              /* exec-header */
        if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -322,6 +323,23 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
 
        fd_offset = N_TXTOFF(ex);
 
+#ifdef __i386__
+       if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
+               if(warnings++<10)
+                       printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+               return -ENOEXEC;
+       }
+
+       if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
+           bprm->dentry->d_inode->i_op &&
+           bprm->dentry->d_inode->i_op->bmap &&
+           (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
+               if(warnings++<10)
+                       printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
+               return -ENOEXEC;
+       }
+#endif
+
        /* Check initial limits. This avoids letting people circumvent
         * size limits imposed on them by creating programs with large
         * arrays in the data or bss.
@@ -389,33 +407,19 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
                flush_icache_range((unsigned long) 0,
                                   (unsigned long) ex.a_text+ex.a_data);
        } else {
-               static unsigned long error_time, error_time2;
                if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
-                   (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
-               {
-                       printk(KERN_NOTICE "executable not page aligned\n");
-                       error_time2 = jiffies;
-               }
+                   (N_MAGIC(ex) != NMAGIC))
+                       if(warnings++<10)
+                               printk(KERN_NOTICE "executable not page aligned\n");
 
                fd = open_dentry(bprm->dentry, O_RDONLY);
                if (fd < 0)
                        return fd;
-               file = fget(fd);
-
-               if ((fd_offset & ~PAGE_MASK) != 0 &&
-                   (jiffies-error_time) > 5*HZ)
-               {
-                       printk(KERN_WARNING 
-                              "fd_offset is not page aligned. Please convert program: %s\n",
-                              file->f_dentry->d_name.name
-                              );
-                       error_time = jiffies;
-               }
+               file = fcheck(fd);
 
-               if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
-                       fput(file);
+               if (!file->f_op || !file->f_op->mmap) {
                        sys_close(fd);
-                       do_mmap(NULL, N_TXTADDR(ex), ex.a_text+ex.a_data,
+                       do_mmap(NULL, 0, ex.a_text+ex.a_data,
                                PROT_READ|PROT_WRITE|PROT_EXEC,
                                MAP_FIXED|MAP_PRIVATE, 0);
                        read_exec(bprm->dentry, fd_offset,
@@ -432,7 +436,6 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
                        fd_offset);
 
                if (error != N_TXTADDR(ex)) {
-                       fput(file);
                        sys_close(fd);
                        send_sig(SIGKILL, current, 0);
                        return error;
@@ -442,7 +445,6 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
                                fd_offset + ex.a_text);
-               fput(file);
                sys_close(fd);
                if (error != N_DATADDR(ex)) {
                        send_sig(SIGKILL, current, 0);
@@ -497,6 +499,7 @@ do_load_aout_library(int fd)
        unsigned long error;
        int retval;
        loff_t offset = 0;
+       static int warnings = 0;
        struct exec ex;
 
        retval = -EACCES;
@@ -522,6 +525,13 @@ do_load_aout_library(int fd)
                goto out_putf;
        }
 
+       if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
+           (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
+               if(warnings++<10)
+                       printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
+               goto out_putf;
+       }
+
        if (N_FLAGS(ex))
                goto out_putf;
 
@@ -530,26 +540,6 @@ do_load_aout_library(int fd)
 
        start_addr =  ex.a_entry & 0xfffff000;
 
-       if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
-               static unsigned long error_time;
-
-               if ((jiffies-error_time) > 5*HZ)
-               {
-                       printk(KERN_WARNING 
-                              "N_TXTOFF is not page aligned. Please convert library: %s\n",
-                              file->f_dentry->d_name.name);
-                       error_time = jiffies;
-               }
-               do_mmap(NULL, start_addr, ex.a_text + ex.a_data,
-                       PROT_READ | PROT_WRITE | PROT_EXEC,
-                       MAP_FIXED| MAP_PRIVATE, 0);
-               read_exec(file->f_dentry, N_TXTOFF(ex),
-                         (char *)start_addr, ex.a_text + ex.a_data, 0);
-               flush_icache_range((unsigned long) start_addr,
-                                  (unsigned long) start_addr + ex.a_text + ex.a_data);
-               retval = 0;
-               goto out_putf;
-       }
        /* Now use mmap to map the library into memory. */
        error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
                        PROT_READ | PROT_WRITE | PROT_EXEC,
index 1f76051878cf59718a98c87d124237d4db5d0881..e57f678f4d332a08d5b75ab405623383716fc35e 100644 (file)
@@ -58,11 +58,12 @@ static char buffersize_index[65] =
 /*
  * Hash table mask..
  */
-static unsigned long bh_hash_mask = 0;
+static unsigned int bh_hash_mask = 0;
+static unsigned int bh_hash_shift = 0;
+static struct buffer_head ** hash_table = NULL;
 
 static int grow_buffers(int size);
 
-static struct buffer_head ** hash_table;
 static struct buffer_head * lru_list[NR_LIST] = {NULL, };
 static struct buffer_head * free_list[NR_SIZES] = {NULL, };
 
@@ -420,8 +421,13 @@ void invalidate_buffers(kdev_t dev)
        }
 }
 
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
-#define hash(dev,block) hash_table[_hashfn(dev,block)]
+/* After several hours of tedious analysis, the following hash
+ * function won.  Do not mess with it... -DaveM
+ */
+#define _hashfn(dev,block)     \
+       ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
+        (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[_hashfn(dev,block) & bh_hash_mask]
 
 static inline void remove_from_hash_queue(struct buffer_head * bh)
 {
@@ -1512,16 +1518,26 @@ void __init buffer_init(unsigned long memory_size)
            for something that is really too small */
 
        do {
+               unsigned long tmp;
+
                nr_hash = (1UL << order) * PAGE_SIZE /
                    sizeof(struct buffer_head *);
+               bh_hash_mask = (nr_hash - 1);
+
+               tmp = nr_hash;
+               bh_hash_shift = 0;
+               while((tmp >>= 1UL) != 0UL)
+                       bh_hash_shift++;
+
                hash_table = (struct buffer_head **)
                    __get_free_pages(GFP_ATOMIC, order);
-       } while (hash_table == NULL && --order > 4);
+       } while (hash_table == NULL && --order >= 0);
+       printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+              nr_hash, order, (1UL<<order) * PAGE_SIZE);
        
        if (!hash_table)
                panic("Failed to allocate buffer hash table\n");
        memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
-       bh_hash_mask = nr_hash-1;
 
        bh_cachep = kmem_cache_create("buffer_head",
                                      sizeof(struct buffer_head),
index aa299f61ed11bacc4b88872a14719b051c0083c1..e1aace0a330c414b99728bee3d2c9bddbdfb62c1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #define DCACHE_PARANOIA 1
 /* #define DCACHE_DEBUG 1 */
@@ -41,11 +42,12 @@ kmem_cache_t *dentry_cache;
  * This hash-function tries to avoid losing too many bits of hash
  * information, yet avoid using a prime hash-size or similar.
  */
-#define D_HASHBITS     10
-#define D_HASHSIZE     (1UL << D_HASHBITS)
-#define D_HASHMASK     (D_HASHSIZE-1)
+#define D_HASHBITS     d_hash_shift
+#define D_HASHMASK     d_hash_mask
 
-static struct list_head dentry_hashtable[D_HASHSIZE];
+static unsigned int d_hash_mask = 0;
+static unsigned int d_hash_shift = 0;
+static struct list_head *dentry_hashtable = NULL;
 static LIST_HEAD(dentry_unused);
 
 struct {
@@ -563,7 +565,7 @@ struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
 
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
-       hash += (unsigned long) parent;
+       hash += (unsigned long) parent / L1_CACHE_BYTES;
        hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
        return dentry_hashtable + (hash & D_HASHMASK);
 }
@@ -902,8 +904,10 @@ out:
 
 void __init dcache_init(void)
 {
-       int i;
-       struct list_head *d = dentry_hashtable;
+       int i, order;
+       struct list_head *d;
+       unsigned int nr_hash;
+       unsigned long memory_size;
 
        /* 
         * A constructor could be added for stable state like the lists,
@@ -921,7 +925,33 @@ void __init dcache_init(void)
        if (!dentry_cache)
                panic("Cannot create dentry cache");
 
-       i = D_HASHSIZE;
+       memory_size = num_physpages << PAGE_SHIFT;
+       for (order = 5; (1UL << order) < memory_size; order++)
+               ;
+
+       do {
+               unsigned long tmp;
+
+               nr_hash = (1UL << order) * PAGE_SIZE /
+                       sizeof(struct list_head);
+               d_hash_mask = (nr_hash - 1);
+
+               tmp = nr_hash;
+               d_hash_shift = 0;
+               while((tmp >>= 1UL) != 0UL)
+                       d_hash_shift++;
+
+               dentry_hashtable = (struct list_head *)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while(dentry_hashtable == NULL && --order >= 0);
+       printk("DENTRY hash table entries: %d (order: %d, %ld bytes)\n",
+              nr_hash, order, (1UL<<order) * PAGE_SIZE);
+
+       if (!dentry_hashtable)
+               panic("Failed to allocate dcache hash table\n");
+
+       d = dentry_hashtable;
+       i = nr_hash;
        do {
                INIT_LIST_HEAD(d);
                d++;
index c8208227c99d7c97a1d0efdf5a310ff2e27aa55d..6630a8cf69b434e744ff1b66d87edca777f69143 100644 (file)
@@ -267,21 +267,6 @@ error_return:
        unlock_super (sb);
 }
 
-/*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
-                              struct ext2_group_desc *gdp,
-                              int mode)
-{
-       inode->u.ext2_i.i_version++;
-       mark_inode_dirty(inode);
-
-       return;
-}
-
 /*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
@@ -493,8 +478,9 @@ repeat:
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
                inode->i_flags |= MS_SYNCHRONOUS;
        insert_inode_hash(inode);
+       inode->i_generation = inode_generation_count++;
+       inode->u.ext2_i.i_version = inode->i_generation;
        mark_inode_dirty(inode);
-       inc_inode_version (inode, gdp, mode);
 
        unlock_super (sb);
        if(DQUOT_ALLOC_INODE(sb, inode)) {
index 315d71b0f65621f23bd1ee7361eb1004e9cc590a..5629f728a802115a105ee78861b53affa86e5603 100644 (file)
@@ -51,6 +51,10 @@ void ext2_delete_inode (struct inode * inode)
            inode->i_ino == EXT2_ACL_DATA_INO)
                return;
        inode->u.ext2_i.i_dtime = CURRENT_TIME;
+       /* When we delete an inode, we increment its i_version. If it
+          is ever read in from disk again, it will have a different
+          i_version. */
+       inode->u.ext2_i.i_version++;
        mark_inode_dirty(inode);
        ext2_update_inode(inode, IS_SYNC(inode));
        inode->i_size = 0;
@@ -538,6 +542,7 @@ void ext2_read_inode (struct inode * inode)
 #endif
        }
        inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
+       inode->i_generation = inode->u.ext2_i.i_version;
        inode->u.ext2_i.i_block_group = block_group;
        inode->u.ext2_i.i_next_alloc_block = 0;
        inode->u.ext2_i.i_next_alloc_goal = 0;
index 773d0c6eb8809690bdb016441472aecc9b86dec8..443cdd941fe589301b6216cc5d8b08ff569d9643 100644 (file)
@@ -76,6 +76,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                        return -EROFS;
                if (get_user(inode->u.ext2_i.i_version, (int *) arg))
                        return -EFAULT; 
+               inode->i_generation = inode->u.ext2_i.i_version;
                inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
                return 0;
index ee3f32c672a8e8f495519991241957f564a4d64a..d8c4d6e6b40fa2599e45cac6279bd9831ed24716 100644 (file)
@@ -37,6 +37,7 @@
 #endif
 #include <linux/lockd/bind.h>
 #include <linux/lockd/xdr.h>
+#include <linux/lockd/syscall.h>
 #include <linux/init.h>
 #include <linux/nls.h>
 
@@ -159,28 +160,48 @@ void __init filesystem_setup(void)
 #ifdef CONFIG_NFSD_MODULE
 int (*do_nfsservctl)(int, void *, void *) = NULL;
 #endif
+
+#ifdef CONFIG_LOCKD_MODULE
+int (*do_lockdctl)(int, void *, void *) = NULL;
+#endif
+
 int
 asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
 {
-#ifndef CONFIG_NFSD_MODULE
-       return -ENOSYS;
-#else
        int ret = -ENOSYS;
        
+       if (cmd >= NFSCTL_LOCKD) {
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+               lock_kernel();
+#ifdef CONFIG_LOCKD
+               ret = lockdctl(cmd, argp, resp);
+#else
+               if (do_lockdctl) 
+                       ret = do_lockdctl(cmd, argp, resp);
+#ifdef CONFIG_KMOD
+               else if (request_module ("lockd") == 0) {
+                       if (do_lockdctl)
+                               ret = do_lockdctl(cmd, argp, resp);
+               }
+#endif
+#endif
+               unlock_kernel();
+#endif
+               return ret;
+       }
+
+#ifdef CONFIG_NFSD_MODULE
        lock_kernel();
-       if (do_nfsservctl) {
+       if (do_nfsservctl)
                ret = do_nfsservctl(cmd, argp, resp);
-               goto out;
-       }
 #ifdef CONFIG_KMOD
-       if (request_module ("nfsd") == 0) {
+       else if (request_module ("nfsd") == 0) {
                if (do_nfsservctl)
                        ret = do_nfsservctl(cmd, argp, resp);
        }
 #endif /* CONFIG_KMOD */
-out:
        unlock_kernel();
-       return ret;
 #endif /* CONFIG_NFSD_MODULE */
+       return ret;
 }
 #endif /* CONFIG_NFSD */
index a72ef481513873637f0927b4c492c97fb95a67b1..66c1dd0e382fc73eb886bbac721ecd25849d4af0 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/dcache.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
+#include <linux/random.h>
 
 /*
  * New inode.c implementation.
@@ -48,6 +49,8 @@ LIST_HEAD(inode_in_use);
 static LIST_HEAD(inode_unused);
 static struct list_head inode_hashtable[HASH_SIZE];
 
+__u32 inode_generation_count = 0;
+
 /*
  * A simple spinlock to protect the list manipulations.
  *
@@ -809,6 +812,10 @@ void __init inode_init(void)
        if (max > MAX_INODE)
                max = MAX_INODE;
        max_inodes = max;
+
+       /* Get a random number. */
+       get_random_bytes (&inode_generation_count,
+                         sizeof (inode_generation_count));
 }
 
 /* This belongs in file_table.c, not here... */
@@ -844,3 +851,48 @@ void update_atime (struct inode *inode)
     inode->i_atime = CURRENT_TIME;
     mark_inode_dirty (inode);
 }   /*  End Function update_atime  */
+
+/* This function is called by nfsd. */
+struct inode *iget_in_use(struct super_block *sb, unsigned long ino)
+{
+       struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+
+       spin_lock(&inode_lock);
+       inode = find_inode(sb, ino, head);
+       if (inode) {
+               spin_unlock(&inode_lock);
+               wait_on_inode(inode);
+       }
+       else
+               inode = get_new_inode (sb, ino, head);
+
+       /* When we get the inode, we have to check if it is in use. We
+          have to release it if it is not. */
+       if (inode) {
+               spin_lock(&inode_lock);
+               if (inode->i_nlink == 0 && inode->i_count == 1) {
+                       --inode->i_count;
+                       list_del(&inode->i_hash);
+                       INIT_LIST_HEAD(&inode->i_hash);
+                       list_del(&inode->i_list);
+                       INIT_LIST_HEAD(&inode->i_list);
+                       if (list_empty(&inode->i_hash)) {
+                               list_del(&inode->i_list);
+                               INIT_LIST_HEAD(&inode->i_list);
+                               spin_unlock(&inode_lock);
+                               clear_inode(inode);
+                               spin_lock(&inode_lock);
+                               list_add(&inode->i_list, &inode_unused);
+                               inodes_stat.nr_free_inodes++;
+                       }
+                       else if (!(inode->i_state & I_DIRTY)) {
+                               list_del(&inode->i_list);
+                               list_add(&inode->i_list, &inode_in_use);
+                       }
+                       inode = NULL;
+               }
+               spin_unlock(&inode_lock);
+       }
+       return inode;
+}
index b3990ed9893fff3f4af960dfd2ac28228fb60681..1bcb4f824bbd293b657d9331ab232e5c1afdcf40 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 
 /* Start/stop the daemon */
 EXPORT_SYMBOL(lockd_up);
@@ -34,6 +35,7 @@ EXPORT_SYMBOL(nlmclnt_proc);
 /* NFS server entry points/hooks */
 EXPORT_SYMBOL(nlmsvc_invalidate_client);
 EXPORT_SYMBOL(nlmsvc_ops);
+EXPORT_SYMBOL(lockdctl);
 
 /* Configuration at insmod time */
 EXPORT_SYMBOL(nlmsvc_grace_period);
index d61db4302b472280871839be9555fd802a6e88e5..80dcc1adba9e8bacaba59b86c87054bd46b40d72 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 #include <linux/nfs.h>
 
 #define NLMDBG_FACILITY                NLMDBG_SVC
@@ -315,6 +316,9 @@ out:
   MODULE_PARM(nlm_grace_period, "10-240l");
   MODULE_PARM(nlm_timeout, "3-20l");
 #endif
+
+extern int (*do_lockdctl)(int, void *, void *);
+
 int
 init_module(void)
 {
@@ -324,6 +328,7 @@ init_module(void)
        nlmsvc_pid = 0;
        lockd_exit = NULL;
        nlmxdr_init();
+       do_lockdctl = lockdctl;
        return 0;
 }
 
@@ -332,6 +337,7 @@ cleanup_module(void)
 {
        /* FIXME: delete all NLM clients */
        nlm_shutdown_hosts();
+       do_lockdctl = NULL;
 }
 #endif
 
@@ -370,3 +376,23 @@ struct svc_program         nlmsvc_program = {
        "lockd",                /* service name */
        &nlmsvc_stats,          /* stats table */
 };
+
+int
+lockdctl(int cmd, void *opaque_argp, void *opaque_resp)
+{
+       int err;
+
+       MOD_INC_USE_COUNT;
+
+       switch(cmd) {
+       case LOCKDCTL_SVC:
+               err = lockd_up ();
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+       MOD_DEC_USE_COUNT;
+
+       return err;
+}
index 87926addb5eec1a74c5166afccb60b03f979d541..ce456cac4031ab4b0f4e79bbc9c5a69c673a9690 100644 (file)
@@ -688,8 +688,11 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
 
        if (((start += l->l_start) < 0) || (l->l_len < 0))
                return (0);
+       fl->fl_end = start + l->l_len - 1;
+       if (l->l_len > 0 && fl->fl_end < 0)
+               return (0);
        fl->fl_start = start;   /* we record the absolute position */
-       if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
+       if (l->l_len == 0)
                fl->fl_end = OFFSET_MAX;
        
        fl->fl_file = filp;
index afa07f00179c481cbadab05460f5dca63d3cad77..194cd98888eab0567ad13fa156b0e891a30255db 100644 (file)
@@ -134,8 +134,10 @@ nfs_put_super(struct super_block *sb)
        if ((rpc = server->client) != NULL)
                rpc_shutdown_client(rpc);
 
+#if 0
        if (!(server->flags & NFS_MOUNT_NONLM))
                lockd_down();   /* release rpc.lockd */
+#endif
        rpciod_down();          /* release rpciod */
        /*
         * Invalidate the dircache for this superblock.
@@ -311,9 +313,11 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        /* We're airborne */
        unlock_super(sb);
 
+#if 0
        /* Check whether to start the lockd process */
        if (!(server->flags & NFS_MOUNT_NONLM))
                lockd_up();
+#endif
        return sb;
 
        /* Yargs. It didn't work out. */
index aca7e982c3dd2d96c09679e7ffd8a39eadebeb70..e95d32b01e89bd6b1ce2541b5ffc5ad24524333c 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 
-#include <linux/linkage.h>
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -29,6 +29,7 @@
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
+#include <linux/lockd/syscall.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
@@ -40,7 +41,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
-extern void nfsd_fh_init(void);
 extern long sys_call_table[];
 
 static int     nfsctl_svc(struct nfsctl_svc *data);
@@ -57,15 +57,72 @@ static int  initialized = 0;
 int exp_procfs_exports(char *buffer, char **start, off_t offset,
                              int length, int *eof, void *data);
 
-void proc_export_init(void)
+struct long_maxmin
 {
-       struct proc_dir_entry *nfs_export_ent = NULL;
+       long *value;
+       long min_value;
+       long max_value;
+};
 
-       if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
+/* In seconds. */
+#define TIME_DIFF_MARGIN       10
+#define MIN_TIME_DIFF_MARGIN   0
+#define MAX_TIME_DIFF_MARGIN   600
+
+long nfsd_time_diff_margin = TIME_DIFF_MARGIN;
+
+static struct long_maxmin time_diff_margin =
+{
+       &nfsd_time_diff_margin,
+       MIN_TIME_DIFF_MARGIN,
+       MAX_TIME_DIFF_MARGIN
+};
+
+static int
+nfsd_proc_read_long_maxmin(char *buffer, char **start, off_t offset,
+                         int length, int *eof, void *data)
+{
+       int len;
+       struct long_maxmin *x = (struct long_maxmin *) data;
+       len = sprintf(buffer, "%ld\n", *x->value) - offset;
+       if (len < length) {
+               *eof = 1;
+               if (len <= 0)
+                        return 0;
+       } else
+               len = length;
+       *start = buffer + offset;
+       return len;
+}
+
+static int
+nfsd_proc_write_long_maxmin(struct file *file, const char *buffer,
+                          unsigned long count, void *data)
+{
+       long v;
+       struct long_maxmin *x = (struct long_maxmin *) data;
+       v = simple_strtoul(buffer, NULL, 10);
+       if (v < x->min_value || v > x->max_value)
+               return -EINVAL;
+       *x->value = v;
+       return count;
+}
+
+static void nfsd_proc_init(void)
+{
+       struct proc_dir_entry *nfsd_ent = NULL;
+
+       if (!(nfsd_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
                return;
-       if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+       if (!(nfsd_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
                return;
-       nfs_export_ent->read_proc = exp_procfs_exports;
+       nfsd_ent->read_proc = exp_procfs_exports;
+       if (!(nfsd_ent = create_proc_entry("fs/nfs/time-diff-margin",
+                                          S_IFREG|S_IRUGO|S_IWUSR, 0)))
+               return;
+       nfsd_ent->read_proc = nfsd_proc_read_long_maxmin;
+       nfsd_ent->write_proc = nfsd_proc_write_long_maxmin;
+       nfsd_ent->data = (void *) &time_diff_margin;
 }
 
 
@@ -80,8 +137,7 @@ nfsd_init(void)
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
-       nfsd_fh_init();         /* FH table */
-       proc_export_init();
+       nfsd_proc_init();
        initialized = 1;
 }
 
@@ -209,6 +265,11 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
                goto done;
        }
 
+       if (cmd >= NFSCTL_LOCKD) {
+               err = lockdctl(cmd, argp, resp);
+               goto done;
+       }
+
        switch(cmd) {
        case NFSCTL_SVC:
                err = nfsctl_svc(&arg->ca_svc);
@@ -303,6 +364,7 @@ cleanup_module(void)
        nfsd_export_shutdown();
        nfsd_cache_shutdown();
        nfsd_fh_free();
+       remove_proc_entry("fs/nfs/time-diff-margin", NULL);
        remove_proc_entry("fs/nfs/exports", NULL);
        remove_proc_entry("fs/nfs", NULL);
        nfsd_stat_shutdown();
index 2dcf3e3541891600f590fd71002fce3639df2723..cf7817617d6ef848fdf6530c57d921a0b48337c6 100644 (file)
@@ -22,6 +22,7 @@
 #define NFSDDBG_FACILITY               NFSDDBG_FH
 #define NFSD_PARANOIA 1
 /* #define NFSD_DEBUG_VERBOSE 1 */
+/* #define NFSD_DEBUG_VERY_VERBOSE 1 */
 
 extern unsigned long max_mapnr;
 
@@ -34,16 +35,16 @@ struct fh_entry {
        kdev_t  dev;
 };
 
-#define NFSD_MAXFH PAGE_SIZE/sizeof(struct fh_entry)
-static struct fh_entry filetable[NFSD_MAXFH];
-static struct fh_entry dirstable[NFSD_MAXFH];
+#define NFSD_MAXFH \
+  (((nfsd_nservers + 1) >> 1) * PAGE_SIZE/sizeof(struct fh_entry))
+static struct fh_entry *filetable = NULL;
+static struct fh_entry *dirstable = NULL;
 
 static int nfsd_nr_verified = 0;
 static int nfsd_nr_put = 0;
 static unsigned long nfsd_next_expire = 0;
 
 static int add_to_fhcache(struct dentry *, int);
-static int nfsd_d_validate(struct dentry *);
 struct dentry * lookup_inode(kdev_t, ino_t, ino_t);
 
 static LIST_HEAD(fixup_head);
@@ -51,15 +52,16 @@ static LIST_HEAD(path_inuse);
 static int nfsd_nr_fixups = 0;
 static int nfsd_nr_paths = 0;
 #define NFSD_MAX_PATHS 500
-#define NFSD_MAX_FIXUPAGE 60*HZ
+#define NFSD_MAX_FIXUPS 500
+#define NFSD_MAX_FIXUP_AGE 30*HZ
 
 struct nfsd_fixup {
        struct list_head lru;
-       ino_t   dir;
+       unsigned long reftime;
+       ino_t   dirino;
        ino_t   ino;
        kdev_t  dev;
-       struct dentry *dentry;
-       unsigned long reftime;
+       ino_t   new_dirino;
 };
 
 struct nfsd_path {
@@ -71,7 +73,8 @@ struct nfsd_path {
        char    name[1];
 };
 
-static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino)
+static struct nfsd_fixup *
+find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino)
 {
        struct list_head *tmp = fixup_head.next;
 
@@ -79,32 +82,43 @@ static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino)
                struct nfsd_fixup *fp;
 
                fp = list_entry(tmp, struct nfsd_fixup, lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("fixup %lu %lu, %lu %lu %s %s\n",
+        fp->ino, ino,
+       fp->dirino, dirino,
+       kdevname(fp->dev), kdevname(dev));
+#endif
                if (fp->ino != ino)
                        continue;
-               if (fp->dir != dir)
+               if (fp->dirino != dirino)
                        continue;
                if (fp->dev != dev)
                        continue;
+               fp->reftime = jiffies;  
                list_del(tmp);
                list_add(tmp, &fixup_head);
-               fp->reftime = jiffies;
                return fp;
        }
        return NULL;
 }
 
 /*
- * Save the dentry pointer from a successful lookup.
+ * Save the dirino from a rename.
  */
-static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
+void
+add_to_rename_cache(ino_t new_dirino,
+                    kdev_t dev, ino_t dirino, ino_t ino)
 {
        struct nfsd_fixup *fp;
 
-       fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev), 
-                               u32_to_ino_t(fh->fh_dirino),
-                               u32_to_ino_t(fh->fh_ino));
+       if (dirino == new_dirino)
+               return;
+
+       fp = find_cached_lookup(dev, 
+                               dirino,
+                               ino);
        if (fp) {
-               fp->dentry = dentry;
+               fp->new_dirino = new_dirino;
                return;
        }
 
@@ -115,19 +129,30 @@ static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
         */
        fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
        if (fp) {
-               fp->dir = u32_to_kdev_t(fh->fh_dirino);
-               fp->ino = u32_to_ino_t(fh->fh_ino);
-               fp->dev = u32_to_ino_t(fh->fh_dev);
-               fp->dentry = dentry;
-               fp->reftime = jiffies;
+               fp->dirino = dirino;
+               fp->ino = ino;
+               fp->dev = dev;
+               fp->new_dirino = new_dirino;
                list_add(&fp->lru, &fixup_head);
                nfsd_nr_fixups++;
        }
 }
 
+/*
+ * Save the dentry pointer from a successful lookup.
+ */
+
 static void free_fixup_entry(struct nfsd_fixup *fp)
 {
        list_del(&fp->lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("free_rename_entry: %lu->%lu %lu/%s\n",
+               fp->dirino,
+               fp->new_dirino,
+               fp->ino,
+               kdevname(fp->dev),
+               (jiffies - fp->reftime));
+#endif
        kfree(fp);
        nfsd_nr_fixups--;
 }
@@ -212,9 +237,9 @@ restart:
        if (new) {
                new->users = 0; 
                new->reftime = jiffies; 
-               new->ino = inode->i_ino;        
-               new->dev = inode->i_dev;        
-               result = copy_path(new->name, dentry, len);     
+               new->ino = inode->i_ino;
+               new->dev = inode->i_dev;
+               result = copy_path(new->name, dentry, len);
                if (!result)
                        goto retry;
                list_add(&new->lru, &path_inuse);
@@ -301,8 +326,8 @@ static int filldir_one(void * __buf, const char * name, int len,
        int result = 0;
 
        buf->sequence++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name);
 #endif
        if (buf->sequence == 2) {
                buf->dirino = ino;
@@ -311,7 +336,7 @@ printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
        if (dirent->ino == ino) {
                dirent->len = len;
                memcpy(dirent->name, name, len);
-               dirent->name[len] = 0;
+               dirent->name[len] = '\0';
                buf->found = 1;
                result = -1;
        }
@@ -431,7 +456,7 @@ struct dentry * lookup_inode(kdev_t dev, ino_t dirino, ino_t ino)
                }
 
                result = ERR_PTR(-ENOENT);
-               dir = iget(sb, dirino);
+               dir = iget_in_use(sb, dirino);
                if (!dir)
                        goto out_root;
                dentry = d_alloc_root(dir, NULL);
@@ -483,7 +508,7 @@ out_iput:
        iput(dir);
 out_root:
        dput(root);
-       goto out;
+       goto out_page;
 }
 
 /*
@@ -521,7 +546,8 @@ static void expire_fhe(struct fh_entry *empty, int cache)
        struct dentry *dentry = empty->dentry;
 
 #ifdef NFSD_DEBUG_VERBOSE
-printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n",
+printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n",
+(cache == NFSD_FILE_CACHE) ? "file" : "dir",
 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
 #endif
        empty->dentry = NULL;   /* no dentry */
@@ -576,11 +602,10 @@ out:
  */
 static void expire_old(int cache, int age)
 {
-       struct list_head *tmp;
        struct fh_entry *fhe;
        int i;
 
-#ifdef NFSD_DEBUG_VERBOSE
+#ifdef NFSD_DEBUG_VERY_VERBOSE
 printk("expire_old: expiring %s older than %d\n",
 (cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
 #endif
@@ -593,12 +618,12 @@ printk("expire_old: expiring %s older than %d\n",
        }
 
        /*
-        * Remove old entries from the patch-up cache.
+        * Trim the fixup cache ...
         */
-       while ((tmp = fixup_head.prev) != &fixup_head) {
+       while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) {
                struct nfsd_fixup *fp;
-               fp = list_entry(tmp, struct nfsd_fixup, lru);
-               if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE)
+               fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru);
+               if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE)
                        break;
                free_fixup_entry(fp);
        }
@@ -736,15 +761,21 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ino);
                                        dget(dentry);
                                        nfsd_nr_verified++;
                                }
+                               put_path(pe);
                        } else {
                                dput(res);
+                               put_path(pe);
+                               /* We should delete it from the cache. */
+                               free_path_entry(pe);
                        }
                } else {
 #ifdef NFSD_PARANOIA
 printk("find_dentry_by_ino: %s lookup failed\n", pe->name);
 #endif
+                       put_path(pe);
+                       /* We should delete it from the cache. */
+                       free_path_entry(pe);
                }
-               put_path(pe);
        }
 out:
        return dentry;
@@ -757,6 +788,8 @@ out:
  */
 static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
 {
+/* FIXME: this must use the dev/ino/dir_ino triple. */ 
+#if 0
        struct fh_entry * fhe;
 
        fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
@@ -794,6 +827,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                return dentry;
        }
 out:
+#endif
        return NULL;
 }
 
@@ -822,7 +856,7 @@ printk("lookup_by_inode: ino %ld not found in %s\n", ino, parent->d_name.name);
 printk("lookup_by_inode: found %s\n", dirent.name);
 #endif
 
-       dentry = lookup_dentry(dirent.name, dget(parent), 0);
+       dentry = lookup_dentry(dirent.name, parent, 0);
        if (!IS_ERR(dentry)) {
                if (dentry->d_inode && dentry->d_inode->i_ino == ino)
                        goto out;
@@ -842,13 +876,12 @@ no_entry:
        dentry = NULL;
 out:
        return dentry;
-
 }
 
 /*
  * Search the fix-up list for a dentry from a prior lookup.
  */
-static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
+static ino_t nfsd_cached_lookup(struct knfs_fh *fh)
 {
        struct nfsd_fixup *fp;
 
@@ -856,8 +889,8 @@ static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
                                u32_to_ino_t(fh->fh_dirino),
                                u32_to_ino_t(fh->fh_ino));
        if (fp)
-               return fp->dentry;
-       return NULL;
+               return fp->new_dirino;
+       return 0;
 }
 
 void
@@ -916,8 +949,12 @@ expire_by_dentry(struct dentry *dentry)
 static struct dentry *
 find_fh_dentry(struct knfs_fh *fh)
 {
+       struct super_block *sb;
        struct dentry *dentry, *parent;
+       struct inode * inode;
+       struct list_head *lst;
        int looked_up = 0, retry = 0;
+       ino_t dirino;
 
        /*
         * Stage 1: Look for the dentry in the short-term fhcache.
@@ -927,50 +964,73 @@ find_fh_dentry(struct knfs_fh *fh)
                nfsdstats.fh_cached++;
                goto out;
        }
-
        /*
-        * Stage 2: Attempt to validate the dentry in the file handle.
+        * Stage 2: Attempt to find the inode.
         */
-       dentry = fh->fh_dcookie;
+       sb = get_super(fh->fh_dev);
+       if (NULL == sb) {
+               printk("find_fh_dentry: No SuperBlock for device %s.",
+                      kdevname(fh->fh_dev));
+               dentry = NULL;
+               goto out;
+       }
+
+       dirino = u32_to_ino_t(fh->fh_dirino);
+       inode = iget_in_use(sb, fh->fh_ino);
+       if (!inode) {
+               dprintk("find_fh_dentry: No inode found.\n");
+               goto out_five;
+       }
+       goto check;
 recheck:
-       if (nfsd_d_validate(dentry)) {
-               struct inode * dir = dentry->d_parent->d_inode;
+       if (!inode) {
+               dprintk("find_fh_dentry: No inode found.\n");
+               goto out_three;
+       }
+check:
+       for (lst = inode->i_dentry.next;
+            lst != &inode->i_dentry;
+            lst = lst->next) {
+               dentry = list_entry(lst, struct dentry, d_alias);
+
+/* if we are looking up a directory then we don't need the parent! */
+               if (!dentry ||
+                   !dentry->d_parent ||
+                   !dentry->d_parent->d_inode) {
+printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino);
+                       continue;
+               }
+               if (dentry->d_parent->d_inode->i_ino != dirino)
+                       continue;
 
-               if (dir->i_ino == u32_to_ino_t(fh->fh_dirino) && 
-                   dir->i_dev == u32_to_kdev_t(fh->fh_dev)) {
-                       struct inode * inode = dentry->d_inode;
-                       /*
-                        * NFS file handles must always have an inode,
-                        * so we won't accept a negative dentry.
-                        */
-                       if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
-                               dget(dentry);
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: validated %s/%s, ino=%ld\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino);
-#endif
-                               if (!retry)
-                                       nfsdstats.fh_valid++;
-                               else {
-                                       nfsdstats.fh_fixup++;
+               dget(dentry);
+               iput(inode);
 #ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: retried validation successful\n");
+               printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n",
+                      retry ? " Renamed" : "",
+                      dentry->d_parent->d_name.name,
+                      dentry->d_name.name,
+                      dentry->d_parent->d_inode->i_ino,
+                      dirino);
 #endif
-                               }
-                               goto out;
-                       }
-               }
-       }
+               goto out;
+       } /* for inode->i_dentry */
 
        /*
-        * Before proceeding to a lookup, check whether we cached a
-        * prior lookup. If so, try to validate that dentry ...
+        * Before proceeding to a lookup, check for a rename
         */
-       if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+       if (!retry && (dirino = nfsd_cached_lookup(fh))) {
+               dprintk("find_fh_dentry: retry with %lu\n", dirino);
                retry = 1;
                goto recheck;
        }
 
+       iput(inode);
+
+       dprintk("find_fh_dentry: dirino not found %lu\n", dirino);
+
+out_three:
+
        /*
         * Stage 3: Look up the dentry based on the inode and parent inode
         * numbers. This should work for all Unix-like filesystems.
@@ -983,7 +1043,7 @@ printk("find_fh_dentry: retried validation successful\n");
                struct inode * inode = dentry->d_inode;
 #ifdef NFSD_DEBUG_VERBOSE
 printk("find_fh_dentry: looked up %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
                if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
                        nfsdstats.fh_lookup++;
@@ -991,7 +1051,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                }
 #ifdef NFSD_PARANOIA
 printk("find_fh_dentry: %s/%s lookup mismatch!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
                dput(dentry);
        }
@@ -1005,29 +1065,27 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                /*
                 * ... then search for the inode in the parent directory.
                 */
+               dget(parent);
                dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
                dput(parent);
                if (dentry)
                        goto out;
        }
 
+out_five:
+
        /*
-        * Stage 5: Search the whole volume.
+        * Stage 5: Search the whole volume, Yea Right.
         */
 #ifdef NFSD_PARANOIA
-printk("find_fh_dentry: %s, %u/%u not found -- need full search!\n",
-kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_dirino, fh->fh_ino);
+printk("find_fh_dentry: %s/%u dir/%u not found!\n",
+       kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino);
 #endif
        dentry = NULL;
        nfsdstats.fh_stale++;
        
 out:
-       if (looked_up && dentry) {
-               add_to_lookup_cache(dentry, fh);
-       }
-
        expire_all();
-
        return dentry;
 }
 
@@ -1046,8 +1104,12 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        struct inode    *inode;
        u32             error = 0;
 
-       dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
-               fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
+       dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n",
+               kdevname(fh->fh_xdev),
+               fh->fh_xino,
+               kdevname(fh->fh_dev),
+               fh->fh_ino,
+               fh->fh_dirino);
 
        if (fhp->fh_dverified)
                goto check_type;
@@ -1056,10 +1118,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
         */
        error = nfserr_stale;
        exp = exp_get(rqstp->rq_client,
-                       u32_to_kdev_t(fh->fh_xdev),
-                       u32_to_ino_t(fh->fh_xino));
-       if (!exp) /* export entry revoked */
+                     u32_to_kdev_t(fh->fh_xdev),
+                     u32_to_ino_t(fh->fh_xino));
+       if (!exp) {
+               /* export entry revoked */
+               nfsdstats.fh_stale++;
                goto out;
+       }
 
        /* Check if the request originated from a secure port. */
        error = nfserr_perm;
@@ -1079,8 +1144,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
         */
        error = nfserr_noent;
        dentry = find_fh_dentry(fh);
-       if (!dentry)
+       if (!dentry) {
+               goto out;
+       }
+       if (IS_ERR(dentry)) {
+               error = nfserrno(-PTR_ERR(dentry));
                goto out;
+       }
 
        /*
         * Note:  it's possible the returned dentry won't be the one in the
@@ -1102,6 +1172,35 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 check_type:
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
+       error = nfserr_stale;
+       /* On a heavily loaded SMP machine, more than one identical
+          requests may run at the same time on different processors.
+          One thread may get here with unfinished fh after another
+          thread just fetched the inode. It doesn't make any senses
+          to check fh->fh_generation here since it has not been set
+          yet. In that case, we shouldn't send back the stale
+          filehandle to the client. We use fh->fh_dcookie to indicate
+          if fh->fh_generation is set or not. If fh->fh_dcookie is
+          not set, don't return stale filehandle. */
+       if (inode->i_generation != fh->fh_generation) {
+               if (fh->fh_dcookie) {
+                       dprintk("fh_verify: Bad version %u %u %u: 0x%x, 0x%x\n",
+                               inode->i_ino,
+                               inode->i_generation,
+                               fh->fh_generation,
+                               type, access);
+                       nfsdstats.fh_stale++;
+                       goto out;
+               }
+               else {
+                       /* We get here when inode is fetched by other
+                          threads. We just use what is in there. */
+                       fh->fh_ino = ino_t_to_u32(inode->i_ino);
+                       fh->fh_generation = inode->i_generation;
+                       fh->fh_dcookie = (struct dentry *)0xfeebbaca;
+                       nfsdstats.fh_concurrent++;
+               }
+       }
        exp = fhp->fh_export;
        if (type > 0 && (inode->i_mode & S_IFMT) != type) {
                error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -1117,9 +1216,10 @@ check_type:
         */
        error = 0;
        if (fh->fh_dev != fh->fh_xdev) {
-               printk("fh_verify: Security: export on other device"
-                      " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+               printk("fh_verify: Security: export on other device (%s, %s).\n",
+                      kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
                error = nfserr_stale;
+               nfsdstats.fh_stale++;
        } else if (exp->ex_dentry != dentry) {
                struct dentry *tdentry = dentry;
 
@@ -1128,19 +1228,21 @@ check_type:
                        if (exp->ex_dentry == tdentry)
                                break;
                        /* executable only by root and we can't be root */
-                       if (current->fsuid &&
-                           !(tdentry->d_inode->i_uid  &&
-                               (tdentry->d_inode->i_mode & S_IXUSR)) &&
-                           !(tdentry->d_inode->i_gid &&
-                               (tdentry->d_inode->i_mode & S_IXGRP)) &&
-                           !(tdentry->d_inode->i_mode & S_IXOTH) && 
-                           (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+                       if (current->fsuid
+                           && !(tdentry->d_inode->i_uid
+                                && (tdentry->d_inode->i_mode & S_IXUSR))
+                           && !(tdentry->d_inode->i_gid
+                                && (tdentry->d_inode->i_mode & S_IXGRP))
+                           && !(tdentry->d_inode->i_mode & S_IXOTH)
+                           && (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
                                error = nfserr_stale;
+                               nfsdstats.fh_stale++;
 dprintk("fh_verify: no root_squashed access.\n");
                        }
                } while ((tdentry != tdentry->d_parent));
                if (exp->ex_dentry != tdentry) {
                        error = nfserr_stale;
+                       nfsdstats.fh_stale++;
                        printk("nfsd Security: %s/%s bad export.\n",
                               dentry->d_parent->d_name.name,
                               dentry->d_name.name);
@@ -1194,6 +1296,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
        if (inode) {
                fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
                fhp->fh_handle.fh_generation = inode->i_generation;
+               fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
        }
        fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
        fhp->fh_handle.fh_dev    = kdev_t_to_u32(parent->d_inode->i_dev);
@@ -1226,7 +1329,8 @@ fh_update(struct svc_fh *fhp)
                goto out_negative;
        fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
        fhp->fh_handle.fh_generation = inode->i_generation;
-out:
+       fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+ out:
        return;
 
 out_bad:
@@ -1264,51 +1368,6 @@ out_bad:
        return;
 }
 
-/*
- * Verify that the FH dentry is still a valid dentry pointer.
- * After making some preliminary checks, we ask VFS to verify
- * that it is indeed a dentry.
- */
-static int nfsd_d_validate(struct dentry *dentry)
-{
-       unsigned long dent_addr = (unsigned long) dentry;
-       unsigned long min_addr = PAGE_OFFSET;
-       unsigned long max_addr = min_addr + (max_mapnr << PAGE_SHIFT);
-       unsigned long align_mask = 0x0F;
-       unsigned int len;
-       int valid = 0;
-
-       if (dent_addr < min_addr)
-               goto bad_addr;
-       if (dent_addr > max_addr - sizeof(struct dentry))
-               goto bad_addr;
-       if ((dent_addr & ~align_mask) != dent_addr)
-               goto bad_align;
-       if (!kern_addr_valid(dent_addr))
-               goto bad_addr;
-       /*
-        * Looks safe enough to dereference ...
-        */
-       len = dentry->d_name.len;
-       if (len > NFS_MAXNAMLEN)
-               goto out;
-       /*
-        * Note: d_validate doesn't dereference the parent pointer ...
-        * just combines it with the name hash to find the hash chain.
-        */
-       valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
-
-out:
-       return valid;
-
-bad_addr:
-       printk(KERN_DEBUG "nfsd_d_validate: invalid address %lx\n", dent_addr);
-       goto out;
-bad_align:
-       printk(KERN_DEBUG "nfsd_d_validate: unaligned address %lx\n", dent_addr);
-       goto out;
-}
-
 /*
  * Flush any cached dentries for the specified device
  * or for all devices.
@@ -1338,7 +1397,7 @@ void nfsd_fh_flush(kdev_t dev)
 }
 
 /*
- * Free the dentry and path caches.
+ * Free the rename and path caches.
  */
 void nfsd_fh_free(void)
 {
@@ -1375,18 +1434,33 @@ void nfsd_fh_free(void)
 
 void nfsd_fh_init(void)
 {
-       /* Sanity check */ 
        extern void __my_nfsfh_is_too_big(void); 
+
+       if (filetable)
+               return;
+
+       /* Sanity check */ 
        if (sizeof(struct nfs_fhbase) > 32) 
                __my_nfsfh_is_too_big(); 
 
+       filetable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+                           GFP_KERNEL);
+       dirstable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+                           GFP_KERNEL);
+
+       if (filetable == NULL || dirstable == NULL) {
+               printk(KERN_WARNING "nfsd_fh_init : Could not allocate fhcache\n");
+               nfsd_nservers = 0;
+               return;
+       }
+
        memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
        memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
        INIT_LIST_HEAD(&path_inuse);
        INIT_LIST_HEAD(&fixup_head);
 
        printk(KERN_DEBUG 
-               "nfsd_init: initialized fhcache, entries=%lu\n", NFSD_MAXFH);
+               "nfsd_fh_init : initialized fhcache, entries=%lu\n", NFSD_MAXFH);
        /*
         * Display a warning if the ino_t is larger than 32 bits.
         */
@@ -1395,3 +1469,15 @@ void nfsd_fh_init(void)
                        "NFSD: ino_t is %d bytes, using lower 4 bytes\n",
                        sizeof(ino_t));
 }
+
+void
+nfsd_fh_shutdown(void)
+{
+       if (!filetable)
+               return;
+       printk(KERN_DEBUG 
+               "nfsd_fh_shutdown : freeing %d fhcache entries.\n", NFSD_MAXFH);
+       kfree(filetable);
+       kfree(dirstable);
+       filetable = dirstable = NULL;
+}
index 87de16aad5ed818d6f3735ef9037ebd95ccbb15d..971bab42088a957fd994a6a1e12cbac2f9045ec1 100644 (file)
@@ -270,7 +270,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                rdev = (dev_t) size;
                if (type != S_IFBLK && type != S_IFCHR) {
                        rdev = 0;
-               } else if (type == S_IFCHR && size == ~(u32) 0) {
+               } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
                        /* If you think you've seen the worst, grok this. */
                        attr->ia_mode = S_IFIFO | mode;
                        type = S_IFIFO;
@@ -288,6 +288,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
                if (inode && (type != (inode->i_mode & S_IFMT) || 
                    (is_borc && inode->i_rdev != rdev)))
                        goto out_unlock;
+
+               /* invalidate size because only (type == S_IFREG) has
+                  size. */
+               attr->ia_valid &= ~ATTR_SIZE;
        }
        
        nfserr = 0;
index b7fa534e065b12bd54b748903ff9dbe5df73a4a8..452829812a1d1bb2cc3b0cab8d732bc0b5f9a073 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Authors:    Olaf Kirch (okir@monad.swb.de)
  *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
  */
 
 #define __NO_VERSION__
@@ -63,6 +63,11 @@ nfsd_svc(unsigned short port, int nrservs)
                nrservs = NFSD_MAXSERVS;
        nfsd_nservers = nrservs;
 
+       error = -ENOMEM;
+       nfsd_fh_init();         /* NFS dentry cache */
+       if (nfsd_nservers == 0)
+               goto out;
+         
        error = -ENOMEM;
        nfsd_racache_init();     /* Readahead param cache */
        if (nfsd_nservers == 0)
@@ -119,7 +124,9 @@ nfsd(struct svc_rqst *rqstp)
                nfssvc_boot = xtime;            /* record boot time */
                first = 1;
        }
+#if 0
        lockd_up();                             /* start lockd */
+#endif
 
        /*
         * The main request loop
@@ -177,12 +184,16 @@ nfsd(struct svc_rqst *rqstp)
                printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
        }
 
+#if 0
        /* Release lockd */
        lockd_down();
+#endif
        if (!--nfsd_active) {
                printk("nfsd: last server exiting\n");
                /* revoke all exports */
                nfsd_export_shutdown();
+               /* release fhcache */
+               nfsd_fh_shutdown ();
                /* release read-ahead cache */
                nfsd_racache_shutdown();
        }
index accd0aadc3dfc3a3ed27fa698f0418c60bc5a69c..ca9e7ae2317783b9ebd3b50615f497fc42e4ae39 100644 (file)
@@ -32,7 +32,7 @@ nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
 {
        int     len;
 
-       len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d\n",
+       len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d %d\n",
                        nfsdstats.rchits,
                        nfsdstats.rcmisses,
                        nfsdstats.rcnocache,
@@ -40,7 +40,8 @@ nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
                        nfsdstats.fh_valid,
                        nfsdstats.fh_fixup,
                        nfsdstats.fh_lookup,
-                       nfsdstats.fh_stale);
+                       nfsdstats.fh_stale,
+                       nfsdstats.fh_concurrent);
 
        /* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
        *eof = 0;
index ab577897e62b9130fc40b7e709d4901ae89edb35..c3e3e0db55ea8d50376dd4177d56a20a6cf3753a 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 
 /* Hack until we have a macro check for mandatory locks. */
 #ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i)  (((i)->i_mode & (S_ISGID|S_IXGRP)) == S_ISGID)
+#define IS_ISMNDLK(i)  (((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
+                        == (S_ISGID|S_IFREG))
 #endif
 
+/* Time difference margin in seconds for comparison. It is a
+   dynamically-tunable parameter via /proc/fs/nfs/time-diff-margin.
+ */
+extern long nfsd_time_diff_margin;
+
 /* Check for dir entries '.' and '..' */
 #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
 
@@ -236,8 +241,30 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
        inode = dentry->d_inode;
 
        err = inode_change_ok(inode, iap);
-       if (err)
+       if (err) {
+               /* It is very tricky. When you are not the file owner,
+                  but have the write permission, you should be allowed
+                  to set atime and mtime to the current time on the
+                  server. However, the NFS V2 protocol doesn't support
+                  it. It has been fixed in V3. Here we do this: if the
+                  current server time and atime/mtime are close enough,
+                  we use the current server time. */
+#define CURRENT_TIME_SET       (ATTR_ATIME_SET | ATTR_MTIME_SET)
+               if (iap->ia_mtime == iap->ia_atime
+                   && ((iap->ia_valid & (CURRENT_TIME_SET))
+                       == CURRENT_TIME_SET)) {
+                       time_t now = CURRENT_TIME;
+                       time_t delta = iap->ia_atime - now;
+                       if (delta < 0) delta = -delta;
+                       if (delta <= nfsd_time_diff_margin) {
+                               iap->ia_valid &= ~CURRENT_TIME_SET;
+                               goto current_time_ok;
+                       }
+               }
                goto out_nfserr;
+       }
+
+current_time_ok:
 
        /* The size case is special... */
        if (iap->ia_valid & ATTR_SIZE) {
@@ -248,15 +275,19 @@ printk("nfsd_setattr: size change??\n");
                        if (err)
                                goto out;
                }
+               DQUOT_INIT(inode);
                err = get_write_access(inode);
-               if (err)
+               if (err) {
+                       DQUOT_DROP(inode);
                        goto out_nfserr;
+               }
                /* N.B. Should we update the inode cache here? */
                inode->i_size = iap->ia_size;
                if (inode->i_op && inode->i_op->truncate)
                        inode->i_op->truncate(inode);
                mark_inode_dirty(inode);
                put_write_access(inode);
+               DQUOT_DROP(inode);
                iap->ia_valid &= ~ATTR_SIZE;
                iap->ia_valid |= ATTR_MTIME;
                iap->ia_mtime = CURRENT_TIME;
@@ -554,7 +585,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
        /* clear setuid/setgid flag after write */
        if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
                struct iattr    ia;
-               kernel_cap_t    saved_cap;
+               kernel_cap_t    saved_cap = 0;
 
                ia.ia_valid = ATTR_MODE;
                ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
@@ -658,10 +689,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                if (IS_ERR(dchild))
                        goto out_nfserr;
                fh_compose(resfhp, fhp->fh_export, dchild);
-               /* Lock the parent and check for errors ... */
-               err = fh_lock_parent(fhp, dchild);
-               if (err)
-                       goto out;
        } else {
                dchild = resfhp->fh_dentry;
                if (!fhp->fh_locked)
@@ -670,6 +697,15 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                dentry->d_parent->d_name.name,
                                dentry->d_name.name);
        }
+       err = nfserr_exist;
+       if (dchild->d_inode)
+               goto out;
+       if (!fhp->fh_locked) {
+               /* Lock the parent and check for errors ... */
+               err = fh_lock_parent(fhp, dchild);
+               if (err)
+                       goto out;
+       }
        /*
         * Make sure the child dentry is still negative ...
         */
@@ -695,8 +731,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        case S_IFCHR:
        case S_IFBLK:
                /* The client is _NOT_ required to do security enforcement */
-               if(!capable(CAP_SYS_ADMIN))
-               {
+               if(!capable(CAP_SYS_ADMIN)) {
                        err = -EPERM;
                        goto out;
                }
@@ -759,7 +794,7 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
        struct inode    *inode;
        struct iattr    newattrs;
        int             err;
-       kernel_cap_t    saved_cap;
+       kernel_cap_t    saved_cap = 0;
 
        err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
        if (err)
@@ -899,6 +934,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        /* Compose the fh so the dentry will be freed ... */
 out_compose:
        fh_compose(resfhp, fhp->fh_export, dnew);
+
 out:
        return err;
 
@@ -1091,6 +1127,15 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        DQUOT_DROP(tdir);
 
        nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
+
+       if (!err && odentry->d_inode) {
+               add_to_rename_cache(tdir->i_ino,
+                                   odentry->d_inode->i_dev,
+                                   fdir->i_ino,
+                                   odentry->d_inode->i_ino);
+       } else {
+               printk(": no inode in rename or err: %d.\n", err);
+       }
        dput(ndentry);
 
 out_dput_old:
@@ -1132,7 +1177,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        err = PTR_ERR(rdentry);
        if (IS_ERR(rdentry))
                goto out_nfserr;
-
        if (!rdentry->d_inode) {
                dput(rdentry);
                err = nfserr_noent;
@@ -1154,7 +1198,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                fh_unlock(fhp);
 
                dput(rdentry);
-
+               expire_by_dentry(rdentry);
        } else {
                /* It's RMDIR */
                /* See comments in fs/namei.c:do_rmdir */
@@ -1183,6 +1227,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                goto out_nfserr;
        if (EX_ISSYNC(fhp->fh_export))
                write_inode_now(dirp);
+
 out:
        return err;
 
@@ -1314,7 +1359,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
 {
        struct inode    *inode = dentry->d_inode;
        int             err;
-       kernel_cap_t    saved_cap;
+       kernel_cap_t    saved_cap = 0;
 
        if (acc == MAY_NOP)
                return 0;
@@ -1334,7 +1379,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
                inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 #ifndef CONFIG_NFSD_SUN
-        if (dentry->d_mounts != dentry) {
+       if (dentry->d_mounts != dentry) {
                return nfserr_perm;
        }
 #endif
index a55752abb0e9b8d3d1bcb99bac2e360ee2e9443d..b8b69d90f8f25552ef7bb0b9d8934174e8c91df8 100644 (file)
@@ -9,12 +9,18 @@
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
 
+/* We can make the delay loop inline, but we have to be very careful
+ * WRT scheduling for EV6 machines, to keep it consistent for all locations
+ * of invocations. This is a reasonable compromise.
+ */
+
 extern __inline__ void
 __delay(unsigned long loops)
 {
-       __asm__ __volatile__(".align 3\n"
-               "1:\tsubq %0,1,%0\n\t"
-               "bge %0,1b": "=r" (loops) : "0" (loops));
+       __asm__ __volatile__(".align 4\n"
+                    "1:\tsubq %0,1,%0\n\t"
+                    "bge %0,1b\n\t"
+                    "nop": "=r" (loops) : "0" (loops));
 }
 
 /*
index 7d8bdb94b2b70f5abd04aed1ff204ec47b09093d..5eb7823def6e27af86df165a1cd593bb2e9934b3 100644 (file)
@@ -261,6 +261,8 @@ static inline void iounmap(void *addr)
 {
 }
 
+#define ioremap_nocache(offset, size) ioremap((offset),(size))
+
 #ifndef readb
 # define readb(a)      _readb((unsigned long)(a))
 #endif
index c259a45ee837cf2be579099e358cf96576938fa0..ee7b04db991e88544810452c84c659e44124dba7 100644 (file)
@@ -45,7 +45,10 @@ enum fixed_addresses {
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
 #endif
 #ifdef CONFIG_X86_IO_APIC
-       FIX_IO_APIC_BASE,
+       FIX_IO_APIC_BASE_0,     /* IF YOU CHANGE THIS, PLEASE ALSO CHANGE */
+       FIX_IO_APIC_BASE_1,     /* MAX_IO_APICS in arch/i386/irq.h        */
+       FIX_IO_APIC_BASE_2,
+       FIX_IO_APIC_BASE_3,
 #endif
 #ifdef CONFIG_X86_VISWS_APIC
        FIX_CO_CPU,     /* Cobalt timer */
index 93a39537ac5cbbdf640b08498d85c94dfcf8f4fe..32bd71827d6a3471f2f035f99bac50caa0f0af15 100644 (file)
@@ -837,6 +837,7 @@ extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *inode);
 extern ino_t iunique(struct super_block *, ino_t);
 extern struct inode * iget(struct super_block *, unsigned long);
+extern struct inode * iget_in_use (struct super_block *, unsigned long);
 extern void clear_inode(struct inode *);
 extern struct inode * get_empty_inode(void);
 
index 45a6dc35be73bf573916db23c81c7799ab17bbd4..1b6253190f50f501354e818083f22f7171f79588 100644 (file)
@@ -42,7 +42,7 @@
 #endif
 
 #define DM6_PARTITION          0x54    /* has DDO: use xlated geom & offset */
-#define EZD_PARTITION          0x55    /* EZ-DRIVE:  same as DM6 (we think) */
+#define EZD_PARTITION          0x55    /* EZ-DRIVE: remap sector 1 to 0 */
 #define DM6_AUX1PARTITION      0x51    /* no DDO:  use xlated geom */
 #define DM6_AUX3PARTITION      0x53    /* no DDO:  use xlated geom */
        
diff --git a/include/linux/lockd/syscall.h b/include/linux/lockd/syscall.h
new file mode 100644 (file)
index 0000000..fd06d70
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * include/linux/lockd/syscall.h
+ *
+ * This file holds all declarations for the knfsd/lockd syscall
+ * interface.
+ *
+ */
+
+#ifndef LOCKD_SYSCALL_H
+#define LOCKD_SYSCALL_H
+
+#include <linux/nfsd/syscall.h>
+
+#define LOCKDCTL_SVC NFSCTL_LOCKD
+
+#ifdef __KERNEL__
+/*
+ * Kernel syscall implementation.
+ */
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+extern int     lockdctl(int, void *, void *);
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* LOCKD_SYSCALL_H */
index 6d43f98d7a0c6b4e87869910ce5c489e2eaa8f74..2acec5295f43aa54f841c17e02e369ca0a8942ed 100644 (file)
@@ -266,6 +266,9 @@ struct device
        struct Qdisc            *qdisc_list;
        unsigned long           tx_queue_len;   /* Max frames per queue allowed */
 
+       /* Bridge stuff */
+       int                     bridge_port_id;         
+       
        /* Pointers to interface service routines.      */
        int                     (*open)(struct device *dev);
        int                     (*stop)(struct device *dev);
index a0ba9587f4c2a4b7027dba8aea1833838a6cda55..ba7fef44fd67f26e4876b95f5b4d57697bda8182 100644 (file)
@@ -107,6 +107,7 @@ void        fh_update(struct svc_fh *);
 void   fh_put(struct svc_fh *);
 void   nfsd_fh_flush(kdev_t);
 void   nfsd_fh_init(void);
+void   nfsd_fh_shutdown(void);
 void   nfsd_fh_free(void);
 
 void   expire_all(void);
@@ -182,6 +183,11 @@ fh_unlock(struct svc_fh *fhp)
        }
 }
 
+/*
+ * This is a long term cache to help find renamed files.
+ */
+void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
+
 #endif /* __KERNEL__ */
 
 #endif /* NFSD_FH_H */
index 4ce3f06cdc7727ab990a63b30f526e7d55b0de0a..194919e566cc3a9c13bc9bb03692ca40209dfeed 100644 (file)
@@ -18,6 +18,7 @@ struct nfsd_stats {
        unsigned int    fh_fixup;       /* dentry fixup validated */
        unsigned int    fh_lookup;      /* new lookup required */
        unsigned int    fh_stale;       /* FH stale error */
+       unsigned int    fh_concurrent;  /* concurrent request */
 };
 
 #ifdef __KERNEL__
index 019d33f7664e8262fba1187412d140defaa48f98..f7bd1174dd9645b3379f37e70ffa195c7c375f8f 100644 (file)
@@ -35,6 +35,9 @@
 #define NFSCTL_GETFH           6       /* get an fh by ino (used by mountd) */
 #define NFSCTL_GETFD           7       /* get an fh by path (used by mountd) */
 
+/* Above this is for lockd. */
+#define NFSCTL_LOCKD           0x10000
+
 /* SVC */
 struct nfsctl_svc {
        unsigned short          svc_port;
@@ -121,11 +124,7 @@ union nfsctl_res {
 /*
  * Kernel syscall implementation.
  */
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 extern asmlinkage int  sys_nfsservctl(int, void *, void *);
-#else
-#define sys_nfsservctl         sys_ni_syscall
-#endif
 extern int             exp_addclient(struct nfsctl_client *ncp);
 extern int             exp_delclient(struct nfsctl_client *ncp);
 extern int             exp_export(struct nfsctl_export *nxp);
index 1f5a62dd992622537448976bed85eece53065955..9bf5efd806e4413cfced52c04e241d2efe609ba4 100644 (file)
@@ -38,11 +38,15 @@ static inline unsigned long page_address(struct page * page)
  */
 #define page_cache_entry(x)    (mem_map + MAP_NR(x))
 
-#define PAGE_HASH_BITS 12
-#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
+#define PAGE_HASH_BITS page_hash_bits
+#define PAGE_HASH_MASK page_hash_mask
 
 extern unsigned long page_cache_size; /* # of pages currently in the hash table */
-extern struct page * page_hash_table[PAGE_HASH_SIZE];
+extern unsigned int page_hash_bits;
+extern unsigned int page_hash_mask;
+extern struct page **page_hash_table;
+
+extern void page_cache_init(unsigned long);
 
 /*
  * We use a power-of-two hash table to avoid a modulus,
@@ -53,12 +57,10 @@ extern struct page * page_hash_table[PAGE_HASH_SIZE];
 static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
 {
 #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
-#define o (offset >> PAGE_SHIFT)
-#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
-       return s(i+o) & (PAGE_HASH_SIZE-1);
+#define o ((offset >> PAGE_SHIFT) + (offset & ~PAGE_MASK))
+       return ((i+o) & PAGE_HASH_MASK);
 #undef i
 #undef o
-#undef s
 }
 
 #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
index 8f5eda0c6c34bf9fc4ad97bdd9bba5934d123f28..2efb9438c80222f7e0fda5a8f0c94825d1995cd0 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82441      0x1237
 #define PCI_DEVICE_ID_INTEL_82380FB    0x124b
 #define PCI_DEVICE_ID_INTEL_82439      0x1250
+#define PCI_DEVICE_ID_INTEL_MEGARAID   0x1960
 #define PCI_DEVICE_ID_INTEL_82371SB_0  0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1  0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2  0x7020
 #define PCI_DEVICE_ID_INTEL_82371AB    0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2  0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3  0x7113
-#define PCI_VENDOR_ID_COMPUTONE                0x8e0e
-#define PCI_DEVICE_ID_COMPUTONE_IP2EX  0x0291
-
 #define PCI_DEVICE_ID_INTEL_82443LX_0  0x7180
 #define PCI_DEVICE_ID_INTEL_82443LX_1  0x7181
 #define PCI_DEVICE_ID_INTEL_82443BX_0  0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1  0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2  0x7192
 #define PCI_DEVICE_ID_INTEL_P6         0x84c4
-#define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
+#define PCI_DEVICE_ID_INTEL_82450GX    0x84c4
+#define PCI_DEVICE_ID_INTEL_82453GX    0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX    0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX    0x84cb
+
+#define PCI_VENDOR_ID_COMPUTONE                0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX  0x0291
 
 #define PCI_VENDOR_ID_KTI              0x8e2e
 #define PCI_DEVICE_ID_KTI_ET32P2       0x3000
@@ -1318,6 +1321,9 @@ extern inline struct pci_dev *pci_find_class(unsigned int class, struct pci_dev
 extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
 { return NULL; }
 
+extern inline void pci_set_master(struct pci_dev *dev)
+{ return; }
+
 #endif /* !CONFIG_PCI */
 
 #endif /* __KERNEL__ */
index e1b0a89363e30a38132c2c645712f02199f5492a..77d7d74136368d92f977376caae40e925f3462f1 100644 (file)
@@ -466,6 +466,7 @@ extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *pa
 extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
 extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
+extern struct proc_dir_entry proc_root;
 
-#endif
+#endif /* CONFIG_PROC_FS */
 #endif /* _LINUX_PROC_FS_H */
index 4ab59ed1c500f39e76c1a24e0e75d09cefe86342..4558fa1f3323e16a4e7d5cdf3e64d924a689073b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
+#include <asm/atomic.h>
 
 /*
  * RPC service.
@@ -29,7 +30,7 @@ struct svc_serv {
        struct svc_sock *       sv_sockets;     /* pending sockets */
        struct svc_program *    sv_program;     /* RPC program */
        struct svc_stat *       sv_stats;       /* RPC statistics */
-       unsigned int            sv_nrthreads;   /* # of server threads */
+       atomic_t                sv_nrthreads;   /* # of server threads */
        unsigned int            sv_bufsz;       /* datagram buffer size */
        unsigned int            sv_xdrsize;     /* XDR buffer size */
 
index 5f8dc87689f11548640b433746ef54ec0b0d1ad2..9e6f3a76aba7320d2a6244c69371a3e9277491bb 100644 (file)
@@ -10,6 +10,7 @@
 #define SUNRPC_SVCSOCK_H
 
 #include <linux/sunrpc/svc.h>
+#include <asm/atomic.h>
 
 /*
  * RPC server socket.
@@ -23,7 +24,7 @@ struct svc_sock {
        struct sock *           sk_sk;          /* INET layer */
 
        struct svc_serv *       sk_server;      /* service for this socket */
-       unsigned char           sk_inuse;       /* use count */
+       atomic_t                sk_inuse;       /* use count */
        unsigned char           sk_busy;        /* enqueued/receiving */
        unsigned char           sk_conn;        /* conn pending */
        unsigned char           sk_close;       /* dead or dying */
index 4d79fc6277d1b24797766268d603ac5cb5dc8b6e..cbf4b4c3c472451e1ee82d70574e075a1e062e4a 100644 (file)
 #define Forwarding     3                         /* (4 4 4)     */
 #define Blocking       4                         /* (4.4.1)     */
 
-#define No_of_ports 8
+
+/* MAG Yich! Easiest way of giving a configurable number of ports
+ * If you want more than 32, change BR_MAX_PORTS and recompile brcfg!
+ */
+#define BR_MAX_PORTS (32)
+#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS
+#undef CONFIG_BRIDGE_NUM_PORTS
+#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS
+#endif
+#define No_of_ports CONFIG_BRIDGE_NUM_PORTS
 /* arbitrary choice, to allow the code below to compile */
 
 #define All_ports (No_of_ports + 1)
@@ -147,6 +156,7 @@ typedef struct {
        unsigned int     top_change;              /* (4.5.3.12)  */
        unsigned short   topology_change_time;    /* (4.5.3.13)  */
        unsigned short   hold_time;               /* (4.5.3.14)  */
+       unsigned int     instance;
 } Bridge_data;
 
 /** Port Parameters (4.5.5) **/
@@ -160,7 +170,10 @@ typedef struct {
        unsigned short   designated_port;         /* (4.5.5.7)   */
        unsigned int     top_change_ack;          /* (4.5.5.8)   */
        unsigned int     config_pending;          /* (4.5.5.9)   */
-       struct device *dev;     
+        bridge_id_t      ifmac; 
+        unsigned int     admin_state;
+       char             ifname[IFNAMSIZ]; /* Make life easier for brcfg */
+        struct device *dev;    
        struct fdb *fdb;        /* head of per port fdb chain */
 } Port_data;
 
@@ -245,13 +258,14 @@ typedef struct {
 struct br_stat {
        unsigned int flags;
        Bridge_data bridge_data;
-       Port_data port_data[No_of_ports];
        unsigned int policy;
        unsigned int exempt_protocols;
        unsigned short protocols[BR_MAX_PROTOCOLS];
        unsigned short prot_id[BR_MAX_PROT_STATS];      /* Protocol encountered */
        unsigned int prot_counter[BR_MAX_PROT_STATS];   /* How many packets ? */
        br_stats_counter packet_cnts;
+       unsigned int    num_ports;
+       Port_data port_data[BR_MAX_PORTS + 1];
 };
 
 /* defined flags for br_stat.flags */
@@ -274,7 +288,7 @@ struct br_cf {
 #define        BRCMD_SET_BRIDGE_PRIORITY       5       /* arg1 = priority */
 #define        BRCMD_SET_PORT_PRIORITY 6       /* arg1 = port, arg2 = priority */
 #define        BRCMD_SET_PATH_COST     7       /* arg1 = port, arg2 = cost */
-#define        BRCMD_DISPLAY_FDB       8       /* arg1 = port */
+#define        BRCMD_DISPLAY_FDB       8
 #define        BRCMD_ENABLE_DEBUG      9
 #define        BRCMD_DISABLE_DEBUG     10
 #define BRCMD_SET_POLICY       11      /* arg1 = default policy (1==bridge all) */
@@ -283,14 +297,19 @@ struct br_cf {
 #define BRCMD_DISABLE_PROT_STATS 14
 #define BRCMD_ZERO_PROT_STATS  15
 #define BRCMD_TOGGLE_STP       16
+#define BRCMD_IF_ENABLE                17      /* arg1 = if_index */
+#define BRCMD_IF_DISABLE       18      /* arg1 = if_index */
+#define BRCMD_SET_IF_PRIORITY  19      /* arg1 = if_index, arg2 = priority */
+#define        BRCMD_SET_IF_PATH_COST  20      /* arg1 = if_index, arg2 = cost */
 
 /* prototypes of exported bridging functions... */
 
+#ifdef __KERNEL__
 void br_init(void);
 int br_receive_frame(struct sk_buff *skb);     /* 3.5 */
 int br_tx_frame(struct sk_buff *skb);
+int brg_init(void);
 int br_ioctl(unsigned int cmd, void *arg);
-int br_protocol_ok(unsigned short protocol);
 void requeue_fdb(struct fdb *node, int new_port);
 
 struct fdb *br_avl_find_addr(unsigned char addr[6]);
@@ -298,8 +317,15 @@ struct fdb *br_avl_insert (struct fdb * new_node);
 void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length);
 int br_tree_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 void br_avl_delete_by_port(int port);
+int br_call_bridge(struct sk_buff *skb, unsigned short type);
+void br_spacedevice_register(void);
+
 /* externs */
 
 extern struct br_stat br_stats;
 extern Port_data port_info[];
 
+#endif
+
+
index 8b050c63a8a332642e1a437ce255f8bbee57bf31..0e7e4bb6e37d4e5804703b0beb37580e45c47b66 100644 (file)
 #include <net/checksum.h>
 
 /* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest.  I'll experiment with dynamic table growth later.
+ * Half of the table is for TIME_WAIT, the other half is for the
+ * rest.
+ *
+ * This needs to be shared by v4 and v6 because the lookup and hashing
+ * code needs to work with different AF's yet the port space is
+ * shared.
  */
-#define TCP_HTABLE_SIZE                512
+extern unsigned int tcp_ehash_size;
+extern struct sock **tcp_ehash;
 
 /* 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       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
- *             the port space is shared.
- */
-extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
 extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -81,7 +77,8 @@ struct tcp_bind_bucket {
        struct tcp_bind_bucket  **pprev;
 };
 
-extern struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+extern unsigned int tcp_bhash_size;
+extern struct tcp_bind_bucket **tcp_bhash;
 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);
@@ -109,7 +106,7 @@ static __inline__ void tcp_reg_zap(struct sock *sk)
 /* These are AF independent. */
 static __inline__ int tcp_bhashfn(__u16 lport)
 {
-       return (lport & (TCP_BHTABLE_SIZE - 1));
+       return (lport & (tcp_bhash_size - 1));
 }
 
 /* This is a TIME_WAIT bucket.  It works around the memory consumption
index ed3643f87d9e1b2793004eccd33c214c94dc6fb6..cb9861ebf83fd4617bb45f06a99c5fbdc9612f4d 100644 (file)
@@ -1211,6 +1211,7 @@ asmlinkage void __init start_kernel(void)
        dcache_init();
        vma_init();
        buffer_init(memory_end-memory_start);
+       page_cache_init(memory_end-memory_start);
        signals_init();
        inode_init();
        file_table_init();
index 5c67a540952f62eff5d6ad60736cd936d2f33318..c617c0d8431e4c11cefeb5a5877d5f17d919c9dd 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -694,7 +694,7 @@ asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
                 interruptible_sleep_on(&queue.sleeper);
 
                 /*
-                 * If queue.status == 1 we where woken up and
+                 * If queue.status == 1 we were woken up and
                  * have to retry else we simply return.
                  * If an interrupt occurred we have to clean up the
                  * queue
index 14a1cbaba1fa0c41ea10a39e6d0c57785f8832f4..f08a62ea87e751b1586293f0caf3626f8f9bd022 100644 (file)
@@ -54,6 +54,9 @@ extern int blkdev_release(struct inode * inode);
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 extern int (*do_nfsservctl)(int, void *, void *);
 #endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+extern int (*do_lockdctl)(int, void *, void *);
+#endif
 
 extern void *sys_call_table;
 
@@ -121,6 +124,7 @@ EXPORT_SYMBOL(__fput);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget_in_use);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
@@ -193,6 +197,9 @@ EXPORT_SYMBOL(ROOT_DEV);
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
 #endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+EXPORT_SYMBOL(do_lockdctl);
+#endif
 
 /* device registration */
 EXPORT_SYMBOL(register_chrdev);
index a474f38ac436be5e14df54872496f6ef3b335d20..882e61311c42c7e4580c37102381b612119c36c8 100644 (file)
@@ -169,8 +169,10 @@ static ctl_table kern_table[] = {
         0644, NULL, &proc_doutsstring, &sysctl_string},
        {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
         0644, NULL, &proc_dointvec},
+#ifdef CONFIG_PROC_FS   
        {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
         0600, NULL, &proc_dointvec_bset},
+#endif  
 #ifdef CONFIG_BLK_DEV_INITRD
        {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
         0644, NULL, &proc_dointvec},
index 9d9b1f271d2a83c10fba7949854ffcd547417af7..68e3f8c2b67d99ae7777c0a266e1f2275dc0fc71 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/swapctl.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -32,7 +33,8 @@
  */
 
 unsigned long page_cache_size = 0;
-struct page * page_hash_table[PAGE_HASH_SIZE];
+unsigned int page_hash_bits, page_hash_mask;
+struct page **page_hash_table;
 
 /* 
  * Define a request structure for outstanding page write requests
@@ -1757,3 +1759,34 @@ int kpiod(void * unused)
                }
        }
 }
+
+void __init page_cache_init(unsigned long memory_size)
+{
+       unsigned long htable_size;
+       long order;
+
+       htable_size  = memory_size >> PAGE_SHIFT;
+       htable_size *= sizeof(struct page *);
+       for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
+               ;
+
+       do {
+               unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
+
+               page_hash_mask = (tmp - 1UL);
+
+               page_hash_bits = 0;
+               while((tmp >>= 1UL) != 0UL)
+                       page_hash_bits++;
+
+               page_hash_table = (struct page **)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while(page_hash_table == NULL && --order >= 0L);
+
+       printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+              (1 << page_hash_bits), order, (PAGE_SIZE << order));
+       if (!page_hash_table)
+               panic("Failed to allocate page hash table\n");
+       memset(page_hash_table, 0,
+              (PAGE_HASH_MASK + 1UL) * sizeof(struct page *));
+}
index eb0a0203f4d303cd11051ce5e8ba62d82af118a8..0afca8c0fb756dfd9eef68de588e6f6017ce2208 100644 (file)
@@ -90,7 +90,10 @@ int fc_rebuild_header(struct sk_buff *skb)
                printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype));
                return 0;
        }
-
+#ifdef CONFIG_INET
        return arp_find(fch->daddr, skb);
+#else
+       return 0; /* Cannot happen because of ETH_P_IP test */
+#endif 
 }
        
index ed8510209a731bed5dc40a3e3cc406f306517edb..a5c6446380b705f04ad2c0d3184f92a434d29a34 100644 (file)
@@ -39,6 +39,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+  if [ "$CONFIG_BRIDGE" != "n" ]; then
+       int '  Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8
+  fi
   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
 #  if [ "$CONFIG_LLC" = "y" ]; then
 #   bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
index 50ed9e84916b26d99a861b95a0e55481f3b4222d..aa5e2e8dbd5195adf2f1784b9f5213dc511d8443 100644 (file)
  *                     so blame me first if its broken ;)
  *
  *     Robert Pintarelli:      fixed bug in bpdu time values
+ *
+ *      Matthew Grant:  start ports disabled.  
+ *                      auto-promiscuous mode on port enable/disable
+ *                      fleshed out interface event handling, interfaces 
+ *                        now register with bridge on module load as well as ifup
+ *                      port control ioctls with ifindex support
+ *                      brg0 logical ethernet interface
+ *                      reworked brcfg to take interface arguments
+ *                      added support for changing the hardware address
+ *                      generally made bridge a lot more usable.
  *     
  *     Todo:
- *             Don't bring up devices automatically. Start ports disabled
- *     and use a netlink notifier so a daemon can maintain the bridge
+ *     Use a netlink notifier so a daemon can maintain the bridge
  *     port group (could we also do multiple groups ????).
  *             A nice /proc file interface.
  *             Put the path costs in the port info and devices.
@@ -53,6 +62,7 @@
  */
  
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
@@ -72,6 +85,7 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <linux/rtnetlink.h>
 #include <net/br.h>
 #include <linux/proc_fs.h>
 
@@ -145,11 +159,20 @@ static void br_add_local_mac(unsigned char *mac);
 static int br_flood(struct sk_buff *skb, int port);
 static int br_drop(struct sk_buff *skb);
 static int br_learn(struct sk_buff *skb, int port);    /* 3.8 */
+static int br_protocol_ok(unsigned short protocol);
+static int br_find_port(int ifindex);
+static void br_get_ifnames(void);
+static int brg_rx(struct sk_buff *skb, int port);
 
 static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 static Bridge_data     bridge_info;                      /* (4.5.3)     */
 Port_data       port_info[All_ports];            /* (4.5.5)     */
 
+/* MAG: Maximum port registered - used to speed up flooding and to make
+ * have a large ports array more efficient
+ */
+static int max_port_used = 0; 
+
 /* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
 struct fdb     *newfdb[All_ports];
 int allocated_fdb_cnt = 0;
@@ -190,6 +213,30 @@ static struct notifier_block br_dev_notifier={
        0
 };
 
+
+/* 
+ * the following data is for the bridge network device
+ */
+struct brg_if {
+  struct device dev;
+  char name[IFNAMSIZ];
+};
+static struct brg_if brg_if;
+
+/* 
+ * Here to save linkage? problems
+ */
+
+static inline int find_port(struct device *dev)
+{
+       int i;
+
+       for (i = One; i <= No_of_ports; i++)
+               if (port_info[i].dev == dev)
+                       return(i);
+       return(0);
+}
+
 /*
  * Implementation of Protocol specific bridging
  *
@@ -202,7 +249,7 @@ static struct notifier_block br_dev_notifier={
 
 /* Checks if that protocol type is to be bridged */
 
-int br_protocol_ok(unsigned short protocol)
+static int inline br_protocol_ok(unsigned short protocol)
 {
        unsigned x;
        
@@ -843,8 +890,14 @@ __initfunc(void br_init(void))
 {                                                /* (4.8.1)     */
        int port_no;
 
-       printk(KERN_INFO "NET4: Ethernet Bridge 005 for NET4.0\n");
+       printk(KERN_INFO "NET4: Ethernet Bridge 007 for NET4.0\n");
 
+       /* Set up brg device information */
+       bridge_info.instance = 0;
+       brg_init();
+
+       max_port_used = 0;
+       
        /*
         * Form initial topology change time.
         * The topology change timer is only used if this is the root bridge.
@@ -874,8 +927,8 @@ __initfunc(void br_init(void))
        stop_topology_change_timer();
        memset(newfdb, 0, sizeof(newfdb));
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.1.4) */
-               /* initial state = Enable */
-               user_port_state[port_no] = ~Disabled;
+               /* initial state = Disable */
+               user_port_state[port_no] = Disabled;
                port_priority[port_no] = 128;
                br_init_port(port_no);
                disable_port(port_no);
@@ -1306,6 +1359,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        if (dev->flags & IFF_LOOPBACK)
                return(NOTIFY_DONE);
 
+       if (dev == &brg_if.dev)
+         return(NOTIFY_DONE);  /* Don't attach the brg device to a port! */
+       
        switch (event) 
        {
                case NETDEV_DOWN:
@@ -1335,6 +1391,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                                {
                                        port_info[i].dev = dev;
                                        port_info[i].port_id = i;
+                                       dev->bridge_port_id = i;
+                                       if( i > max_port_used ) 
+                                               max_port_used = i;
                                        /* set bridge addr from 1st device addr */
                                        if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) &&
                                                (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) 
@@ -1344,7 +1403,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                                                        bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768);
                                                set_bridge_priority(&bridge_info.bridge_id);
                                        }
+                                       /* Add local MAC address */
                                        br_add_local_mac(dev->dev_addr);
+                                       /* Save MAC address for latter change address events */
+                                       memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
                                        if((br_stats.flags & BR_UP) &&
                                                (user_port_state[i] != Disabled)) 
                                        {
@@ -1362,19 +1424,122 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
                                }
                        }
                        break;
+               case NETDEV_REGISTER:
+                       if (br_stats.flags & BR_DEBUG) 
+                               printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n");
+                       /* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */
+                       /* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */
+                       /* Only handle ethernet ports */
+                       if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
+                               return NOTIFY_DONE;
+                       /* printk(KERN_ERR "br_device_event: Looking for port...\n"); */
+                       for (i = One; i <= No_of_ports; i++) 
+                       {
+                               if (port_info[i].dev == NULL || port_info[i].dev == dev) 
+                               {
+                                       /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */
+                                       port_info[i].dev = dev;
+                                       port_info[i].port_id = i;
+                                       dev->bridge_port_id = i;
+                                       if( i > max_port_used )
+                                               max_port_used = i;
+                                       /* handle local MAC address minuplations */
+                                       br_add_local_mac(dev->dev_addr);
+                                       memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
+                                       return NOTIFY_DONE;
+                                       break;
+                               }
+                       }
+                       break;
                case NETDEV_UNREGISTER:
                        if (br_stats.flags & BR_DEBUG)
                                printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n");
                         i = find_port(dev);
                         if (i > 0) {
                                br_avl_delete_by_port(i);
+                               memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
                                port_info[i].dev = NULL;
                        }
                        break;
+               case NETDEV_CHANGEADDR:
+                       if (br_stats.flags & BR_DEBUG)
+                               printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n");
+                        i = find_port(dev);
+                        if (i <= 0)  
+                         break;
+                       if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0)
+                         break; /* Don't worry about a change of hardware broadcast address! */
+                       if (dev->start) {
+                         printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", 
+                                dev->name);
+                       /*  return NOTIFY_BAD;  It SHOULD be this, but I want to be friendly... */
+                         return NOTIFY_DONE;
+                       }
+                       br_avl_delete_by_port(i);
+                       memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
+                       break;
        }
        return NOTIFY_DONE;
 }
 
+/* Routine to loop over device list and register 
+ * interfaces to bridge.  Called from last part of net_dev_init just before
+ * bootp/rarp interface setup
+ */
+void br_spacedevice_register(void) 
+{
+       struct device *dev;
+       for( dev = dev_base; dev != NULL; dev = dev->next)
+       {
+               br_device_event(NULL, NETDEV_REGISTER, dev);
+       }
+}      
+
+
+/* This is for SPEED in the kernel in net_bh.c */
+
+int br_call_bridge(struct sk_buff *skb, unsigned short type)
+{
+       int port;
+       struct device *dev;
+  
+#if 0  /* Checked first in handle_bridge to save expense of function call */ 
+       if(!(br_stats.flags & BR_UP))
+               return 0;
+#endif
+  
+       dev = skb->dev;
+
+       /* Check for brg0 device
+        */
+       if (dev == &brg_if.dev)
+               return 0;
+                
+       port = dev->bridge_port_id;
+
+       if(!port)
+               return 0;
+
+       /* Sanity - make sure we are not leaping off into fairy space! */
+       if ( port < 0 || port > max_port_used || port_info[port].dev != dev) {
+               if (net_ratelimit())
+                       printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n",
+                               dev->name,
+                               dev->bridge_port_id);
+               return 0;
+       }
+
+       if(user_port_state[port] == Disabled)
+               return 0;
+  
+       if (!br_protocol_ok(ntohs(type)))
+               return 0;
+
+       return 1;
+
+}
+
+
 /*
  * following routine is called when a frame is received
  * from an interface, it returns 1 when it consumes the
@@ -1383,9 +1548,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 
 int br_receive_frame(struct sk_buff *skb)      /* 3.5 */
 {
-       int port;
+       int port, ret;
        Port_data  *p;
        struct ethhdr *eth;
+       struct device *dev;
        
        /* sanity */
        if (!skb) {
@@ -1393,17 +1559,32 @@ int br_receive_frame(struct sk_buff *skb)       /* 3.5 */
                return(1);
        }
 
+       dev = skb->dev;
+
+       /* Check for brg0 device 
+        */
+       if (dev == &brg_if.dev)
+               return 0;
+
        skb->pkt_bridged = IS_BRIDGED;
 
        /* check for loopback */
-       if (skb->dev->flags & IFF_LOOPBACK)
+       if (dev->flags & IFF_LOOPBACK)
                return 0 ;
 
-       port = find_port(skb->dev);
+#if 0
+       port = find_port(dev);
+#else
+       port = dev->bridge_port_id;
+#endif
        
        if(!port)
                return 0;
        
+       /* Hand off to brg_rx BEFORE we screw up the skb */
+       if(brg_rx(skb, port))
+         return(1);
+
        skb->nh.raw = skb->mac.raw;
        eth = skb->mac.ethernet;
        p = &port_info[port];
@@ -1435,9 +1616,9 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */
        switch (p->state) 
        {
                case Learning:
-                       if(br_learn(skb, port)) 
+                       if((ret = br_learn(skb, port))) 
                        {       /* 3.8 */
-                               ++br_stats_cnt.drop_multicast;
+                               if (ret > 0) ++br_stats_cnt.drop_multicast;
                                return br_drop(skb);
                        }
                        /* fall through */
@@ -1452,8 +1633,8 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */
                 */
                        break;
                case Forwarding:
-                       if(br_learn(skb, port)) {       /* 3.8 */
-                               ++br_stats_cnt.drop_multicast;
+                       if((ret = br_learn(skb, port))) {       /* 3.8 */
+                               if (ret > 0) ++br_stats_cnt.drop_multicast;
                                return br_drop(skb);
                        }
                        /* Now this frame came from one of bridged
@@ -1577,7 +1758,11 @@ static inline int mcast_quench(struct fdb *f)
 
 /*
  * this routine returns 0 when it learns (or updates) from the
- * frame, and 1 if we must dropped the frame.
+ * frame, and 1 if we must dropped the frame due to multicast
+ * limitations, or -1 because of not enough memory.
+ *
+ * NB Can be called when skb->nh.raw is NOT set up when
+ * receiving frames on brg0 via brg_rx
  */
 
 static int br_learn(struct sk_buff *skb, int port)     /* 3.8 */
@@ -1600,8 +1785,8 @@ static int br_learn(struct sk_buff *skb, int port)        /* 3.8 */
                newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
                if (!f) 
                {
-                       printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
-                       return(-1); /* this drop the frame */
+                       printk(KERN_WARNING "br_learn: unable to malloc fdb\n");
+                       return(-1); /* this drops the frame */
                }
        }
        f->port = port; /* source port */
@@ -1819,6 +2004,9 @@ static int br_flood(struct sk_buff *skb, int port)
        {
                if (i == port)  /* don't send back where we got it */
                        continue;
+               if (i > max_port_used)
+                       /* Don't go scanning empty port entries */
+                       break;
                if (port_info[i].state == Forwarding) 
                {
                        nskb = skb_clone(skb, GFP_ATOMIC);
@@ -1840,16 +2028,6 @@ static int br_flood(struct sk_buff *skb, int port)
        return(0);
 }
 
-static int find_port(struct device *dev)
-{
-       int i;
-
-       for (i = One; i <= No_of_ports; i++)
-               if (port_info[i].dev == dev)
-                       return(i);
-       return(0);
-}
-
 /*
  *     FIXME: This needs to come from the device structs, eg for
  *     10,100,1Gbit ethernet.
@@ -1956,17 +2134,62 @@ struct fdb_info *get_fdb_info(int user_buf_size, int *copied,int *notcopied)
        return fdbis;
 }
 
+
+/* Fill in interface names in port_info structure
+ */
+static void br_get_ifdata(void) {
+       int i;
+
+       for(i=One;i<=No_of_ports; i++) {
+
+               port_info[i].admin_state = user_port_state[i]; 
+               
+               /* memset IS needed.  Kernel strncpy does NOT NULL terminate 
+                * strings when limit reached 
+                */
+               memset(port_info[i].ifname, 0, IFNAMSIZ); 
+               if( port_info[i].dev == 0 )
+                       continue;
+               strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1);
+               /* Being paranoid */
+               port_info[i].ifname[IFNAMSIZ-1] = '\0';
+       }
+}
+
+/* Given an interface index, loop over port array to see if configured.  If
+   so, return port number, otherwise error */ 
+static int br_find_port(int ifindex) 
+{
+  int i;
+  
+  for(i=1; i <= No_of_ports; i++) {
+    if (port_info[i].dev == 0)
+      continue;
+    if (port_info[i].dev->ifindex == ifindex)
+      return(i);
+  }
+  
+  return -EUNATCH;  /* Tell me if this is incorrect error code for this case */
+} 
+
+
 int br_ioctl(unsigned int cmd, void *arg)
 {
-       int err, i;
+       int err, i, ifflags;
        struct br_cf bcf;
        bridge_id_t new_id;
-
+       struct device *dev;
+       
        switch(cmd)
        {
                case SIOCGIFBR: /* get bridging control blocks */
                        memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
-                       memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
+
+                       /* Fill in interface names in port_info*/
+                       br_get_ifdata();
+                       
+                       br_stats.num_ports = No_of_ports;
+                       memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports);
 
                        err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
                        if (err)
@@ -2032,16 +2255,28 @@ int br_ioctl(unsigned int cmd, void *arg)
                                        }
                                        br_stats.flags ^= BR_STP_DISABLED;
                                        break;
+                               case BRCMD_IF_ENABLE:
+                                       bcf.arg1 = br_find_port(bcf.arg1);
+                                       if (bcf.arg1 < 0)
+                                               return(bcf.arg1);
                                case BRCMD_PORT_ENABLE:
                                        if (port_info[bcf.arg1].dev == 0)
                                                return(-EINVAL);
                                        if (user_port_state[bcf.arg1] != Disabled)
                                                return(-EALREADY);
                                        printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
+                                       dev = port_info[bcf.arg1].dev;
+                                       ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+                                         |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+                                       dev_change_flags(dev, ifflags|IFF_PROMISC);
                                        user_port_state[bcf.arg1] = ~Disabled;
                                        if(br_stats.flags & BR_UP)
                                                enable_port(bcf.arg1);
                                        break;
+                               case BRCMD_IF_DISABLE:
+                                       bcf.arg1 = br_find_port(bcf.arg1);
+                                       if (bcf.arg1 < 0)
+                                               return(bcf.arg1);
                                case BRCMD_PORT_DISABLE:
                                        if (port_info[bcf.arg1].dev == 0)
                                                return(-EINVAL);
@@ -2051,12 +2286,20 @@ int br_ioctl(unsigned int cmd, void *arg)
                                        user_port_state[bcf.arg1] = Disabled;
                                        if(br_stats.flags & BR_UP)
                                                disable_port(bcf.arg1);
+                                       dev = port_info[bcf.arg1].dev;
+                                       ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+                                         |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+                                       dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC);
                                        break;
                                case BRCMD_SET_BRIDGE_PRIORITY:
                                        new_id = bridge_info.bridge_id;
                                        new_id.BRIDGE_PRIORITY = htons(bcf.arg1);
                                        set_bridge_priority(&new_id);
                                        break;
+                               case BRCMD_SET_IF_PRIORITY:
+                                       bcf.arg1 = br_find_port(bcf.arg1);
+                                       if (bcf.arg1 < 0)
+                                               return(bcf.arg1);
                                case BRCMD_SET_PORT_PRIORITY:
                                        if((port_info[bcf.arg1].dev == 0)
                                            || (bcf.arg2 & ~0xff))
@@ -2064,6 +2307,10 @@ int br_ioctl(unsigned int cmd, void *arg)
                                        port_priority[bcf.arg1] = bcf.arg2;
                                        set_port_priority(bcf.arg1);
                                        break;
+                               case BRCMD_SET_IF_PATH_COST:
+                                       bcf.arg1 = br_find_port(bcf.arg1);
+                                       if (bcf.arg1 < 0)
+                                               return(bcf.arg1);
                                case BRCMD_SET_PATH_COST:
                                        if (port_info[bcf.arg1].dev == 0)
                                                return(-EINVAL);
@@ -2145,3 +2392,385 @@ static int br_cmp(unsigned int *a, unsigned int *b)
        }
        return(0);
 }
+
+
+
+
+/* --------------------------------------------------------------------------------
+ *
+ *
+ *  Bridge network device here for future modularization - device structures
+ *  must be 'static' inside bridge instance
+ *  Modelled after sch_teql.c
+ * 
+ */
+
+
+
+/*
+ *     Index to functions.
+ */
+
+int        brg_probe(struct device *dev);
+static int  brg_open(struct device *dev);
+static int  brg_start_xmit(struct sk_buff *skb, struct device *dev);
+static int  brg_close(struct device *dev);
+static struct net_device_stats *brg_get_stats(struct device *dev);
+static void brg_set_multicast_list(struct device *dev);
+
+/*
+ *     Board-specific info in dev->priv.
+ */
+
+struct net_local
+{
+       __u32           groups;
+       struct net_device_stats stats;
+};
+
+
+
+
+/*
+ *     To call this a probe is a bit misleading, however for real
+ *     hardware it would have to check what was present.
+ */
+__initfunc(int brg_probe(struct device *dev))
+{
+  unsigned int bogomips;
+  struct timeval utime;
+
+  printk(KERN_INFO "%s: network interface for Ethernet Bridge 007/NET4.0\n", dev->name);
+
+  /*
+   *   Initialize the device structure.
+   */
+  
+  dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+  if (dev->priv == NULL)
+    return -ENOMEM;
+  memset(dev->priv, 0, sizeof(struct net_local));
+
+  /* Set up MAC address based on BogoMIPs figure for first CPU and time
+   */ 
+  bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
+  get_fast_time(&utime);
+
+  /* Ummmm....  YES! */
+  dev->dev_addr[0] = '\xFE';
+  dev->dev_addr[1] = '\xFD';
+  dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
+  dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
+  dev->dev_addr[3] = bogomips & 0xFF;
+  dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
+  dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
+  
+  printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
+        dev->name,
+        dev->dev_addr[0],
+        dev->dev_addr[1],
+        dev->dev_addr[2],
+        dev->dev_addr[3],
+        dev->dev_addr[4],
+        dev->dev_addr[5]);
+
+  
+  printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
+
+  /*
+   *   The brg specific entries in the device structure.
+   */
+
+  dev->open = brg_open;
+  dev->hard_start_xmit = brg_start_xmit;
+  dev->stop = brg_close;
+  dev->get_stats = brg_get_stats;
+  dev->set_multicast_list = brg_set_multicast_list;
+
+  /*
+   *   Setup the generic properties
+   */
+
+  ether_setup(dev);
+
+  dev->tx_queue_len = 0;
+
+  return 0;
+}
+
+/*
+ *     Open/initialize the board.
+ */
+
+static int brg_open(struct device *dev)
+{
+        if (br_stats.flags & BR_DEBUG)
+               printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name);
+
+       if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+         return -EFAULT;
+
+       dev->start = 1;
+       dev->tbusy = 0;
+       return 0;
+}
+
+static unsigned brg_mc_hash(__u8 *dest)
+{
+       unsigned idx = 0;
+       idx ^= dest[0];
+       idx ^= dest[1];
+       idx ^= dest[2];
+       idx ^= dest[3];
+       idx ^= dest[4];
+       idx ^= dest[5];
+       return 1U << (idx&0x1F);
+}
+
+static void brg_set_multicast_list(struct device *dev)
+{
+       unsigned groups = ~0;
+       struct net_local *lp = (struct net_local *)dev->priv;
+
+       if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+               struct dev_mc_list *dmi;
+
+               groups = brg_mc_hash(dev->broadcast);
+
+               for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+                       if (dmi->dmi_addrlen != 6)
+                               continue;
+                       groups |= brg_mc_hash(dmi->dmi_addr);
+               }
+       }
+       lp->groups = groups;
+}
+
+/*
+ *     We transmit by throwing the packet at the bridge.
+ */
+static int brg_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       struct ethhdr *eth = (struct ethhdr*)skb->data;
+       int port;
+
+       /* Deal with the bridge being disabled */
+       if(!(br_stats.flags & BR_UP)) {
+               /* Either this */
+               /* lp->stats.tx_errors++; */ /* this condition is NOT an error */
+               /* or this  (implied by RFC 2233) */
+               lp->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       lp->stats.tx_bytes+=skb->len;
+       lp->stats.tx_packets++;
+
+#if 0
+       ++br_stats_cnt.port_not_disable;
+#endif
+       skb->mac.raw = skb->nh.raw = skb->data;
+       eth = skb->mac.ethernet;
+       port = 0;       /* an impossible port (locally generated) */    
+
+        if (br_stats.flags & BR_DEBUG)
+               printk("%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x"
+                       " dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                      dev->name,
+                      eth->h_source[0],
+                      eth->h_source[1],
+                      eth->h_source[2],
+                      eth->h_source[3],
+                      eth->h_source[4],
+                      eth->h_source[5],
+                      eth->h_dest[0],
+                      eth->h_dest[1],
+                      eth->h_dest[2],
+                      eth->h_dest[3],
+                      eth->h_dest[4],
+                      eth->h_dest[5]);
+       
+       /* Forward the packet ! */
+       if(br_forward(skb, port))
+         return(0);
+    
+       /* Throw packet initially */
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+
+/*
+ *     The typical workload of the driver:
+ *     Handle the ether interface interrupts.
+ *
+ *     (In this case handle the packets posted from the bridge)
+ */
+
+static int brg_rx(struct sk_buff *skb, int port)
+{
+        struct device *dev = &brg_if.dev;
+       struct net_local *lp = (struct net_local *)dev->priv;
+       struct ethhdr *eth = (struct ethhdr*)(skb->data);
+       int len = skb->len;
+       int clone = 0;
+
+       if (br_stats.flags & BR_DEBUG)
+               printk(KERN_DEBUG "%s: brg_rx()\n", dev->name);
+
+       /* Get out of here if the bridge interface is not up
+        */
+       if(!(dev->flags & IFF_UP))
+         return(0);
+       
+       /* Check that the port that this thing came off is in the forwarding state 
+        * We sould only listen to the same address scope we will transmit to.
+        */
+       if(port_info[port].state != Forwarding)
+         return(0);
+
+       /* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning,
+         * with uni-cast we eat the packet
+        */
+       clone = 0;
+       if (dev->flags & IFF_PROMISC) {
+         clone = 1;
+       }
+       else if (eth->h_dest[0]&1) {
+         if (!(dev->flags&(IFF_ALLMULTI))
+             && !(brg_mc_hash(eth->h_dest)&lp->groups))
+           return(0);
+         clone = 1;
+       }
+       else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) {
+         return(0);
+       }
+
+       /* Clone things here - we want to be transparent before we check packet data 
+        * integrity
+        */
+       if(clone) {
+         struct sk_buff *skb2 = skb;
+         skb = skb_clone(skb2, GFP_KERNEL);
+         if (skb == NULL) {
+           return(0);
+         }
+         
+       }
+       else {
+               /* Learn source addresses for unicast non-promiscuous 
+                * frames for brg0
+                */
+               if(br_learn(skb, port)) {
+                       return br_drop(skb);
+               }
+       }
+
+       /* Check packet length 
+        */
+       if (len < 16) {
+               printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
+               kfree_skb(skb);
+               return(!clone);
+       }
+
+       if (br_stats.flags & BR_DEBUG)
+         printk("%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x"
+                " dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                dev->name,
+                eth->h_source[0],
+                eth->h_source[1],
+                eth->h_source[2],
+                eth->h_source[3],
+                eth->h_source[4],
+                eth->h_source[5],
+                eth->h_dest[0],
+                eth->h_dest[1],
+                eth->h_dest[2],
+                eth->h_dest[3],
+                eth->h_dest[4],
+                eth->h_dest[5]);
+
+       /* Do it */
+       skb->pkt_type = PACKET_HOST;
+       skb->dev = dev;
+       skb->protocol=eth_type_trans(skb,dev);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       lp->stats.rx_packets++;
+       lp->stats.rx_bytes+=len;
+       netif_rx(skb);
+       return(!clone);
+}
+
+static int brg_close(struct device *dev)
+{
+       if (br_stats.flags & BR_DEBUG)
+               printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
+
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       return 0;
+}
+
+static struct net_device_stats *brg_get_stats(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       return &lp->stats;
+}
+
+/* 
+ *      
+ */
+
+__initfunc(int brg_init(void))
+{
+        int err;
+
+       memset(&brg_if, 0, sizeof(brg_if));
+
+        rtnl_lock();
+
+       brg_if.dev.base_addr = bridge_info.instance;
+       sprintf (brg_if.name, "brg%d", bridge_info.instance);
+       brg_if.dev.name = (void*)&brg_if.name;
+        if(dev_get(brg_if.name)) {
+               printk(KERN_INFO "%s already loaded.\n", brg_if.name);
+              return -EBUSY;
+       }
+        brg_if.dev.init = brg_probe;
+
+        err = register_netdevice(&brg_if.dev);
+        rtnl_unlock();
+        return err;
+}
+
+
+#if 0                          /* Its here if we ever need it... */
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+
+  /* 
+   * Unregister the device
+   */
+  rtnl_lock();
+  unregister_netdevice(&the_master.dev);
+  rtnl_unlock();
+
+  /*
+   *   Free up the private structure.
+   */
+  
+  kfree(brg_if.dev.priv);
+  brg_if.dev.priv = NULL;      /* gets re-allocated by brg_probe */
+}
+
+#endif /* MODULE */
+
+#endif
index c1ed82f10875a52e7382d6710f8c34611a2c10de..67efa8f1ba2b0244a9168c1767cdeef56315e907 100644 (file)
@@ -492,7 +492,8 @@ void br_avl_delete_by_port(int port)
         port_info[port].fdb = NULL;
 
         /* remove the local mac too */
-        next = br_avl_find_addr(port_info[port].dev->dev_addr);
+/*        next = br_avl_find_addr(port_info[port].dev->dev_addr); */
+        next = br_avl_find_addr(port_info[port].ifmac.BRIDGE_ID_ULA);
         if (next != NULL)
                 br_avl_remove(next);
 
index 75fae54a8fe96932dfa7f7936c0f4a91a7dc03ee..963304594845d92237a33021eb87a5fd3a0000b7 100644 (file)
@@ -796,7 +796,11 @@ void netif_rx(struct sk_buff *skb)
 #ifdef CONFIG_BRIDGE
 static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
 {
-       if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(type)))
+       /* 
+        * The br_stats.flags is checked here to save the expense of a 
+        * function call.
+        */
+       if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type))
        {
                /*
                 *      We pass the bridge a complete frame. This means
@@ -820,7 +824,6 @@ static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
 }
 #endif
 
-
 /*
  *     When we are called the queue is ready to grab, the interrupts are
  *     on and hardware can interrupt and queue to the receive queue as we
@@ -2018,6 +2021,13 @@ __initfunc(int net_dev_init(void))
 
        dev_mcast_init();
 
+#ifdef CONFIG_BRIDGE
+       /*
+        * Register any statically linked ethernet devices with the bridge
+        */
+       br_spacedevice_register();
+#endif
+
 #ifdef CONFIG_IP_PNP
        ip_auto_config();
 #endif
index 08ebbc2f1e7608f5061842e508836b063eab9206..3aa790da4b2e5873139f3d1a46b42f8e31639d6b 100644 (file)
@@ -176,7 +176,7 @@ int ip_forward(struct sk_buff *skb)
                            (icmph->type==ICMP_TIME_EXCEEDED))
                        {
 #endif
-                               maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+                               maddr = rt->rt_src;
                                fw_res = ip_fw_masq_icmp(&skb, maddr);
                                if (fw_res < 0) {
                                        kfree_skb(skb);
@@ -226,7 +226,7 @@ skip_call_fw_firewall:
 
                if (maddr == 0)
 #endif
-                       maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+                       maddr = rt->rt_src;
 
                        if (ip_fw_masquerade(&skb, maddr) < 0) {
                                kfree_skb(skb);
index 6319b89e73ba107eb0647e908827c9ab675dc2fe..4edd083c3d781004e9de6a58cc2024eea7b2b8b0 100644 (file)
@@ -488,7 +488,10 @@ static int find_special(ip_chainlabel label, int *answer)
                 static int enabled = 0;
 
                 if(!enabled)
+                {
+                       enabled=1;
                         sysctl_ip_always_defrag++;
+                }
                *answer = FW_REDIRECT;
                return 1;
 #endif
index 657632150c96efec24d7aa6e90f689c8d8f1cb1b..dd7615e5a013eaaa56e621dfc5739bc912becd97 100644 (file)
@@ -1798,6 +1798,8 @@ extern void __skb_cb_too_small_for_tcp(int, int);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
+       unsigned long goal;
+       int order;
 
        if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
                __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -1823,4 +1825,43 @@ void __init tcp_init(void)
                                                NULL, NULL);
        if(!tcp_timewait_cachep)
                panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
+
+       /* Size and allocate TCP hash tables. */
+       goal = num_physpages >> (20 - PAGE_SHIFT);
+       for (order = 0; (1UL << order) < goal; order++)
+               ;
+       do {
+               tcp_ehash_size = (1UL << order) * PAGE_SIZE /
+                       sizeof(struct sock *);
+               tcp_ehash = (struct sock **)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while (tcp_ehash == NULL && --order >= 0);
+
+       if (!tcp_ehash)
+               panic("Failed to allocate TCP established hash table\n");
+       memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *));
+
+       goal = (((1UL << order) * PAGE_SIZE) / sizeof(struct tcp_bind_bucket *));
+       if (goal > (64 * 1024)) {
+               /* Don't size the bind-hash larger than the port
+                * space, that is just silly.
+                */
+               goal = (((64 * 1024) * sizeof(struct tcp_bind_bucket *)) / PAGE_SIZE);
+               for (order = 0; (1UL << order) < goal; order++)
+                       ;
+       }
+
+       do {
+               tcp_bhash_size = (1UL << order) * PAGE_SIZE /
+                       sizeof(struct tcp_bind_bucket *);
+               tcp_bhash = (struct tcp_bind_bucket **)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while (tcp_bhash == NULL && --order >= 0);
+
+       if (!tcp_bhash)
+               panic("Failed to allocate TCP bind hash table\n");
+       memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *));
+
+       printk("TCP: Hash tables configured (ehash %d bhash %d)\n",
+              tcp_ehash_size, tcp_bhash_size);
 }
index a753b128243d9b446c2734722ab3d01a1523bd41..a58382ef57d2f0113d4c856d7215d11b90f5ad3a 100644 (file)
@@ -1043,7 +1043,7 @@ static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *t
        sk->prot->inuse--;
 
        /* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-       head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+       head = &tcp_ehash[sk->hashent + (tcp_ehash_size/2)];
        sktw = (struct sock *)tw;
        if((sktw->next = *head) != NULL)
                (*head)->pprev = &sktw->next;
index 904f8b5d3117d1033e9818f8bbb025649ec6866d..4436ac0d5add2e3eafff7159bc65b771ca4187e0 100644 (file)
@@ -90,12 +90,14 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
  * First half of the table is for sockets not in TIME_WAIT, second half
  * is for TIME_WAIT sockets only.
  */
-struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
+unsigned int tcp_ehash_size;
+struct sock **tcp_ehash;
 
 /* 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];
+unsigned int tcp_bhash_size;
+struct tcp_bind_bucket **tcp_bhash;
 
 /* 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
@@ -117,7 +119,7 @@ int tcp_port_rover = (1024 - 1);
 static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
                                 __u32 faddr, __u16 fport)
 {
-       return ((laddr ^ lport) ^ (faddr ^ fport)) & ((TCP_HTABLE_SIZE/2) - 1);
+       return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size/2) - 1);
 }
 
 static __inline__ int tcp_sk_hashfn(struct sock *sk)
@@ -140,7 +142,7 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
        tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
        if(tb != NULL) {
                struct tcp_bind_bucket **head =
-                       &tcp_bound_hash[tcp_bhashfn(snum)];
+                       &tcp_bhash[tcp_bhashfn(snum)];
                tb->port = snum;
                tb->fastreuse = 0;
                tb->owners = NULL;
@@ -162,7 +164,7 @@ static __inline__ int __tcp_bucket_check(unsigned short snum)
 {
        struct tcp_bind_bucket *tb;
 
-       tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       tb = tcp_bhash[tcp_bhashfn(snum)];
        for( ; (tb && (tb->port != snum)); tb = tb->next)
                ;
        if (tb == NULL) {
@@ -181,7 +183,7 @@ static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
        if (child->num != sk->num) {
                unsigned short snum = ntohs(child->num);
-               for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+               for(tb = tcp_bhash[tcp_bhashfn(snum)];
                    tb && tb->port != snum;
                    tb = tb->next)
                        ;
@@ -220,7 +222,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
                do {    rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
-                       tb = tcp_bound_hash[tcp_bhashfn(rover)];
+                       tb = tcp_bhash[tcp_bhashfn(rover)];
                        for ( ; tb; tb = tb->next)
                                if (tb->port == rover)
                                        goto next;
@@ -237,7 +239,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
                snum = rover;
                tb = NULL;
        } else {
-               for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+               for (tb = tcp_bhash[tcp_bhashfn(snum)];
                     tb != NULL;
                     tb = tb->next)
                        if (tb->port == snum)
@@ -328,7 +330,7 @@ static __inline__ void __tcp_v4_hash(struct sock *sk)
        if(sk->state == TCP_LISTEN)
                skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
        else
-               skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+               skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
        if((sk->next = *skp) != NULL)
                (*skp)->pprev = &sk->next;
@@ -421,7 +423,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
         * have wildcards anyways.
         */
        hash = tcp_hashfn(daddr, hnum, saddr, sport);
-       for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+       for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
                if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
                                TCP_RHASH(sport) = sk;
@@ -429,7 +431,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
                }
        }
        /* 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_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next)
                if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
                        goto hit;
        sk = tcp_v4_lookup_listener(daddr, hnum, dif);
@@ -469,7 +471,7 @@ static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
 
        /* This code must run only from NET_BH. */
        {
-               struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hnum)];
+               struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)];
                for( ; (tb && tb->port != hnum); tb = tb->next)
                        ;
                if(tb == NULL)
@@ -510,7 +512,7 @@ pass2:
        }
 next:
        if(firstpass--) {
-               struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hpnum)];
+               struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)];
                for( ; (tb && tb->port != hpnum); tb = tb->next)
                        ;
                if(tb) {
@@ -547,7 +549,7 @@ static int tcp_v4_unique_address(struct sock *sk)
 
        /* Freeze the hash while we snoop around. */
        SOCKHASH_LOCK();
-       tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       tb = tcp_bhash[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
@@ -1793,7 +1795,7 @@ do_time_wait:
 
 static void __tcp_v4_rehash(struct sock *sk)
 {
-       struct sock **skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+       struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
        SOCKHASH_LOCK();
        if(sk->pprev) {
index 21029f8ecbd08ca9f9aa5c94420fea824c5de6d9..ccb52088609eeca28490ff57492c4c43fdc30dc7 100644 (file)
@@ -363,8 +363,8 @@ static void tcp_keepalive(unsigned long data)
        int count = 0;
        int i;
        
-       for(i = chain_start; i < (chain_start + ((TCP_HTABLE_SIZE/2) >> 2)); i++) {
-               struct sock *sk = tcp_established_hash[i];
+       for(i = chain_start; i < (chain_start + ((tcp_ehash_size/2) >> 2)); i++) {
+               struct sock *sk = tcp_ehash[i];
                while(sk) {
                        if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
                                count += tcp_keepopen_proc(sk);
@@ -375,8 +375,8 @@ static void tcp_keepalive(unsigned long data)
                }
        }
 out:
-       chain_start = ((chain_start + ((TCP_HTABLE_SIZE/2)>>2)) &
-                      ((TCP_HTABLE_SIZE/2) - 1));
+       chain_start = ((chain_start + ((tcp_ehash_size/2)>>2)) &
+                      ((tcp_ehash_size/2) - 1));
 }
 
 /*
index 1bd6181dec4de917a69d64a004aae73085b26abe..54aef23dbe010746776a045c29305b4d3f4cbf43 100644 (file)
@@ -67,7 +67,7 @@ static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
        int hashent = (lport ^ fport);
 
        hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-       return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
+       return (hashent & ((tcp_ehash_size/2) - 1));
 }
 
 static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
@@ -98,7 +98,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                do {    rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
-                       tb = tcp_bound_hash[tcp_bhashfn(rover)];
+                       tb = tcp_bhash[tcp_bhashfn(rover)];
                        for ( ; tb; tb = tb->next)
                                if (tb->port == rover)
                                        goto next;
@@ -115,7 +115,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
                snum = rover;
                tb = NULL;
        } else {
-               for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+               for (tb = tcp_bhash[tcp_bhashfn(snum)];
                     tb != NULL;
                     tb = tb->next)
                        if (tb->port == snum)
@@ -194,7 +194,7 @@ static void tcp_v6_hash(struct sock *sk)
                if(sk->state == TCP_LISTEN)
                        skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
                else
-                       skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+                       skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 
                SOCKHASH_LOCK();
                if((sk->next = *skp) != NULL)
@@ -276,7 +276,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
         * have wildcards anyways.
         */
        hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
-       for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+       for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
                /* For IPV6 do the cheaper port and family tests first. */
                if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
@@ -285,7 +285,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                }
        }
        /* 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_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next) {
                if(*((__u32 *)&(sk->dport))     == ports        &&
                   sk->family                   == PF_INET6) {
                        struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
@@ -336,7 +336,7 @@ static int tcp_v6_unique_address(struct sock *sk)
 
        /* Freeze the hash while we snoop around. */
        SOCKHASH_LOCK();
-       tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       tb = tcp_bhash[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
index c2e2453db64e7d77c647f88a2abdd02dd6880b2d..a3fa6d271ff18609fa22b07901456ce19403e05d 100644 (file)
@@ -345,6 +345,7 @@ void irlan_eth_send_gratuitous_arp(struct device *dev)
         * is useful if we have changed access points on the same
         * subnet.  
         */
+#ifdef CONFIG_INET      
        DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
        in_dev = dev->ip_ptr;
        arp_send(ARPOP_REQUEST, ETH_P_ARP, 
@@ -352,6 +353,7 @@ void irlan_eth_send_gratuitous_arp(struct device *dev)
                 dev, 
                 in_dev->ifa_list->ifa_address,
                 NULL, dev->dev_addr, NULL);
+#endif /* CONFIG_INET */                
 }
 
 /*
index 1dfaad196320ffff684c78b6a1944dbf696d1324..031527426e4e870fd7fe86022c8482a019c72676 100644 (file)
@@ -277,9 +277,11 @@ EXPORT_SYMBOL(inet_sendmsg);
 EXPORT_SYMBOL(inet_recvmsg);
 
 /* Socket demultiplexing. */
-EXPORT_SYMBOL(tcp_established_hash);
+EXPORT_SYMBOL(tcp_ehash_size);
+EXPORT_SYMBOL(tcp_ehash);
 EXPORT_SYMBOL(tcp_listening_hash);
-EXPORT_SYMBOL(tcp_bound_hash);
+EXPORT_SYMBOL(tcp_bhash_size);
+EXPORT_SYMBOL(tcp_bhash);
 EXPORT_SYMBOL(udp_hash);
 
 EXPORT_SYMBOL(destroy_sock);
@@ -496,8 +498,10 @@ EXPORT_SYMBOL(init_hippi_dev);
 EXPORT_SYMBOL(unregister_hipdev);
 #endif
 
+#ifdef CONFIG_INET
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
+#endif
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
 #include<linux/if_ltalk.h>
index dc06be6b0ed3987252737f8eb173639b19f1f29c..635ce705169af109a735ed9a08eb8fb83fc46108 100644 (file)
@@ -467,6 +467,9 @@ call_encode(struct rpc_task *task)
                return;
        }
 
+       /* Zero buffer so we have automatic zero-padding of opaque & string */
+       memset(task->tk_buffer, 0, bufsiz);
+
        /* Encode header and provided arguments */
        encode = rpcproc_encode(clnt, task->tk_proc);
        if (!(p = call_header(task))) {
index 143b6153fc2c85560007cea5918488f4d23aa58f..e879053011bbed33eb61d610a4ffc5673176bdf9 100644 (file)
@@ -38,7 +38,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, unsigned int xdrsize)
 
        memset(serv, 0, sizeof(*serv));
        serv->sv_program   = prog;
-       serv->sv_nrthreads = 1;
+       atomic_set(&serv->sv_nrthreads, 1);
        serv->sv_stats     = prog->pg_stats;
        serv->sv_bufsz     = bufsize? bufsize : 4096;
        serv->sv_xdrsize   = xdrsize;
@@ -61,10 +61,10 @@ svc_destroy(struct svc_serv *serv)
 
        dprintk("RPC: svc_destroy(%s, %d)\n",
                                serv->sv_program->pg_name,
-                               serv->sv_nrthreads);
+                               atomic_read (&serv->sv_nrthreads));
 
-       if (serv->sv_nrthreads) {
-               if (--(serv->sv_nrthreads) != 0)
+       if (atomic_read (&serv->sv_nrthreads)) {
+               if (!atomic_dec_and_test (&serv->sv_nrthreads))
                        return;
        } else
                printk("svc_destroy: no threads for serv=%p!\n", serv);
@@ -128,7 +128,7 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
         || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
                goto out_thread;
 
-       serv->sv_nrthreads++;
+       atomic_inc(&serv->sv_nrthreads);
        rqstp->rq_server = serv;
        error = kernel_thread((int (*)(void *)) func, rqstp, 0);
        if (error < 0)
index 18db6ffc6fd22b9173fca3f35714e7db887d11eb..266f389bb8b3e653def3b100b0a5e3aa60a2ebdd 100644 (file)
@@ -124,7 +124,7 @@ svc_sock_enqueue(struct svc_sock *svsk)
                                "svc_sock_enqueue: server %p, rq_sock=%p!\n",
                                rqstp, rqstp->rq_sock);
                rqstp->rq_sock = svsk;
-               svsk->sk_inuse++;
+               atomic_inc(&svsk->sk_inuse);
                wake_up(&rqstp->rq_wait);
        } else {
                dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
@@ -148,7 +148,7 @@ svc_sock_dequeue(struct svc_serv *serv)
 
        if (svsk) {
                dprintk("svc: socket %p dequeued, inuse=%d\n",
-                       svsk->sk_sk, svsk->sk_inuse);
+                       svsk->sk_sk, atomic_read(&svsk->sk_inuse));
                svsk->sk_qued = 0;
        }
 
@@ -206,7 +206,7 @@ svc_sock_release(struct svc_rqst *rqstp)
                return;
        svc_release_skb(rqstp);
        rqstp->rq_sock = NULL;
-       if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+       if (atomic_dec_and_test(&svsk->sk_inuse) && svsk->sk_dead) {
                dprintk("svc: releasing dead socket\n");
                sock_release(svsk->sk_sock);
                kfree(svsk);
@@ -766,7 +766,7 @@ again:
        start_bh_atomic();
        if ((svsk = svc_sock_dequeue(serv)) != NULL) {
                rqstp->rq_sock = svsk;
-               svsk->sk_inuse++;
+               atomic_inc(&svsk->sk_inuse);
        } else {
                /* No data pending. Go to sleep */
                svc_serv_enqueue(serv, rqstp);
@@ -793,7 +793,7 @@ again:
        end_bh_atomic();
 
        dprintk("svc: server %p, socket %p, inuse=%d\n",
-                rqstp, svsk, svsk->sk_inuse);
+                rqstp, svsk, atomic_read(&svsk->sk_inuse));
        len = svsk->sk_recvfrom(rqstp);
        dprintk("svc: got len=%d\n", len);
 
@@ -988,11 +988,12 @@ svc_delete_socket(struct svc_sock *svsk)
                rpc_remove_list(&serv->sv_sockets, svsk);
        svsk->sk_dead = 1;
 
-       if (!svsk->sk_inuse) {
+       if (!atomic_read(&svsk->sk_inuse)) {
                sock_release(svsk->sk_sock);
                kfree(svsk);
        } else {
-               printk(KERN_NOTICE "svc: server socket destroy delayed\n");
+               printk(KERN_NOTICE "svc: server socket destroy delayed (sk_inuse: %d)\n",
+                      atomic_read(&svsk->sk_inuse));
                /* svsk->sk_server = NULL; */
        }
 }