]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.0pre2 (December 31 1998) 2.2.0pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:48 +0000 (15:17 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:48 +0000 (15:17 -0500)
Well, some people obviously had problems with the first 2.2.0pre, so
there's a second one there. Most of it is almost purely syntactic sugar:
configuration issues and jiffies wraparound, but there were a few problems
wrt some IDE disk geometry stuff in particular that made 2.2.0pre1 not
boot for some people.

Other real changes:
 - nfsd updated, and we have an official maintainer for knfsd (and I was
   happy by how many people were ready to stand up for it. Good show,
   guys!)
 - network driver updates (tulip/eepro)
 - some TCP fixes for occasional but nasty performance problems.
 - fix for an attack where you could cause a complete and utter lockup of
   the kernel as a normal user. Thanks to Michael Chastain for keeping the
   faith on this one and reminding me to fix it.

If you haven't had problems with pre1, there should be no major cause to
look at pre2. But if you haven't even looked at pre1 yet, please consider
looking at the pre-2.2.0 kernels before it's too late. I'm going to be
extremely rude to people who knew better but didn't test out the pre-
kernels and then send me bug-reports on the released 2.2.0.

Linus

169 files changed:
CREDITS
Documentation/Configure.help
Documentation/kernel-docs.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/config.in
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq.h
arch/alpha/kernel/ptrace.c
arch/alpha/kernel/smp.c
arch/i386/Makefile
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/irq.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/smp.c
arch/i386/kernel/time.c
arch/i386/mm/init.c
arch/ppc/defconfig
arch/ppc/kernel/head.S
arch/ppc/kernel/idle.c
arch/ppc/kernel/irq.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/process.c
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/smp.c
arch/ppc/kernel/time.c
arch/ppc/lib/locks.c
arch/ppc/pmac_defconfig
arch/ppc/vmlinux.lds
arch/sparc/kernel/ptrace.c
drivers/block/Config.in
drivers/block/acsi.c
drivers/block/acsi_slm.c
drivers/block/ataflop.c
drivers/block/ide-disk.c
drivers/block/ide-dma.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/ide.h
drivers/block/pdc4030.c
drivers/char/console.c
drivers/char/consolemap.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/ftape/RELEASE-NOTES
drivers/char/ftape/lowlevel/fdc-io.c
drivers/char/hfmodem/Config.in
drivers/char/istallion.c
drivers/char/riscom8.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/isdn/Config.in
drivers/net/Makefile
drivers/net/bmac.c
drivers/net/de4x5.c
drivers/net/de4x5.h
drivers/net/dgrs.c
drivers/net/eepro.c
drivers/net/hamradio/Config.in
drivers/net/hamradio/hdlcdrv.c
drivers/net/hp100.c
drivers/net/plip.c
drivers/net/sdla.c
drivers/net/seeq8005.c
drivers/net/sktr.c
drivers/net/tulip.c
drivers/nubus/nubus.c
drivers/pci/oldproc.c
drivers/scsi/Config.in
drivers/scsi/advansys.c
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma_proc.c
drivers/scsi/eata_pio.c
drivers/scsi/eata_pio_proc.c
drivers/scsi/fdomain.c
drivers/scsi/ibmmca.c
drivers/scsi/mesh.c
drivers/scsi/scsi.h
drivers/scsi/seagate.c
drivers/scsi/wd7000.c
drivers/sound/dmasound.c
fs/Config.in
fs/buffer.c
fs/dcache.c
fs/fat/inode.c
fs/isofs/inode.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/lockd/svc.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/nfsd/Makefile
fs/nfsd/auth.c
fs/nfsd/export.c
fs/nfsd/nfscache.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfssvc.c
fs/nfsd/stats.c
fs/nfsd/vfs.c
fs/open.c
fs/sysv/CHANGES
fs/sysv/inode.c
fs/sysv/namei.c
include/asm-alpha/delay.h
include/asm-alpha/init.h
include/asm-alpha/irq.h
include/asm-alpha/pgtable.h
include/asm-alpha/smp.h
include/asm-alpha/system.h
include/asm-alpha/timex.h
include/asm-i386/bugs.h
include/asm-i386/byteorder.h
include/asm-i386/elf.h
include/asm-i386/pgtable.h
include/asm-i386/smp.h
include/asm-i386/string.h
include/asm-i386/timex.h
include/asm-i386/uaccess.h
include/asm-ppc/checksum.h
include/asm-ppc/ide.h
include/asm-ppc/init.h
include/asm-ppc/pgtable.h
include/asm-ppc/spinlock.h
include/asm-ppc/system.h
include/asm-ppc/termios.h
include/asm-ppc/timex.h
include/linux/arcdevice.h
include/linux/consolemap.h
include/linux/cyclades.h
include/linux/dcache.h
include/linux/hdreg.h
include/linux/kernel.h
include/linux/nfsd/nfsd.h
include/linux/pci.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/sysctl.h
include/linux/sysv_fs.h
ipc/shm.c
kernel/acct.c
kernel/ksyms.c
kernel/sched.c
kernel/sysctl.c
mm/vmscan.c
net/Config.in
net/core/Makefile
net/core/firewall.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/ipconfig.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/netsyms.c
net/sunrpc/auth.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/xprt.c
net/wanrouter/wanmain.c

diff --git a/CREDITS b/CREDITS
index 7a0675d46124abd0fecddea49213d01ab6bee051..f01f7d4d7c5c05204fb0f1a0bea76adcab2d956b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -147,7 +147,8 @@ M: Krzysztof G. Baranowski
 E: kgb@manjak.knm.org.pl
 P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC  F9 4F 36 1F 6D 60 7B DA
 D: Maintainer of the System V file system.
-D: SystemV fs update for 2.1.x dcache.
+D: System V fs update for 2.1.x dcache.
+D: Forward ported a couple of SCSI drivers.
 D: Various bugfixes.
 S: ul. Koscielna 12a
 S: 62-300 Wrzesnia
index 9470b48650db3dfa855fe4c4df2a17b9656df88c..bdb085a77f2e61b8aa3d81169c4d51e3c7de1cdb 100644 (file)
@@ -91,6 +91,9 @@ CONFIG_SMP
   single-CPU machines.  On a single-CPU machine, a non-SMP kernel
   will run faster than an SMP kernel.
 
+  i486 based SMP boards don't boot CONFIG_M586/M686 kernels. CONFIG_M686
+  SMP kernels might not work on all Pentium based boards.
+
   People using multiprocessor machines should also say Y to "Enhanced
   Real Time Clock Support", below.  The "Advanced Power Management"
   code will be disabled in an SMP kernel.
@@ -1557,23 +1560,23 @@ CONFIG_M386
   This is the processor type of your CPU. This information is used for
   optimizing purposes. In order to compile a kernel that can run on
   all x86 CPU types (albeit not optimally fast), you can specify
-  "386" here. If you specify one of "486" or "Pentium" or "PPro",
-  then the kernel will run on all x86 architectures except on 386.
+  "386" here.
+
+  If you specify one of "486" or "Pentium" or "PPro", then the kernel
+  will not necessarily run on earlier architectures (ie a Pentium
+  optimized kernel will run on a PPro, but not necessarily on a i486).
 
   Here are the settings recommended for greatest speed:
    - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX and
      Cyrix/TI 486DLC/DLC2. Only "386" kernels will run on a 386 class
      machine.
    - "486" for the AMD/Cyrix/IBM/Intel DX4 or 486DX/DX2/SL/SX/SX2,
-     AMD/Cyrix 5x86, NexGen Nx586 and UMC U5D or U5S
-   - "Pentium" for the AMD K5, K6 and K6-3D, Cyrix MediaGX,
-     Cyrix/IBM/National Semiconductor 6x86 and GXm, IDT Centaur
-     WinChip C6, and Intel Pentium/Pentium MMX
+     AMD/Cyrix 5x86, NexGen Nx586 and UMC U5D or U5S.
+   - "586" for generic Pentium CPU's, possibly lacking the TSC register.
+   - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and K6-3D.
+     This option will assume that you have a time stamp counter.
    - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
-     Intel Pentium II/Pentium Pro
-
-  In rare cases, it can make sense to specify "Pentium" even if
-  running on a 486: the kernel will be smaller but slower.
+     Intel Pentium II/Pentium Pro.
 
   If you don't know what to do, choose "386".
 
@@ -3776,15 +3779,20 @@ CONFIG_SCSI_U14_34F_MAX_TAGS
   given SCSI device. Go with the default unless you know what you're
   doing. Minimum is 2 and maximum is 8.
 
-Future Domain 16xx SCSI/AHA 2920 support
+Future Domain 16xx SCSI/AHA-2920A support
 CONFIG_SCSI_FUTURE_DOMAIN
   This is support for Future Domain's 16-bit SCSI host adapters
   (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
   other adapters based on the Future Domain chipsets (Quantum
-  ISA-200S, ISA-250MG; Adaptec AHA-2920; and at least one IBM board).
+  ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
   It is explained in section 3.7 of the SCSI-HOWTO, available via FTP
   (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
+  NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip and
+  should use the aic7xxx driver (CONFIG_SCSI_AIC7XXX).  The Future Domain
+  driver works with the older Adaptec AHA-2920A boards with a Future Domain
+  chip on them.
+
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called fdomain.o. If you want to compile it as a
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
new file mode 100644 (file)
index 0000000..3b249fc
--- /dev/null
@@ -0,0 +1,331 @@
+
+   
+ INDEX OF DOCUMENTATION FOR PEOPLE INTERESTED IN WRITING AND/OR UNDERSTANDING
+                               THE LINUX KERNEL.
+                                       
+               Juan-Mariano de Goyeneche <jmseyas@dit.upm.es>
+   
+   
+   /*
+    * The latest version of this document may be found at: 
+    *   http://www.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html
+    */
+
+   The need for a document like this one became apparent in the
+   linux-kernel mailing list as the same questions, asking for pointers
+   to information, appeared again and again.
+   
+   Fortunately, as more and more people get to GNU/Linux, more and more
+   get interested in the Kernel. But reading the sources is not always
+   enough. It is easy to understand the code, but miss the concepts, the
+   philosophy and design decissions behind this code.
+   
+   Unfortunately, not many documents are available for beginners to
+   start. And, even if they exist, there was no "well-known" place which
+   kept track of them. These lines try to cover this lack. All documents
+   available on line known by the author are listed, while some reference
+   books are also mentioned.
+   
+   PLEASE, if you know any paper not listed here or write a new document,
+   send me an e-mail, and I'll include a reference to it here. Any
+   corrections, ideas or comments are also wellcomed.
+   
+   The papers that follow are listed in no particular order. All are
+   catalogued with the following fields: the document's "Title", the
+   "Author"/s, the "URL" where they can be found, some "Keywords"
+   helpfull when searching for specific topics, and a brief "Description"
+   of the Document.
+   
+   Enjoy!
+   
+   
+   ON-LINE DOCS:
+   
+          + Title: "The Linux Kernel"
+            Author: David A. Rusling.
+            URL: http://sunsite.unc.edu/linux/LDP/tlk/tlk.html
+            Keywords: everything!, book.
+            Description: On line, 200 pages book describing most
+            aspects of the Linux Kernel. Probably, the first reference
+            for beginners. Lots of illustrations explaining data
+            structures use and relationships in the purest Richard W.
+            Stevens' style. Contents: "1.-Hardware Basics, 2.-Software
+            Basics, 3.-Memory Management, 4.-Processes, 5.-Interprocess
+            Communication Mechanisms, 6.-PCI, 7.-Interrupts and Interrupt
+            Handling, 8.-Device Drivers, 9.-The File system,
+            10.-Networks, 11.-Kernel Mechanisms, 12.-Modules, 13.-The
+            Linux Kernel Sources, A.-Linux Data Structures, B.-The Alpha
+            AXP Processor, C.-Useful Web and FTP Sites, D.-The GNU
+            General Public License, Glossary". In short: a must have.
+   
+          + Title: "The Linux Kernel Hackers' Guide"
+            Author: Michael K.Johnson and others.
+            URL: http://www.redhat.com:8080/HyperNews/get/khg.html
+            Keywords: everything!
+            Description: No more Postscript book-like version. Only
+            HTML now. Many people have contributed. The interface is
+            similar to web available mailing lists archives. You can find
+            some articles and then some mails asking questions about them
+            and/or complementing previous contributions. A little bit
+            anarchic in this aspect, but with some valuable information
+            in some cases.
+       
+          + Title: "Tour Of the Linux Kernel Source"
+            Author: Vijo Cherian.
+            URL: http://www.svrec.ernet.in/~vijo/tolks/tolks.html
+            Keywords:
+            Description: The name says it all. A tour of the sources,
+            describing directories, files, variables, data structures...
+            It covers general stuff, device drivers, filesystems, IPC and
+            Network Code.
+       
+          + Title: "Overview of the Virtual File System"
+            Author: Richard Gooch.
+            URL: http://www.atnf.csiro.au/~rgooch/linux/vfs.txt
+            Keywords: VFS, File System, mounting filesystems, opening
+            files, dentries,
+            dcache. Description: Brief introduction to the Linux
+            Virtual File System. What is it, how it works, operations
+            taken when opening a file or mounting a file system and
+            description of important data structures explaining the
+            purpose of each of their entries.
+   
+          + Title: "The Linux RAID-1, 4, 5 Code"
+            Author: Ingo Molnar, Gadi Oxman and Miguel de Icaza.
+            URL: http://www.ssc.com/lj/issue44/2391.html
+            Keywords: RAID, MD driver.
+            Description: Linux Journal Kernel Korner article. Here is
+            it's abstract: "A description of the implementation of the
+            RAID-1, RAID-4 and RAID-5 personalities of the MD device
+            driver in the Linux kernel, providing users with high
+            performance and reliable, secondary-storage capability using
+            software".
+   
+          + Title: "Dynamic Kernels: Modularized Device Drivers"
+            Author: Alessandro Rubini.
+            URL: http://www.ssc.com/lj/issue23/1219.html
+            Keywords: device driver, module, loading/unloading modules,
+            allocating
+            resources. Description: Linux Journal Kernel Korner
+            article. Here is it's abstract: "This is the first of a
+            series of four articles co-authored by Alessandro Rubini and
+            Georg Zezchwitz which present a practical approach to writing
+            Linux device drivers as kernel loadable modules. This
+            installment presents an introduction to the topic, preparing
+            the reader to understand next month's installment".
+   
+          + Title: "Dynamic Kernels: Discovery"
+            Author: Alessandro Rubini.
+            URL: http://www.ssc.com/lj/issue24/kk24.html
+            Keywords: character driver, init_module, clean_up module,
+            autodetection,
+            mayor number, minor number, file operations, open(), close().
+            Description: Linux Journal Kernel Korner article. Here is
+            it's abstract: "This article, the second of four, introduces
+            part of the actual code to create custom module implementing
+            a character device driver. It describes the code for module
+            initialization and cleanup, as well as the open() and close()
+            system calls".
+   
+          + Title: "The Devil's in the Details"
+            Author: Georg v. Zezschwitz and Alessandro Rubini.
+            URL: http://www.ssc.com/lj/issue25/kk25.html
+            Keywords: read(), write(), select(), ioctl(), blocking/non
+            blocking mode,
+            interrupt handler. Description: Linux Journal Kernel Korner
+            article. Here is it's abstract: "This article, the third of
+            four on writing character device drivers, introduces concepts
+            of reading, writing, and using ioctl-calls".
+   
+          + Title: "Dissecting Interrupts and Browsing DMA"
+            Author: Alessandro Rubini and Georg v. Zezschwitz.
+            URL: http://www.ssc.com/lj/issue26/interrupt.html
+            Keywords: interrupts, irqs, DMA, bottom halves, task
+            queues.
+            Description: Linux Journal Kernel Korner article. Here is
+            it's abstract: "This is the fourth in a series of articles
+            about writing character device drivers as loadable kernel
+            modules. This month, we further investigate the field of
+            interrupt handling. Though it is conceptually simple,
+            practical limitations and constraints make this an
+            ``interesting'' part of device driver writing, and several
+            different facilities have been provided for different
+            situations. We also investigate the complex topic of DMA".
+   
+          + Title: "Network Buffers And Memory Management"
+            Author: Alan Cox.
+            URL: http://www.ssc.com/lj/issue30/kk30.html
+            Keywords: sk_buffs, network devices, protocol/link layer
+            variables, network
+            devices flags, transmit, receive, configuration, multicast.
+            Description: Linux Journal Kernel Korner. Here is the
+            abstract: "Writing a network device driver for Linux is
+            fundamentally simple---most of the complexity (other than
+            talking to the hardware) involves managing network packets in
+            memory".
+       
+          + Title: "An Introduction to the Linux 1.3.x Networking Code"
+            Author: Vipul Gupta.
+            URL:
+            http://anchor.cs.binghamton.edu/courses/cs628/linux-net.html
+            Keywords: files, sk_buffs.
+            Description: A short description of files under the net/
+            directory. Each file has a one or two lines paragrahp
+            description. sk_buffs explained, too, with some beatiful
+            pictures. A little bit outdated.
+   
+          + Title: "Linux ioctl() Primer"
+            Author: Vipul Gupta.
+            URL:
+            http://anchor.cs.binghamton.edu/courses/cs628/ioctl.html
+            Keywords: ioctl, socket.
+            Description: Little description and examples on the use and
+            implementation of the ioctl() system call. A little bit
+            biased towards sockets.
+       
+          + Title: "Writing Linux Device Drivers"
+            Author: Michael K. Johnson.
+            URL: http://www.redhat.com/~johnsonm/devices.html
+            Keywords: files, VFS, file operations, kernel interface,
+            character vs
+            block devices, I/O access, hardware interrupts, DMA, access
+            to user memory, memory allocation, timers. Description:
+            Introductory 50-minutes (sic) tutorial on writing device
+            drivers. 12 pages written by the same author of the "Kernel
+            Hackers' Guide" which give a very good overview of the topic.
+   
+          + Title: "The Venus kernel interface"
+            Author: Peter J. Braam.
+            URL:
+            http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html
+            Keywords: coda, filesystem, venus, cache manager.
+            Description: "This document describes the communication
+            between Venus and kernel level file system code needed for
+            the operation of the Coda filesystem. This version document
+            is meant to describe the current interface (version 1.0) as
+            well as improvements we envisage".
+       
+          + Title: "Programming PCI-Devices under Linux"
+            Author: Claus Schroeter.
+            URL:
+            ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/pc
+            ip.ps.gz
+            Keywords: PCI, device, busmastering.
+            Description: 6 pages tutorial on PCI programming under
+            Linux. Gives the basic concepts on the architecture of the
+            PCI subsystem, as long as basic functions and macros to
+            read/write the devices and perform busmastering.
+       
+          + Title: "Writing Character Device Driver for Linux"
+            Author: R. Baruch and C. Schroeter.
+            URL:
+            ftp://ftp.llp.fu-berlin.de/pub/linux/LINUX-LAB/whitepapers/dr
+            ivers.ps.gz
+            Keywords: character device drivers, I/O, signals, DMA,
+            accesing ports in user space, kernel environment.
+            Description: 68 pages paper on writing character drivers. A
+            little bit old (1.993, 1.994) although still useful.
+       
+       
+       
+     * BOOKS: (Not on-line)
+       
+          + Title: "Linux Device Drivers"
+            Author: Alessandro Rubini.
+            Publisher: O'Reilly &Associates.
+            Date: 1998.
+            ISBN: 1-56592-292-1
+       
+          + Title: "Linux Kernel Internals"
+            Author: Michael Beck.
+            Publisher: Addison-Wesley.
+            Date: 1997.
+            ISBN: 0-201-33143-8 (second edition)
+       
+          + Title: "The Design of the UNIX Operating System"
+            Author: Maurice J. Bach.
+            Publisher: Prentice Hall.
+            Date: 1986.
+            ISBN: ???
+   
+          + Title: "The Design and Implementation of the 4.3 BSD UNIX
+            Operating System"
+            Author: Samuel J. Leffler, Marshall Kirk McKusick, Michael
+            J. Karels, John S. Quarterman.
+            Publisher: Addison-Wesley.
+            Date: 1989 (reprinted with corrections on October, 1990).
+            ISBN: 0-201-06196-1
+       
+          + Title: "The Design and Implementation of the 4.4 BSD UNIX
+            Operating System"
+            Author: Marshall Kirk McKusick, Keith Bostic, Michael J.
+            Karels, John S. Quarterman.
+            Publisher: Addison-Wesley.
+            Date: 1996.
+            ISBN: 0-201-54979-4
+   
+          + Title: "Programmation Linux 2.0 API systeme et
+            fonctionnement du noyau"
+            Author: Remy Card, Eric Dumas, Franck Mevel.
+            Publisher: Eyrolles.
+            Date: 1997.
+            Pages: 520. ISBN: 2-212-08932-5
+       
+          + Title: "Unix internals -- the new frontiers"
+            Author: Uresh Vahalia.
+            Publisher: Prentice Hall.
+            Date: 1996.
+            Pages: 600. ISBN: 0-13-101908-2
+   
+       
+     * MISCELLANEOUS:
+       
+          + Name: Linux Source Driver.
+            URL: http://lsd.linux.cz
+            Keywords: Browsing.
+            Description: "Linux Source Driver (LSD) is an application,
+            which can make browsing source codes of Linux kernel easier
+            than you can imagine. You can select between multiple
+            versions of kernel (e.g. 0.01, 1.0.0, 2.0.33, 2.0.34pre13,
+            2.0.0, 2.1.101 etc.). With LSD you can search Linux kernel
+            (fulltext, macros, types, functions and variables) and LSD
+            can generate patches for you on the fly (files, directories
+            or kernel)".
+       
+          + Name: Linux Weekly News.
+            URL: http://lwn.net
+            Keywords: last kernel news.
+            Description: The title says it all. There's a fixed kernel
+            section summarizing developers' work, bug fixes, new features
+            and versions produced during the week. Published every
+            thursday.
+       
+          + Name: CuTTiNG.eDGe.LiNuX.
+            URL: http://edge.linuxhq.com
+            Keywords: changelist.
+            Description: Site which provides the changelist for every
+            kernel release. What's new, what's better, what's changed.
+            Myrdraal reads the patchs and describes them. Pointers to the
+            patches are there, too.
+   
+          + Name: New linux-kernel Mailing List FAQ.
+            URL: Original site:
+            http://www.altern.org/andrebalsa/doc/lkml-faq.html
+            URL: U.S. mirror site:
+            http://www.ececs.uc.edu/~rreilova/linux/lkml-faq.html
+            Keywords: linux-kernel mailing list FAQ.
+            Description: linux-kernel is a mailing list for developers
+            to communicate. This FAQ builds on the previous linux-kernel
+            mailing list FAQ maintained by Frohwalt Egerer, who no longer
+            maintains it. Read it to see how to join the mailing list.
+            Dozens of interesting questions regarding the list, Linux,
+            developers (who is ...?), terms (what is...?) are answered
+            here too. Just read it.
+       
+          + Name: "Linux Virtual File System"
+            Author: Peter J. Braam.
+            URL: http://www.coda.cs.cmu.edu/doc/talks/linuxvfs
+            Keywords: slides, VFS, inode, superblock, dentry, dcache.
+            Description: Set of slides, presumably from a presentation
+            on the Linux VFS layer. Covers version 2.1.x, with dentries
+            and the dcache.
index 4f0c66b264a86ca56d94f4315595f127ed57b182..f87c5df8a0bca08865c7473cd3dfe7832f78a824 100644 (file)
@@ -181,12 +181,6 @@ M: kas@fi.muni.cz
 W:     http://www.fi.muni.cz/~kas/cosa/
 S:     Maintained
 
-COSA/SRP SYNC SERIAL DRIVER
-P:     Jan "Yenya" Kasprzak
-M:     kas@fi.muni.cz
-W:     http://www.fi.muni.cz/~kas/cosa/
-S:     Maintained
-
 CREDITS FILE
 P:     John A. Martin
 M:     jam@acm.org
@@ -350,10 +344,10 @@ M:        perex@jcu.cz
 S:     Maintained
 
 IDE DRIVER [GENERAL]
-P:     Mark Lord
-M:     mlord@pobox.com
+P:     Andre Hedrick
+M:     hedrick@astro.dyer.vanderbilt.edu
 L:     linux-kernel@vger.rutgers.edu
-S:     Odd Fixes
+S:     Maintained
 
 IDE/ATAPI CDROM DRIVER 
 P:     Jens Axboe
@@ -407,6 +401,13 @@ M: hpa@zytor.com
 L:     autofs@linux.kernel.org
 S:     Maintained
 
+KERNEL NFSD
+P:     G. Allen Morris III
+M:     gam3@acm.org
+L:     nfs-devel@linux.kernel.org (Linux NFS)
+W:     http://csua.berkeley.edu/~gam3/knfsd
+S:     Maintained
+
 LAPB module
 P:     Henner Eisen
 M:     eis@baty.hanse.de
index 53ff0e7ad92c559545235a247f1ef77843fca9fd..3d6591ba039335c9730d8cc0fe31a14b01e4e3c5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 53467b99237d3e71ecec8f14afc6e7b3e1642796..84aecd676b6d5493f0c594d6eb52e412061e5fa3 100644 (file)
@@ -13,7 +13,6 @@ mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
-  MODULES=y
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
   bool 'Kernel module loader' CONFIG_KMOD
 fi
index 1fee6e5e33910105eea3ec6b46952dedc78f9433..59686fe84cdd72dad948639a777a43f7265947ff 100644 (file)
@@ -86,6 +86,7 @@ EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(memcmp);
index f349ebd6b8a35e5399f6b7e158276e5ad6f5fc64..c2376cc9dde5aa7ed44a8ed920e93ca4b7706f81 100644 (file)
@@ -689,7 +689,8 @@ ret_from_smpfork:
        .set at
        mb      /* Make the changed data visible before the freed lock. */
        stq     $31,scheduler_lock      
-       br      ret_from_sys_call
+       lda     $26,ret_from_sys_call
+       jsr     $31,schedule_tail
        .set noat
 .end ret_from_smpfork
 #endif /* __SMP__ */
index 144b3d2ca3245434e7694ca78ed7c26fd47b78b7..e7113ff0ec7fe510f4d4a495700aa78cb5e1570d 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
index 59034807adc4d03cd4d0aa8a25c3d403a8b2343c..6849e830bbb6c99cc9728c10bd4c321f1e562265 100644 (file)
@@ -8,6 +8,8 @@
  * with the IRQ handling routines in irq.c.
  */
 
+#include <linux/config.h>
+
 #define STANDARD_INIT_IRQ_PROLOG       \
        outb(0, DMA1_RESET_REG);        \
        outb(0, DMA2_RESET_REG);        \
index b6194defac658158695b95b991b8add2bccd7e49..18c9a8b13dc04b68476007e1aee64a65669e6136 100644 (file)
@@ -541,7 +541,9 @@ sys_ptrace(long request, long pid, long addr, long data,
        /* When I and D space are separate, these will need to be fixed.  */
        case PTRACE_PEEKTEXT: /* read word at location addr. */
        case PTRACE_PEEKDATA:
+               down(&child->mm->mmap_sem);
                ret = read_long(child, addr, &tmp);
+               up(&child->mm->mmap_sem);
                DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
                if (ret < 0)
                        goto out;
@@ -560,7 +562,9 @@ sys_ptrace(long request, long pid, long addr, long data,
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA:
                DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
+               down(&child->mm->mmap_sem);
                ret = write_long(child, addr, data);
+               up(&child->mm->mmap_sem);
                goto out;
 
        case PTRACE_POKEUSR: /* write the specified register */
index 19aa9a682a5f8a158fff0e8fb9bac59827831dd8..6faef93581f01bf5da2a2acc7a15cf2fbb07c168 100644 (file)
 
 #include "proto.h"
 
-struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
+#define DEBUG_SMP 0
+#if DEBUG_SMP
+#define DBGS(args)     printk args
+#else
+#define DBGS(args)
+#endif
+
+struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
 
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
@@ -39,7 +46,6 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
 unsigned int boot_cpu_id = 0;
 static int smp_activated = 0;
-static unsigned long ipicnt[NR_CPUS] = {0,}; /* IPI counts */
 
 int smp_found_config = 0; /* Have we found an SMP box */
 static int max_cpus = -1;
@@ -53,10 +59,12 @@ int smp_threads_ready = 0;
 volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
 
+cycles_t cacheflush_time;
+
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 
-volatile int ipi_bits[NR_CPUS];
+volatile int ipi_bits[NR_CPUS] __cacheline_aligned;
 
 unsigned long boot_cpu_palrev;
 
@@ -73,87 +81,80 @@ static void smp_setup_percpu_timer(void);
 static void secondary_cpu_start(int, struct task_struct *);
 static void send_cpu_msg(char *, int);
 
-/* process bootcommand SMP options, like "nosmp" and "maxcpus=" */
-__initfunc(void smp_setup(char *str, int *ints))
+/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+void __init
+smp_setup(char *str, int *ints)
 {
        if (ints && ints[0] > 0)
                max_cpus = ints[1];
-        else
+       else
                max_cpus = 0;
 }
 
-void smp_store_cpu_info(int id)
+static void __init
+smp_store_cpu_info(int id)
 {
        /* This is it on Alpha, so far. */
-        cpu_data[id].loops_per_sec = loops_per_sec;
+       cpu_data[id].loops_per_sec = loops_per_sec;
 }
 
-void smp_commence(void)
+void __init
+smp_commence(void)
 {
        /* Lets the callin's below out of their loop. */
        mb();
        smp_commenced = 1;
 }
 
-void smp_callin(void)
+void __init
+smp_callin(void)
 {
-        int cpuid = hard_smp_processor_id();
+       int cpuid = hard_smp_processor_id();
 
-#if 0
-       printk("CALLIN %d state 0x%lx\n", cpuid, current->state);
-#endif
+       DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
 #ifdef HUH
-        local_flush_cache_all();
-        local_flush_tlb_all();
+       local_flush_cache_all();
+       local_flush_tlb_all();
 #endif
 #if 0
-        set_irq_udt(mid_xlate[boot_cpu_id]);
+       set_irq_udt(mid_xlate[boot_cpu_id]);
 #endif
 
-        /* Get our local ticker going. */
-        smp_setup_percpu_timer();
+       /* Get our local ticker going. */
+       smp_setup_percpu_timer();
 
 #if 0
-        calibrate_delay();
+       calibrate_delay();
 #endif
-        smp_store_cpu_info(cpuid);
+       smp_store_cpu_info(cpuid);
 #ifdef HUH
-        local_flush_cache_all();
-        local_flush_tlb_all();
+       local_flush_cache_all();
+       local_flush_tlb_all();
 #endif
 
-        /* Allow master to continue. */
-        set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
+       /* Allow master to continue. */
+       set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
 #ifdef HUH
-        local_flush_cache_all();
-        local_flush_tlb_all();
+       local_flush_cache_all();
+       local_flush_tlb_all();
 #endif
 
 #ifdef NOT_YET
-        while(!task[cpuid] || current_set[cpuid] != task[cpuid])
-                barrier();
-#endif /* NOT_YET */
-
-#if 0
-        /* Fix idle thread fields. */
-        __asm__ __volatile__("ld [%0], %%g6\n\t"
-                             : : "r" (&current_set[cpuid])
-                             : "memory" /* paranoid */);
-        current->mm->mmap->vm_page_prot = PAGE_SHARED;
-        current->mm->mmap->vm_start = PAGE_OFFSET;
-        current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+       while(!task[cpuid] || current_set[cpuid] != task[cpuid])
+               barrier();
 #endif
-        
+
 #ifdef HUH
-        local_flush_cache_all();
-        local_flush_tlb_all();
+       local_flush_cache_all();
+       local_flush_tlb_all();
 #endif
 #if 0
-        __sti();
+       __sti();
 #endif
 }
 
-asmlinkage int start_secondary(void *unused)
+asmlinkage int __init
+start_secondary(void *unused)
 {
        extern asmlinkage void entInt(void);
        extern void paging_init_secondary(void);
@@ -163,35 +164,83 @@ asmlinkage int start_secondary(void *unused)
        trap_init();
        wrent(entInt, 0);
 
-        smp_callin();
-        while (!smp_commenced)
+       smp_callin();
+       while (!smp_commenced)
                barrier();
 #if 1
-printk("start_secondary: commencing CPU %d current %p\n",
-       hard_smp_processor_id(), current);
+       printk("start_secondary: commencing CPU %d current %p\n",
+              hard_smp_processor_id(), current);
 #endif
-        cpu_idle(NULL);
+       cpu_idle(NULL);
+}
+
+static void __init
+smp_tune_scheduling (void)
+{
+       /*
+        * Rough estimation for SMP scheduling, this is the number of
+        * cycles it takes for a fully memory-limited process to flush
+        * the SMP-local cache.
+        *
+        * We are not told how much cache there is, so we have to guess.
+        */
+
+       struct percpu_struct *cpu;
+       unsigned long on_chip_cache;
+       unsigned long freq;
+
+       cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
+       switch (cpu->type)
+       {
+       case EV45_CPU:
+               on_chip_cache = 16 + 16;
+               break;
+
+       case EV5_CPU:
+       case EV56_CPU:
+               on_chip_cache = 8 + 8 + 96;
+               break;
+
+       case PCA56_CPU:
+               on_chip_cache = 16 + 8;
+               break;
+
+       case EV6_CPU:
+               on_chip_cache = 64 + 64;
+               break;
+
+       default:
+               on_chip_cache = 8 + 8;
+               break;
+       }
+
+       freq = hwrpb->cycle_freq ? : est_cycle_freq;
+
+       /* Magic estimation stolen from x86 port.  */
+       cacheflush_time = freq / 1024 * on_chip_cache / 5000;
 }
 
+
 /*
  *      Cycle through the processors sending START msgs to boot each.
  */
-void smp_boot_cpus(void)
+void __init
+smp_boot_cpus(void)
 {
-        int cpucount = 0;
-        int i, first, prev;
+       int cpucount = 0;
+       int i, first, prev;
 
-        printk("smp_boot_cpus: Entering SMP Mode...\n");
+       printk("Entering SMP Mode.\n");
 
 #if 0
-        __sti();
+       __sti();
 #endif
 
-        for(i=0; i < NR_CPUS; i++) {
+       for(i=0; i < NR_CPUS; i++) {
                cpu_number_map[i] = -1;
                cpu_logical_map[i] = -1;
-                prof_counter[i] = 1;
-                prof_multiplier[i] = 1;
+               prof_counter[i] = 1;
+               prof_multiplier[i] = 1;
                ipi_bits[i] = 0;
        }
 
@@ -199,159 +248,155 @@ void smp_boot_cpus(void)
        cpu_logical_map[0] = boot_cpu_id;
        current->processor = boot_cpu_id; /* ??? */
 
-        smp_store_cpu_info(boot_cpu_id);
+       smp_store_cpu_info(boot_cpu_id);
+       smp_tune_scheduling();
 #ifdef NOT_YET
-        printk("CPU%d: ", boot_cpu_id);
-        print_cpu_info(&cpu_data[boot_cpu_id]);
-        set_irq_udt(mid_xlate[boot_cpu_id]);
-#endif /* NOT_YET */
-        smp_setup_percpu_timer();
+       printk("CPU%d: ", boot_cpu_id);
+       print_cpu_info(&cpu_data[boot_cpu_id]);
+       set_irq_udt(mid_xlate[boot_cpu_id]);
+#endif
+       smp_setup_percpu_timer();
 #ifdef HUH
-        local_flush_cache_all();
+       local_flush_cache_all();
 #endif
-        if (smp_num_probed == 1)
+       if (smp_num_probed == 1)
                return;  /* Not an MP box. */
 
 #if NOT_YET
-        /*
-         * If SMP should be disabled, then really disable it!
-         */
-        if (!max_cpus)
+       /*
+        * If SMP should be disabled, then really disable it!
+        */
+       if (!max_cpus)
        {
                smp_found_config = 0;
-                printk(KERN_INFO "SMP mode deactivated.\n");
-        }
-#endif /* NOT_YET */
+               printk(KERN_INFO "SMP mode deactivated.\n");
+       }
+#endif
 
-        for (i = 0; i < NR_CPUS; i++) {
+       for (i = 0; i < NR_CPUS; i++) {
 
                if (i == boot_cpu_id)
                        continue;
 
-                if (cpu_present_map & (1 << i)) {
-                        struct task_struct *idle;
-                        int timeout;
+               if (cpu_present_map & (1 << i)) {
+                       struct task_struct *idle;
+                       int timeout;
 
-                        /* Cook up an idler for this guy. */
-                        kernel_thread(start_secondary, NULL, CLONE_PID);
-                        idle = task[++cpucount];
+                       /* Cook up an idler for this guy. */
+                       kernel_thread(start_secondary, NULL, CLONE_PID);
+                       idle = task[++cpucount];
                        if (!idle)
                                panic("No idle process for CPU %d", i);
-                        idle->processor = i;
+                       idle->processor = i;
 
-#if 0
-printk("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
-       i, idle->state, idle->flags);
-#endif
+                       DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
+                             i, idle->state, idle->flags));
 
-                        /* whirrr, whirrr, whirrrrrrrrr... */
+                       /* whirrr, whirrr, whirrrrrrrrr... */
 #ifdef HUH
-                        local_flush_cache_all();
+                       local_flush_cache_all();
 #endif
-                        secondary_cpu_start(i, idle);
+                       secondary_cpu_start(i, idle);
 
-                        /* wheee... it's going... wait for 5 secs...*/
-                        for (timeout = 0; timeout < 50000; timeout++) {
+                       /* wheee... it's going... wait for 5 secs...*/
+                       for (timeout = 0; timeout < 50000; timeout++) {
                                if (cpu_callin_map[i])
                                        break;
-                                udelay(100);
-                        }
-                        if (cpu_callin_map[i]) {
+                               udelay(100);
+                       }
+                       if (cpu_callin_map[i]) {
                                /* Another "Red Snapper". */
                                cpu_number_map[i] = cpucount;
-                                cpu_logical_map[cpucount] = i;
-                        } else {
+                               cpu_logical_map[cpucount] = i;
+                       } else {
                                cpucount--;
-                                printk("smp_boot_cpus: Processor %d"
+                               printk("smp_boot_cpus: Processor %d"
                                       " is stuck 0x%lx.\n", i, idle->flags);
-                        }
-                }
-                if (!(cpu_callin_map[i])) {
+                       }
+               }
+               if (!(cpu_callin_map[i])) {
                        cpu_present_map &= ~(1 << i);
-                        cpu_number_map[i] = -1;
-                }
-        }
+                       cpu_number_map[i] = -1;
+               }
+       }
 #ifdef HUH
-        local_flush_cache_all();
+       local_flush_cache_all();
 #endif
-        if (cpucount == 0) {
+       if (cpucount == 0) {
                printk("smp_boot_cpus: ERROR - only one Processor found.\n");
-                cpu_present_map = (1 << smp_processor_id());
-        } else {
+               cpu_present_map = (1 << smp_processor_id());
+       } else {
                unsigned long bogosum = 0;
-                for (i = 0; i < NR_CPUS; i++) {
+               for (i = 0; i < NR_CPUS; i++) {
                        if (cpu_present_map & (1 << i))
                                bogosum += cpu_data[i].loops_per_sec;
-                }
-                printk("smp_boot_cpus: Total of %d Processors activated"
+               }
+               printk("smp_boot_cpus: Total of %d Processors activated"
                       " (%lu.%02lu BogoMIPS).\n",
-                       cpucount + 1,
-                       (bogosum + 2500)/500000,
-                       ((bogosum + 2500)/5000)%100);
-                smp_activated = 1;
-                smp_num_cpus = cpucount + 1;
-        }
-
-        /* Setup CPU list for IRQ distribution scheme. */
-        first = prev = -1;
-        for (i = 0; i < NR_CPUS; i++) {
+                      cpucount + 1,
+                      (bogosum + 2500)/500000,
+                      ((bogosum + 2500)/5000)%100);
+               smp_activated = 1;
+               smp_num_cpus = cpucount + 1;
+       }
+
+       /* Setup CPU list for IRQ distribution scheme. */
+       first = prev = -1;
+       for (i = 0; i < NR_CPUS; i++) {
                if (cpu_present_map & (1 << i)) {
                        if (first == -1)
                                first = i;
                        if (prev != -1)
                                cpu_data[i].next = i;
-                        prev = i;
-                }
-        }
-        cpu_data[prev].next = first;
-
-        /* Ok, they are spinning and ready to go. */
-        smp_processors_ready = 1;
-}
+                       prev = i;
+               }
+       }
+       cpu_data[prev].next = first;
 
-__initfunc(void ioapic_pirq_setup(char *str, int *ints))
-{
-  /* this is prolly INTEL-specific */
+       /* Ok, they are spinning and ready to go. */
+       smp_processors_ready = 1;
 }
 
-static void smp_setup_percpu_timer(void)
+static void __init
+smp_setup_percpu_timer(void)
 {
-        int cpu = smp_processor_id();
+       int cpu = smp_processor_id();
 
-        prof_counter[cpu] = prof_multiplier[cpu] = 1;
+       prof_counter[cpu] = prof_multiplier[cpu] = 1;
 #ifdef NOT_YET
-        load_profile_irq(mid_xlate[cpu], lvl14_resolution);
-        if (cpu == boot_cpu_id)
+       load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+       if (cpu == boot_cpu_id)
                enable_pil_irq(14);
 #endif
 }
 
 extern void update_one_process(struct task_struct *p, unsigned long ticks,
-                               unsigned long user, unsigned long system,
+                              unsigned long user, unsigned long system,
                               int cpu);
 
-void smp_percpu_timer_interrupt(struct pt_regs *regs)
+void
+smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
        int cpu = smp_processor_id();
 
 #ifdef NOT_YET
-        clear_profile_irq(mid_xlate[cpu]);
-        if(!user_mode(regs))
+       clear_profile_irq(mid_xlate[cpu]);
+       if(!user_mode(regs))
                alpha_do_profile(regs->pc);
 #endif
 
-        if (!--prof_counter[cpu]) {
+       if (!--prof_counter[cpu]) {
                int user = user_mode(regs);
-                if (current->pid) {
+               if (current->pid) {
                        update_one_process(current, 1, user, !user, cpu);
 
-                        if (--current->counter < 0) {
+                       if (--current->counter < 0) {
                                current->counter = 0;
-                                current->need_resched = 1;
-                        }
+                               current->need_resched = 1;
+                       }
 
-                        spin_lock(&ticker_lock);
-                        if (user) {
+                       spin_lock(&ticker_lock);
+                       if (user) {
                                if (current->priority < DEF_PRIORITY) {
                                        kstat.cpu_nice++;
                                        kstat.per_cpu_nice[cpu]++;
@@ -359,93 +404,86 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
                                        kstat.cpu_user++;
                                        kstat.per_cpu_user[cpu]++;
                                }
-                        } else {
+                       } else {
                                kstat.cpu_system++;
                                kstat.per_cpu_system[cpu]++;
-                        }
-                        spin_unlock(&ticker_lock);
-                }
-                prof_counter[cpu] = prof_multiplier[cpu];
-        }
+                       }
+                       spin_unlock(&ticker_lock);
+               }
+               prof_counter[cpu] = prof_multiplier[cpu];
+       }
 }
 
-int setup_profiling_timer(unsigned int multiplier)
+int __init
+setup_profiling_timer(unsigned int multiplier)
 {
 #ifdef NOT_YET
-        int i;
-        unsigned long flags;
+       int i;
+       unsigned long flags;
 
-        /* Prevent level14 ticker IRQ flooding. */
-        if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-                return -EINVAL;
+       /* Prevent level14 ticker IRQ flooding. */
+       if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+               return -EINVAL;
 
-        save_and_cli(flags);
-        for(i = 0; i < NR_CPUS; i++) {
-                if(cpu_present_map & (1 << i)) {
-                        load_profile_irq(mid_xlate[i], lvl14_resolution / multip
+       save_and_cli(flags);
+       for(i = 0; i < NR_CPUS; i++) {
+               if(cpu_present_map & (1 << i)) {
+                       load_profile_irq(mid_xlate[i], lvl14_resolution / multip
 lier);
-                        prof_multiplier[i] = multiplier;
-                }
-        }
-        restore_flags(flags);
+                       prof_multiplier[i] = multiplier;
+               }
+       }
+       restore_flags(flags);
 
-        return 0;
+       return 0;
 
 #endif
   return -EINVAL;
 }
 
-/* Only broken Intel needs this, thus it should not even be referenced globally.
-*/
-__initfunc(void initialize_secondary(void))
+/* Only broken Intel needs this, thus it should not even be
+   referenced globally.  */
+
+void __init
+initialize_secondary(void)
 {
-       printk("initialize_secondary: entry\n");
 }
 
-static void
+static void __init
 secondary_cpu_start(int cpuid, struct task_struct *idle)
 {
        struct percpu_struct *cpu;
-        int timeout;
+       int timeout;
          
        cpu = (struct percpu_struct *)
                ((char*)hwrpb
-                       + hwrpb->processor_offset
-                       + cpuid * hwrpb->processor_size);
+                + hwrpb->processor_offset
+                + cpuid * hwrpb->processor_size);
 
-       /* set context to idle thread this CPU will use when running */
-       /* assumption is that the idle thread is all set to go... ??? */
+       /* Set context to idle thread this CPU will use when running
+          assumption is that the idle thread is all set to go... ??? */
        memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
        cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
-#if 0
-printk("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
-       cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb);
-printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
-       cpuid, idle->state, idle->tss.pal_flags);
-#endif
 
-       /* setup HWRPB fields that SRM uses to activate secondary CPU */
-        hwrpb->CPU_restart = __start_cpu;
-        hwrpb->CPU_restart_data = (unsigned long) idle;
-
-        /* recalculate and update the HWRPB checksum */
-        {
-          unsigned long sum, *lp1, *lp2;
-          sum = 0;
-          lp1 = (unsigned long *)hwrpb;
-          lp2 = &hwrpb->chksum;
-          while (lp1 < lp2)
-            sum += *lp1++;
-          *lp2 = sum;
-        }
+       DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
+             cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb));
+       DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
+             cpuid, idle->state, idle->tss.pal_flags));
+
+       /* Setup HWRPB fields that SRM uses to activate secondary CPU */
+       hwrpb->CPU_restart = __start_cpu;
+       hwrpb->CPU_restart_data = (unsigned long) idle;
+
+       /* Recalculate and update the HWRPB checksum */
+       hwrpb_update_checksum(hwrpb);
 
        /*
         * Send a "start" command to the specified processor.
         */
 
        /* SRM III 3.4.1.3 */
-       cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */
-       cpu->flags &= ~1;/* turn off Bootstrap In Progress */
+       cpu->flags |= 0x22;     /* turn on Context Valid and Restart Capable */
+       cpu->flags &= ~1;       /* turn off Bootstrap In Progress */
        mb();
 
        send_cpu_msg("START\r\n", cpuid);
@@ -454,7 +492,7 @@ printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
        for (timeout = 10000; !(cpu->flags & 1); timeout--) {
                if (timeout <= 0) {
                        printk("Processor %d failed to start\n", cpuid);
-                                /* needed for pset_info to work */
+                               /* needed for pset_info to work */
 #if 0
                        ipc_processor_enable(cpu_to_processor(cpunum));
 #endif
@@ -462,49 +500,61 @@ printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
                }
                mdelay(1);
        }
-#if 0
-       printk("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid);
-#endif
+       DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
 }
 
 static void
 send_cpu_msg(char *str, int cpuid)
 {
        struct percpu_struct *cpu;
-        register char *cp1, *cp2;
-        unsigned long cpumask;
-        int timeout;
+       register char *cp1, *cp2;
+       unsigned long cpumask;
+       size_t len;
+       int timeout;
 
-         
        cpu = (struct percpu_struct *)
                ((char*)hwrpb
-                       + hwrpb->processor_offset
-                       + cpuid * hwrpb->processor_size);
-
-        cpumask = (1L << cpuid);
-        for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) {
-                if (timeout <= 0) {
-                        printk("Processor %x not ready\n", cpuid);
-                        return;
-                }
-                mdelay(1);
-        }
-
-        cp1 = (char *) &cpu->ipc_buffer[1];
-        cp2 = str;
-        while (*cp2) *cp1++ = *cp2++;
-        *(unsigned int *)&cpu->ipc_buffer[0] = cp2 - str; /* hack */
-
-        /* atomic test and set */
-        set_bit(cpuid, &hwrpb->rxrdy);
-
-        for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) {
-                if (timeout <= 0) {
-                        printk("Processor %x not ready\n", cpuid);
-                        return;
-                }
-                mdelay(1);
-        }
+                + hwrpb->processor_offset
+                + cpuid * hwrpb->processor_size);
+
+       cpumask = (1L << cpuid);
+       if (hwrpb->txrdy & cpumask)
+               goto delay1;
+       ready1:
+
+       cp2 = str;
+       len = strlen(cp2);
+       *(unsigned int *)&cpu->ipc_buffer[0] = len;
+       cp1 = (char *) &cpu->ipc_buffer[1];
+       memcpy(cp1, cp2, len);
+
+       /* atomic test and set */
+       set_bit(cpuid, &hwrpb->rxrdy);
+
+       if (hwrpb->txrdy & cpumask)
+               goto delay2;
+       ready2:
+       return;
+
+delay1:
+       for (timeout = 10000; timeout > 0; --timeout) {
+               if (!(hwrpb->txrdy & cpumask))
+                       goto ready1;
+               udelay(100);
+       }
+       goto timeout;
+
+delay2:
+       for (timeout = 10000; timeout > 0; --timeout) {
+               if (!(hwrpb->txrdy & cpumask))
+                       goto ready2;
+               udelay(100);
+       }
+       goto timeout;
+
+timeout:
+       printk("Processor %x not ready\n", cpuid);
+       return;
 }
 
 /*
@@ -512,7 +562,8 @@ send_cpu_msg(char *str, int cpuid)
  *
  * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
  */
-__initfunc(void setup_smp(void))
+void __init
+setup_smp(void)
 {
        struct percpu_struct *cpubase, *cpu;
        int i;
@@ -523,10 +574,10 @@ __initfunc(void setup_smp(void))
        }
 
        if (hwrpb->nr_processors > 1) {
-#if 0
-printk("setup_smp: nr_processors 0x%lx\n",
-       hwrpb->nr_processors);
-#endif
+
+               DBGS(("setup_smp: nr_processors %ld\n",
+                     hwrpb->nr_processors));
+
                cpubase = (struct percpu_struct *)
                        ((char*)hwrpb + hwrpb->processor_offset);
                boot_cpu_palrev = cpubase->pal_revision;
@@ -541,12 +592,11 @@ printk("setup_smp: nr_processors 0x%lx\n",
                                if (i != boot_cpu_id)
                                  cpu->pal_revision = boot_cpu_palrev;
                        }
-#if 0
-printk("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
-       i, cpu->flags, cpu->type);
- printk("setup_smp: CPU %d: PAL rev 0x%lx\n",
-       i, cpu->pal_revision);
-#endif
+
+                       DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
+                             i, cpu->flags, cpu->type));
+                       DBGS(("setup_smp: CPU %d: PAL rev 0x%lx\n",
+                             i, cpu->pal_revision));
                }
        } else {
                smp_num_probed = 1;
@@ -560,132 +610,59 @@ printk("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
 static void
 secondary_console_message(void)
 {
-        int mycpu, i, cnt;
+       int mycpu, i, cnt;
        unsigned long txrdy = hwrpb->txrdy;
        char *cp1, *cp2, buf[80];
-        struct percpu_struct *cpu;
-
-        mycpu = hard_smp_processor_id();
-
-#if 0
-printk("secondary_console_message: TXRDY 0x%lx.\n", txrdy);
-#endif
-        for (i = 0; i < NR_CPUS; i++) {
-          if (txrdy & (1L << i)) {
-#if 0
-printk("secondary_console_message: TXRDY contains CPU %d.\n", i);
-#endif
-            cpu = (struct percpu_struct *)
-              ((char*)hwrpb
-               + hwrpb->processor_offset
-               + i * hwrpb->processor_size);
-#if 1
-            printk("secondary_console_message: on %d from %d"
-                   " HALT_REASON 0x%lx FLAGS 0x%lx\n",
-                   mycpu, i, cpu->halt_reason, cpu->flags);
-#endif
-            cnt = cpu->ipc_buffer[0] >> 32;
-            if (cnt <= 0 || cnt >= 80)
-              strcpy(buf,"<<< BOGUS MSG >>>");
-            else {
-              cp1 = (char *) &cpu->ipc_buffer[11];
-              cp2 = buf;
-              while (cnt--) {
-                if (*cp1 == '\r' || *cp1 == '\n') {
-                  *cp2++ = ' '; cp1++;
-                } else
-                  *cp2++ = *cp1++;
-              }
-              *cp2 = 0;
-            }
-#if 1
-            printk("secondary_console_message: on %d message is '%s'\n",
-                   mycpu, buf);
-#endif
-          }
-               }
-        hwrpb->txrdy = 0;
-        return;
-}
-
-static int
-halt_on_panic(unsigned int this_cpu)
-{
-       halt();
-       return 0;
-}
-
-static int
-local_flush_tlb_all(unsigned int this_cpu)
-{
-       tbia();
-       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
-       return 0;
-}
+       struct percpu_struct *cpu;
 
-static int
-local_flush_tlb_mm(unsigned int this_cpu)
-{
-       struct mm_struct * mm = ipi_msg_flush_tb.p.flush_mm;
-       if (mm == current->mm)
-               flush_tlb_current(mm);
-       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
-       return 0;
-}
+       DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy));
 
-static int
-local_flush_tlb_page(unsigned int this_cpu)
-{
-       struct vm_area_struct * vma = ipi_msg_flush_tb.p.flush_vma;
-       struct mm_struct * mm = vma->vm_mm;
+       mycpu = hard_smp_processor_id();
 
-       if (mm == current->mm)
-               flush_tlb_current_page(mm, vma, ipi_msg_flush_tb.flush_addr);
-       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
-       return 0;
-}
+       for (i = 0; i < NR_CPUS; i++) {
+               if (!(txrdy & (1L << i)))
+                       continue;
 
-static int
-wrapper_local_flush_tlb_page(unsigned int this_cpu)
-{
-#if 0
-       int cpu = smp_processor_id();
+               DBGS(("secondary_console_message: "
+                     "TXRDY contains CPU %d.\n", i));
+
+               cpu = (struct percpu_struct *)
+                 ((char*)hwrpb
+                  + hwrpb->processor_offset
+                  + i * hwrpb->processor_size);
+
+               printk("secondary_console_message: on %d from %d"
+                      " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+                      mycpu, i, cpu->halt_reason, cpu->flags);
+
+               cnt = cpu->ipc_buffer[0] >> 32;
+               if (cnt <= 0 || cnt >= 80)
+                       strcpy(buf, "<<< BOGUS MSG >>>");
+               else {
+                       cp1 = (char *) &cpu->ipc_buffer[11];
+                       cp2 = buf;
+                       strcpy(cp2, cp1);
+                       
+                       while ((cp2 = strchr(cp2, '\r')) != 0) {
+                               *cp2 = ' ';
+                               if (cp2[1] == '\n')
+                                       cp2[1] = ' ';
+                       }
+               }
 
-       if (cpu) {
-         printk("wrapper: ipi_msg_flush_tb.flush_addr 0x%lx [%d]\n",
-                ipi_msg_flush_tb.flush_addr, atomic_read(&global_irq_count));
+               printk("secondary_console_message: on %d message is '%s'\n",
+                      mycpu, buf);
        }
-#endif
-       local_flush_tlb_page(this_cpu);
-       return 0;
-}
 
-static int
-unknown_ipi(unsigned int this_cpu)
-{
-       printk("unknown_ipi() on CPU %d:  ", this_cpu);
-       return 1;
+       hwrpb->txrdy = 0;
 }
 
 enum ipi_message_type {
-  CPU_STOP,
-  TLB_ALL,
-  TLB_MM,
-  TLB_PAGE,
-  TLB_RANGE
-};
-
-static int (* ipi_func[32])(unsigned int) = {
-  halt_on_panic,
-  local_flush_tlb_all,
-  local_flush_tlb_mm,
-  wrapper_local_flush_tlb_page,
-  local_flush_tlb_mm,          /* a.k.a. local_flush_tlb_range */
-  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
-  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
-  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
-  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
-  unknown_ipi, unknown_ipi, unknown_ipi
+       IPI_TLB_ALL,
+       IPI_TLB_MM,
+       IPI_TLB_PAGE,
+       IPI_RESCHEDULE,
+       IPI_CPU_STOP
 };
 
 void
@@ -693,122 +670,165 @@ handle_ipi(struct pt_regs *regs)
 {
        int this_cpu = smp_processor_id();
        volatile int * pending_ipis = &ipi_bits[this_cpu];
-       int ops;
+       unsigned long ops, which;
+
+       DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
+             this_cpu, *pending_ipis, regs->pc));
+
+       mb();   /* Order interrupt and bit testing. */
+       while ((ops = xchg(pending_ipis, 0)) != 0) {
+         mb(); /* Order bit clearing and data access. */
+         do {
+               unsigned long which;
+
+               which = ops & -ops;
+               ops &= ~which;
+               which = ffz(~which);
+
+               if (which < IPI_RESCHEDULE) {
+                       if (which == IPI_TLB_ALL)
+                               tbia();
+                       else if (which == IPI_TLB_MM) {
+                               struct mm_struct * mm;
+                               mm = ipi_msg_flush_tb.p.flush_mm;
+                               if (mm == current->mm)
+                                       flush_tlb_current(mm);
+                       }
+                       else /* IPI_TLB_PAGE */ {
+                               struct vm_area_struct * vma;
+                               struct mm_struct * mm;
+                               unsigned long addr;
 
-       mb();           /* Order bit setting and interrupt. */
-#if 0
-       printk("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
-              this_cpu, *pending_ipis, regs->pc);
-#endif
-       while ((ops = *pending_ipis)) {
-               int first;
-               for (first = 0; (ops & 1) == 0; ++first, ops >>= 1)
-                       ; /* look for the first thing to do */
-               clear_bit(first, pending_ipis);
-               mb();   /* Order bit clearing and data access. */
-               if ((*ipi_func[first])(this_cpu))
-                       printk("%d\n", first);
-               mb();   /* Order data access and bit clearing. */
+                               vma = ipi_msg_flush_tb.p.flush_vma;
+                               mm = vma->vm_mm;
+                               addr = ipi_msg_flush_tb.flush_addr;
+
+                               if (mm == current->mm)
+                                       flush_tlb_current_page(mm, vma, addr);
+                       }
+                       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
+               }
+               else if (which == IPI_RESCHEDULE) {
+                       /* Reschedule callback.  Everything to be done
+                          is done by the interrupt return path.  */
+               }
+               else if (which == IPI_CPU_STOP) {
+                       halt();
+               }
+               else {
+                       printk(KERN_CRIT "unknown_ipi() on CPU %ld: %d\n",
+                              this_cpu, which);
+               }
+         } while (ops);
+         mb(); /* Order data access and bit testing. */
        }
+
+       cpu_data[this_cpu].ipi_count++;
+
        if (hwrpb->txrdy)
-         secondary_console_message();
+               secondary_console_message();
 }
 
-void
-send_ipi_message(long to_whom, enum ipi_message_type operation)
+static void
+send_ipi_message(unsigned long to_whom, enum ipi_message_type operation)
 {
-       int i;
-       unsigned int j;
+       long i, j;
 
-       mb();                   /* Order out-of-band data and bit setting. */
-       for (i = 0, j = 1; i < NR_CPUS; ++i, j += j) {
-               if ((to_whom & j) == 0)
-                       continue;
-               set_bit(operation, &ipi_bits[i]);
-               mb();           /* Order bit setting and interrupt. */
-               wripir(i);
+       /* Reduce the number of memory barriers by doing two loops,
+          one to set the bits, one to invoke the interrupts.  */
+
+       mb();   /* Order out-of-band data and bit setting. */
+
+       for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+               if (to_whom & j)
+                       set_bit(operation, &ipi_bits[i]);
+       }
+
+       mb();   /* Order bit setting and interrupt. */
+
+       for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) {
+               if (to_whom & j)
+                       wripir(i);
        }
 }
 
 int
 smp_info(char *buffer)
 {
-       int i;
+       long i;
        unsigned long sum = 0;
        for (i = 0; i < NR_CPUS; i++)
-               sum += ipicnt[i];
+               sum += cpu_data[i].ipi_count;
 
-        return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
+       return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n",
                       smp_num_probed, smp_num_cpus, cpu_present_map, sum);
 }
 
-/* wrapper for call from panic() */
 void
-smp_message_pass(int target, int msg, unsigned long data, int wait)
+smp_send_reschedule(int cpu)
 {
-       int me = smp_processor_id();
-
-       if (msg != MSG_STOP_CPU)
-               goto barf;
+       send_ipi_message(1 << cpu, IPI_RESCHEDULE);
+}
 
-       send_ipi_message(CPU_STOP, cpu_present_map ^ (1 << me));
-       return;
-barf:
-       printk("Yeeee, trying to send SMP msg(%d) on CPU %d\n", msg, me);
-       panic("Bogon SMP message pass.");
+void
+smp_send_stop(void)
+{
+       unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
+       send_ipi_message(to_whom, IPI_CPU_STOP);
 }
 
 void
 flush_tlb_all(void)
 {
-       unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
-       int timeout = 10000;
+       unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
+       long timeout = 1000000;
 
        spin_lock_own(&kernel_flag, "flush_tlb_all");
 
        ipi_msg_flush_tb.flush_tb_mask = to_whom;
-       send_ipi_message(to_whom, TLB_ALL);
+       send_ipi_message(to_whom, IPI_TLB_ALL);
        tbia();
 
-       while (ipi_msg_flush_tb.flush_tb_mask) {
-               if (--timeout < 0) {
-                       printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
-                              smp_processor_id(),
-                              ipi_msg_flush_tb.flush_tb_mask);
-                       ipi_msg_flush_tb.flush_tb_mask = 0;
-                       break;
-               }
-               /* Wait for all clear from other CPUs. */
-               udelay(100);
+       while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
+               udelay(1);
+               barrier();
+       }
+
+       if (timeout == 0) {
+               printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
+                      smp_processor_id(),
+                      ipi_msg_flush_tb.flush_tb_mask);
+               ipi_msg_flush_tb.flush_tb_mask = 0;
        }
 }
 
 void
 flush_tlb_mm(struct mm_struct *mm)
 {
-       unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
-       int timeout = 10000;
+       unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
+       long timeout = 1000000;
 
        spin_lock_own(&kernel_flag, "flush_tlb_mm");
 
-       ipi_msg_flush_tb.p.flush_mm = mm;
        ipi_msg_flush_tb.flush_tb_mask = to_whom;
-       send_ipi_message(to_whom, TLB_MM);
+       ipi_msg_flush_tb.p.flush_mm = mm;
+       send_ipi_message(to_whom, IPI_TLB_MM);
 
        if (mm != current->mm)
                flush_tlb_other(mm);
        else
                flush_tlb_current(mm);
 
-       while (ipi_msg_flush_tb.flush_tb_mask) {
-         if (--timeout < 0) {
-           printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
-                  smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
-           ipi_msg_flush_tb.flush_tb_mask = 0;
-           break;
-         }
-         udelay(100);
-               ; /* Wait for all clear from other CPUs. */
+       while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
+               udelay(1);
+               barrier();
+       }
+
+       if (timeout == 0) {
+               printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
+                      smp_processor_id(),
+                      ipi_msg_flush_tb.flush_tb_mask);
+               ipi_msg_flush_tb.flush_tb_mask = 0;
        }
 }
 
@@ -816,68 +836,40 @@ void
 flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
 {
        int cpu = smp_processor_id();
-       unsigned int to_whom = cpu_present_map ^ (1 << cpu);
+       unsigned long to_whom = cpu_present_map ^ (1 << cpu);
        struct mm_struct * mm = vma->vm_mm;
-       int timeout = 10000;
+       int timeout = 1000000;
 
        spin_lock_own(&kernel_flag, "flush_tlb_page");
 
+       ipi_msg_flush_tb.flush_tb_mask = to_whom;
        ipi_msg_flush_tb.p.flush_vma = vma;
        ipi_msg_flush_tb.flush_addr = addr;
-       ipi_msg_flush_tb.flush_tb_mask = to_whom;
-       send_ipi_message(to_whom, TLB_PAGE);
+       send_ipi_message(to_whom, IPI_TLB_PAGE);
 
        if (mm != current->mm)
                flush_tlb_other(mm);
        else
                flush_tlb_current_page(mm, vma, addr);
 
-       while (ipi_msg_flush_tb.flush_tb_mask) {
-         if (--timeout < 0) {
-           printk("flush_tlb_page: STUCK on CPU %d [0x%x,0x%lx,%d]\n",
-                  cpu, ipi_msg_flush_tb.flush_tb_mask, addr,
-                  global_irq_holder);
-           ipi_msg_flush_tb.flush_tb_mask = 0;
-           break;
-         }
-         udelay(100);
-               ; /* Wait for all clear from other CPUs. */
+       while (ipi_msg_flush_tb.flush_tb_mask && --timeout) {
+               udelay(1);
+               barrier();
+       }
+
+       if (timeout == 0) {
+               printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n",
+                      smp_processor_id(),
+                      ipi_msg_flush_tb.flush_tb_mask);
+               ipi_msg_flush_tb.flush_tb_mask = 0;
        }
 }
 
 void
 flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-#if 0
+       /* On the Alpha we always flush the whole user tlb.  */
        flush_tlb_mm(mm);
-#else
-       unsigned int to_whom;
-       int timeout;
-
-       timeout = 10000;
-       to_whom = cpu_present_map ^ (1 << smp_processor_id());
-
-       spin_lock_own(&kernel_flag, "flush_tlb_range");
-
-       ipi_msg_flush_tb.p.flush_mm = mm;
-       ipi_msg_flush_tb.flush_tb_mask = to_whom;
-       send_ipi_message(to_whom, TLB_MM);
-
-       if (mm != current->mm)
-               flush_tlb_other(mm);
-       else
-               flush_tlb_current(mm);
-
-       while (ipi_msg_flush_tb.flush_tb_mask) {
-         if (--timeout < 0) {
-           printk("flush_tlb_range: STUCK on CPU %d mask 0x%x\n",
-                  smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
-           ipi_msg_flush_tb.flush_tb_mask = 0;
-           break;
-         }
-         udelay(100); /* Wait for all clear from other CPUs. */
-       }
-#endif
 }
 
 #if DEBUG_SPINLOCK
@@ -902,8 +894,8 @@ spinlock_restore_ipl(long prev)
 
 #else
 
-#define spinlock_raise_ipl(LOCK)       0
-#define spinlock_restore_ipl(PREV)     ((void)0)
+#define spinlock_raise_ipl(LOCK)       ((LOCK), 0)
+#define spinlock_restore_ipl(PREV)     ((void)(PREV))
 
 #endif /* MANAGE_SPINLOCK_IPL */
 
index 3e5c4e7ffc9a03175c3b2f2fd87eec95d5ba6d46..322b53210e2b1391da904ebdf1b98cac947d32f9 100644 (file)
@@ -35,6 +35,10 @@ ifdef CONFIG_M586
 CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
 endif
 
+ifdef CONFIG_M586TSC
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
+endif
+
 ifdef CONFIG_M686
 CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686
 endif
index f64a0da2fc24a7f8f98a36c8512e97b4728d5046..5194153c763ec2a712d102eb51a244086823d039 100644 (file)
@@ -14,8 +14,24 @@ comment 'Processor type and features'
 choice 'Processor family' \
        "386                    CONFIG_M386     \
         486/Cx486              CONFIG_M486     \
-        Pentium/K5/5x86/6x86   CONFIG_M586     \
-        PPro/K6/6x86MX         CONFIG_M686" Pentium
+        586/K5/5x86/6x86       CONFIG_M586     \
+        Pentium/TSC            CONFIG_M586TSC  \
+        PPro/K6/6x86MX         CONFIG_M686" PPro
+#
+# Define implied options from the CPU selection here
+#
+if [ "$CONFIG_M386" != "n" ]; then
+  define_bool CONFIG_WP_WORKS_OK y
+  define_bool CONFIG_INVLPG y
+  define_bool CONFIG_BSWAP y
+fi
+if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" ]; then
+  define_bool CONFIG_TSC y
+fi
+if [ "$CONFIG_M686" = "y" ]; then
+  define_bool CONFIG_GOOD_APIC y
+fi
+
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -36,15 +52,14 @@ comment 'General setup'
 bool 'Networking support' CONFIG_NET
 bool 'PCI support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
-  unset CONFIG_PCI_BIOS CONFIG_PCI_DIRECT
   choice 'PCI access mode' \
        "BIOS           CONFIG_PCI_GOBIOS       \
         Direct         CONFIG_PCI_GODIRECT     \
         Any            CONFIG_PCI_GOANY"       Any
-  if [ -n "$CONFIG_PCI_GOBIOS" -o -n "$CONFIG_PCI_GOANY" ]; then
+  if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
     define_bool CONFIG_PCI_BIOS y
   fi
-  if [ -n "$CONFIG_PCI_GODIRECT" -o -n "$CONFIG_PCI_GOANY" ]; then
+  if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
     define_bool CONFIG_PCI_DIRECT y
   fi
   bool '   PCI quirks' CONFIG_PCI_QUIRKS
index 4187224cda509d84e356a7ea43f635e6ee296ee4..6e7572aad5432b9842d848c9fe322537269bfbee 100644 (file)
 #
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
-CONFIG_M586=y
-# CONFIG_M686 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+CONFIG_M686=y
+CONFIG_TSC=y
+CONFIG_GOOD_APIC=y
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_MTRR is not set
 CONFIG_SMP=y
@@ -176,7 +179,6 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -305,7 +307,6 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-CONFIG_NFSD=y
 # CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
index 85352886fb852c884d74ce2cd81b7067538a3ec7..0906a7d7688a9c46c82cb202166e4d43a0ba0dd0 100644 (file)
@@ -58,6 +58,9 @@ EXPORT_SYMBOL_NOVERS(__put_user_1);
 EXPORT_SYMBOL_NOVERS(__put_user_2);
 EXPORT_SYMBOL_NOVERS(__put_user_4);
 
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
+
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
 EXPORT_SYMBOL(clear_user);
index 435de9bc28ae1394dc23fbf9d05047c2affa4853..c584ccc0b1deeee85a9174dd6ac4f4bcf94da985 100644 (file)
@@ -900,7 +900,7 @@ unsigned long probe_irq_on(void)
        /*
         * Wait for spurious interrupts to trigger
         */
-       for (delay = jiffies + HZ/10; delay > jiffies; )
+       for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
                /* about 100ms delay */ synchronize_irq();
 
        /*
index 52a1543c39b73365e31be09724794f088c3f3abc..46afb0e2451c587e32a5226794486f138e52d0ca 100644 (file)
@@ -420,7 +420,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_PEEKDATA: {
                        unsigned long tmp;
 
+                       down(&child->mm->mmap_sem);
                        ret = read_long(child, addr, &tmp);
+                       up(&child->mm->mmap_sem);
                        if (ret >= 0)
                                ret = put_user(tmp,(unsigned long *) data);
                        goto out;
@@ -451,7 +453,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
       /* when I and D space are separate, this will have to be fixed. */
                case PTRACE_POKETEXT: /* write the word at location addr. */
                case PTRACE_POKEDATA:
+                       down(&child->mm->mmap_sem);
                        ret = write_long(child,addr,data);
+                       up(&child->mm->mmap_sem);
                        goto out;
 
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
index 490c4db820038ff60924584b1ccf5e2fbdb18ea8..4bee3b7cbd7eaaa3fd74f2d220b39ced5ec663a5 100644 (file)
@@ -597,7 +597,7 @@ int get_cpuinfo(char * buffer)
 
        for(n=0; n<NR_CPUS; n++, c++) {
 #ifdef __SMP__
-               if (!(cpu_present_map & (1<<n)))
+               if (!(cpu_online_map & (1<<n)))
                        continue;
 #endif
                p += sprintf(p,"processor\t: %d\n"
index d9fcc1e5c155afe843029aff41b21a633d6e1b80..10abc7863b841d675d6484780f57e0e85b308362 100644 (file)
@@ -119,19 +119,21 @@ extern __inline int max(int a,int b)
  * function prototypes:
  */
 static void cache_APIC_registers (void);
-
+static void stop_this_cpu (void);
 
 static int smp_b_stepping = 0;                         /* Set if we find a B stepping CPU                      */
 
 static int max_cpus = -1;                              /* Setup configured maximum number of CPUs to activate  */
 int smp_found_config=0;                                        /* Have we found an SMP box                             */
 
-unsigned long cpu_present_map = 0;                     /* Bitmask of existing CPUs                             */
+unsigned long cpu_present_map = 0;                     /* Bitmask of physically existing CPUs                          */
+unsigned long cpu_online_map = 0;                      /* Bitmask of currently online CPUs                             */
 int smp_num_cpus = 1;                                  /* Total count of live CPUs                             */
 int smp_threads_ready=0;                               /* Set when the idlers are all forked                   */
 volatile int cpu_number_map[NR_CPUS];                  /* which CPU maps to which logical number               */
 volatile int __cpu_logical_map[NR_CPUS];                       /* which logical number maps to which CPU               */
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
+static volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};  /* We always use 0 the rest is ready for parallel delivery */
+static volatile unsigned long cpu_callout_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
 volatile unsigned long smp_invalidate_needed;          /* Used for the invalidate map that's also checked in the spinlock */
 volatile unsigned long kstack_ptr;                     /* Stack vector for booting CPUs                        */
 struct cpuinfo_x86 cpu_data[NR_CPUS];                  /* Per CPU bogomips and other parameters                */
@@ -694,16 +696,55 @@ unsigned long __init init_smp_mappings(unsigned long memory_start)
        return memory_start;
 }
 
+extern void calibrate_delay(void);
+
 void __init smp_callin(void)
 {
-       extern void calibrate_delay(void);
-       int cpuid=GET_APIC_ID(apic_read(APIC_ID));
+       int cpuid;
+       unsigned long timeout;
+
+       /*
+        * (This works even if the APIC is not enabled.)
+        */
+       cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+       SMP_PRINTK(("CPU#%d waiting for CALLOUT\n", cpuid));
+
+       /*
+        * STARTUP IPIs are fragile beasts as they might sometimes
+        * trigger some glue motherboard logic. Complete APIC bus
+        * silence for 1 second, this overestimates the time the
+        * boot CPU is spending to send the up to 2 STARTUP IPIs
+        * by a factor of two. This should be enough.
+        */
+
+       /*
+        * Waiting 2s total for startup (udelay is not yet working)
+        */
+       timeout = jiffies + 2*HZ;
+       while (time_before(jiffies,timeout))
+       {
+               /*
+                * Has the boot CPU finished it's STARTUP sequence?
+                */
+               if (test_bit(cpuid, (unsigned long *)&cpu_callout_map[0]))
+                       break;
+       }
+
+       while (!time_before(jiffies,timeout)) {
+               printk("BUG: CPU%d started up but did not get a callout!\n",
+                       cpuid);
+               stop_this_cpu();
+       }
 
        /*
-        *      Activate our APIC
+        * the boot CPU has finished the init stage and is spinning
+        * on callin_map until we finish. We are free to set up this
+        * CPU, first the APIC. (this is probably redundant on most
+        * boards)
         */
        
-       SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
+       SMP_PRINTK(("CALLIN, before enable_local_APIC().\n"));
        enable_local_APIC();
 
        /*
@@ -711,7 +752,12 @@ void __init smp_callin(void)
         */
        setup_APIC_clock();
 
-       sti();
+       __sti();
+
+#ifdef CONFIG_MTRR
+       /*  Must be done before calibration delay is computed  */
+       mtrr_init_secondary_cpu ();
+#endif
        /*
         *      Get our bogomips.
         */
@@ -738,10 +784,11 @@ extern int cpu_idle(void * unused);
  */
 int __init start_secondary(void *unused)
 {
-#ifdef CONFIG_MTRR
-       /*  Must be done before calibration delay is computed  */
-       mtrr_init_secondary_cpu ();
-#endif
+       /*
+        * Dont put anything before smp_callin(), SMP
+        * booting is too fragile that we want to limit the
+        * things done here to the most necessary things.
+        */
        smp_callin();
        while (!atomic_read(&smp_commenced))
                /* nothing */ ;
@@ -917,12 +964,18 @@ static void __init do_boot_cpu(int i)
                apic_write(APIC_ICR, cfg);                                              /* Kick the second      */
 
                SMP_PRINTK(("Startup point 1.\n"));
+
                timeout = 0;
+               SMP_PRINTK(("Waiting for send to finish...\n"));
                do {
-                       SMP_PRINTK(("Sleeping.\n")); mdelay(1000);
-                       udelay(10);
-               } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
-                         && (timeout++ < 1000));
+                       SMP_PRINTK(("+"));
+                       udelay(100);
+                       send_status = apic_read(APIC_ICR) & 0x1000;
+               } while (send_status && (timeout++ < 1000));
+
+               /*
+                * Give the other CPU some time to accept the IPI.
+                */
                udelay(200);
                accept_status = (apic_read(APIC_ESR) & 0xEF);
        }
@@ -935,6 +988,13 @@ static void __init do_boot_cpu(int i)
 
        if ( !(send_status || accept_status) )
        {
+               /*
+                * allow APs to start initializing.
+                */
+               SMP_PRINTK(("Before Callout %d.\n", i));
+               set_bit(i, (unsigned long *)&cpu_callout_map[0]);
+               SMP_PRINTK(("After Callout %d.\n", i));
+
                for(timeout=0;timeout<50000;timeout++)
                {
                        if (cpu_callin_map[0]&(1<<i))
@@ -980,6 +1040,7 @@ extern unsigned long cpu_hz;
 
 static void smp_tune_scheduling (void)
 {
+       unsigned long cachesize;
        /*
         * Rough estimation for SMP scheduling, this is the number of
         * cycles it takes for a fully memory-limited process to flush
@@ -990,7 +1051,21 @@ static void smp_tune_scheduling (void)
         *  L1 cache), on PIIs it's around 50-100 usecs, depending on
         *  the cache size)
         */
-       cacheflush_time = cpu_hz/1024*boot_cpu_data.x86_cache_size/5000;
+
+       if (boot_cpu_data.x86 <= 4) {
+               /*
+                * this basically disables processor-affinity
+                * scheduling on <=i486 based SMP boards.
+                */
+               cacheflush_time = 0;
+       } else {
+               cachesize = boot_cpu_data.x86_cache_size;
+               if (cachesize == -1)
+                       cachesize = 8; /* Pentiums */
+
+               cacheflush_time = cpu_hz/1024*cachesize/5000;
+       }
+
        printk("per-CPU timeslice cutoff: %ld.%ld usecs.\n",
                (long)cacheflush_time/(cpu_hz/1000000),
                ((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
@@ -1032,7 +1107,13 @@ void __init smp_boot_cpus(void)
        printk("CPU%d: ", boot_cpu_id);
        print_cpu_info(&cpu_data[boot_cpu_id]);
 
+       /*
+        * not necessary because the MP table should list the boot
+        * CPU too, but we do it for the sake of robustness anyway.
+        * (and for the case when a non-SMP board boots an SMP kernel)
+        */
        cpu_present_map |= (1 << hard_smp_processor_id());
+
        cpu_number_map[boot_cpu_id] = 0;
 
        /*
@@ -1106,6 +1187,14 @@ void __init smp_boot_cpus(void)
         *      Now scan the CPU present map and fire up the other CPUs.
         */
 
+       /*
+        * Add all detected CPUs. (later on we can down individual
+        * CPUs which will change cpu_online_map but not necessarily
+        * cpu_present_map. We are pretty much ready for hot-swap CPUs.)
+        */
+       cpu_online_map = cpu_present_map;
+       mb();
+
        SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
 
        for(i=0;i<NR_CPUS;i++)
@@ -1116,7 +1205,7 @@ void __init smp_boot_cpus(void)
                if (i == boot_cpu_id)
                        continue;
 
-               if ((cpu_present_map & (1 << i))
+               if ((cpu_online_map & (1 << i))
                    && (max_cpus < 0 || max_cpus > cpucount+1))
                {
                        do_boot_cpu(i);
@@ -1126,9 +1215,9 @@ void __init smp_boot_cpus(void)
                 *      Make sure we unmap all failed CPUs
                 */
                
-               if (cpu_number_map[i] == -1 && (cpu_present_map & (1 << i))) {
-                       printk("CPU #%d not responding. Removing from cpu_present_map.\n",i);
-                       cpu_present_map &= ~(1 << i);
+               if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) {
+                       printk("CPU #%d not responding. Removing from cpu_online_map.\n",i);
+                       cpu_online_map &= ~(1 << i);
                 }
         }
 
@@ -1168,14 +1257,14 @@ void __init smp_boot_cpus(void)
        if (cpucount==0)
        {
                printk(KERN_ERR "Error: only one processor found.\n");
-               cpu_present_map=(1<<hard_smp_processor_id());
+               cpu_online_map = (1<<hard_smp_processor_id());
        }
        else
        {
                unsigned long bogosum=0;
                for(i=0;i<32;i++)
                {
-                       if (cpu_present_map&(1<<i))
+                       if (cpu_online_map&(1<<i))
                                bogosum+=cpu_data[i].loops_per_sec;
                }
                printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -1213,7 +1302,7 @@ smp_done:
  * Silly serialization to work around CPU bug in P5s.
  * We can safely turn it off on a 686.
  */
-#if defined(CONFIG_M686) & !defined(SMP_DEBUG)
+#ifdef CONFIG_GOOD_APIC
 # define FORCE_APIC_SERIALIZATION 0
 #else
 # define FORCE_APIC_SERIALIZATION 1
@@ -1386,44 +1475,51 @@ void smp_flush_tlb(void)
        unsigned long flags;
 
        /*
-        * The assignment is safe because it's volatile so the
-        * compiler cannot reorder it, because the i586 has
-        * strict memory ordering and because only the kernel
-        * lock holder may issue a tlb flush. If you break any
-        * one of those three change this to an atomic bus
-        * locked or.
+        * it's important that we do not generate any APIC traffic
+        * until the AP CPUs have booted up!
         */
+       if (cpu_online_map) {
+               /*
+                * The assignment is safe because it's volatile so the
+                * compiler cannot reorder it, because the i586 has
+                * strict memory ordering and because only the kernel
+                * lock holder may issue a tlb flush. If you break any
+                * one of those three change this to an atomic bus
+                * locked or.
+                */
 
-       smp_invalidate_needed = cpu_present_map;
+               smp_invalidate_needed = cpu_online_map;
 
-       /*
-        * Processors spinning on some lock with IRQs disabled
-        * will see this IRQ late. The smp_invalidate_needed
-        * map will ensure they don't do a spurious flush tlb
-        * or miss one.
-        */
+               /*
+                * Processors spinning on some lock with IRQs disabled
+                * will see this IRQ late. The smp_invalidate_needed
+                * map will ensure they don't do a spurious flush tlb
+                * or miss one.
+                */
        
-       __save_flags(flags);
-       __cli();
+               __save_flags(flags);
+               __cli();
 
-       send_IPI_allbutself(INVALIDATE_TLB_VECTOR);
+               send_IPI_allbutself(INVALIDATE_TLB_VECTOR);
 
-       /*
-        * Spin waiting for completion
-        */
-
-       stuck = 50000000;
-       while (smp_invalidate_needed) {
                /*
-                * Take care of "crossing" invalidates
+                * Spin waiting for completion
                 */
-               if (test_bit(cpu, &smp_invalidate_needed))
+
+               stuck = 50000000;
+               while (smp_invalidate_needed) {
+                       /*
+                        * Take care of "crossing" invalidates
+                        */
+                       if (test_bit(cpu, &smp_invalidate_needed))
                        clear_bit(cpu, &smp_invalidate_needed);
-               --stuck;
-               if (!stuck) {
-                       printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
-                       break;
+                       --stuck;
+                       if (!stuck) {
+                               printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
+                               break;
+                       }
                }
+               __restore_flags(flags);
        }
 
        /*
@@ -1431,7 +1527,6 @@ void smp_flush_tlb(void)
         */
        local_flush_tlb();
 
-       __restore_flags(flags);
 }
 
 
@@ -1584,14 +1679,24 @@ asmlinkage void smp_invalidate_interrupt(void)
        ack_APIC_irq();
 }
 
+static void stop_this_cpu (void)
+{
+       /*
+        * Remove this CPU:
+        */
+       clear_bit(smp_processor_id(), &cpu_online_map);
+
+       if (cpu_data[smp_processor_id()].hlt_works_ok)
+               for(;;) __asm__("hlt");
+       for (;;);
+}
+
 /*
  *     CPU halt call-back
  */
 asmlinkage void smp_stop_cpu_interrupt(void)
 {
-       if (cpu_data[smp_processor_id()].hlt_works_ok)
-               for(;;) __asm__("hlt");
-       for (;;) ;
+       stop_this_cpu();
 }
 
 void (*mtrr_hook) (void) = NULL;
index 2d89fcbe8d81eb78db8bc4e9bcbc2941fbaf6039..ae33e6fab6a4b0b0f3b7a9dd4227f93c159ac534 100644 (file)
@@ -118,10 +118,7 @@ static inline unsigned long do_fast_gettimeoffset(void)
 
 #define TICK_SIZE tick
 
-/*
- * Older CPU's don't have the rdtsc instruction..
- */
-#if CPU < 586
+#ifndef CONFIG_TSC
 
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
index 6697a991117bb425b6bc3d38dff050ca8c88d253..92ca8b9df6138e1228a04acb5af6a5f5b20060fd 100644 (file)
@@ -408,7 +408,7 @@ __initfunc(void test_wp_bit(void))
        if (boot_cpu_data.wp_works_ok < 0) {
                boot_cpu_data.wp_works_ok = 0;
                printk("No.\n");
-#ifndef CONFIG_M386
+#ifdef CONFIG_WP_WORKS_OK
                panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
 #endif
        } else
index b0c9ad966f43a59294165cb2ef9ffb7e4b744a48..efa2c69ee81895b045c9f175765defd5c4038041 100644 (file)
@@ -14,8 +14,8 @@ CONFIG_PMAC=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
+# CONFIG_SMP is not set
 
 #
 # General setup
@@ -165,6 +165,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -175,14 +176,16 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
@@ -192,6 +195,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -219,6 +223,7 @@ CONFIG_BMAC=y
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 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 is not set
@@ -226,7 +231,7 @@ CONFIG_NET_EISA=y
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
-CONFIG_DEC_ELCP=m
+# CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_LNE390 is not set
@@ -254,6 +259,7 @@ CONFIG_PPP=y
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
 
 #
 # Amateur Radio support
@@ -283,6 +289,7 @@ 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_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -312,9 +319,17 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
 # CONFIG_VIDEO_DEV is not set
-CONFIG_NVRAM=y
+
+#
+# Joystick support
+#
 # CONFIG_JOYSTICK is not set
 
 #
@@ -326,37 +341,47 @@ CONFIG_NVRAM=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+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_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
 # CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_NLS=y
 
 #
@@ -387,6 +412,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_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
index 4374b30d5c4133fb5d2dfe768cabca5d05820ca6..d7b791387e0110dc58c713a8a2eab8b0b193ca7c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.113 1998/12/02 18:41:00 cort Exp $
+ *  $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -532,9 +532,10 @@ HardwareInterrupt:
 
        stw     r3,(_CCR+4)(r21);
 #endif
-       addi    r3,r1,STACK_FRAME_OVERHEAD;
-       li      r20,MSR_KERNEL;
-       bl      transfer_to_handler;
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r20,MSR_KERNEL
+       li      r4,0
+       bl      transfer_to_handler
        .long   do_IRQ;
        .long   int_return
        
@@ -1199,12 +1200,6 @@ stack_ovf:
  * physical address of the hash table are known.  These definitions
  * of Hash_base and Hash_bits below are just an example.
  */
-/*
- * Note that the 603s won't come here, since the 603
- * loads tlb directly into the tlb from the linux tables, while
- * others (601, 604, etc.) call hash_page() to load entries from
- * the linux tables into the hash table.  -- Cort
- */    
 Hash_base = 0x180000
 Hash_bits = 12                         /* e.g. 256kB hash table */
 Hash_msk = (((1 << Hash_bits) - 1) * 64)
@@ -1219,11 +1214,19 @@ hash_page:
        lis     r2,hash_table_lock@h
        ori     r2,r2,hash_table_lock@l
        tophys(r2,r2,r6)
+       lis     r6,100000000@h
+       mtctr   r6
+       lwz     r0,PROCESSOR-TSS(r5)
+       or      r0,r0,r6
 10:    lwarx   r6,0,r2
-       stwcx.  r2,0,r2
-       bne-    10b
-       cmpi    0,0,r6,0
-       bne     10b
+       cmpi    0,r6,0
+       bne-    12f
+       stwcx.  r0,0,r2
+       beq+    11f
+12:    cmpw    r6,r0
+       bdnzf   2,10b
+       tw      31,31,31
+11:
 #endif
        /* Get PTE (linux-style) and check access */
        lwz     r5,PG_TABLES(r5)                
@@ -1271,6 +1274,9 @@ hash_page_patch_A:
        li      r2,8                    /* PTEs/group */
        bne     10f                     /* no PTE: go look for an empty slot */
        tlbie   r3                      /* invalidate TLB entry */
+#ifdef __SMP__
+       tlbsync
+#endif
 
        /* Search the primary PTEG for a PTE whose 1st word matches r5 */
        mtctr   r2
@@ -1315,7 +1321,6 @@ hash_page_patch_C:
        bdnzf   2,2b
        beq+    found_empty
 
-#if 1
        /*
         * Choose an arbitrary slot in the primary PTEG to overwrite.
         * Since both the primary and secondary PTEGs are full, and we
@@ -1331,26 +1336,6 @@ hash_page_patch_C:
        andi.   r2,r2,0x38
        stw     r2,next_slot@l(0)
        add     r3,r4,r2
-#else
-       /* now, allow 2nd hash as well as 1st */
-       lwz     r2,next_slot@l(0)
-       addi    r2,r2,8
-       andi.   r2,r2,0x78
-       stw     r2,next_slot@l(0)
-       cmpi    0,0,r2,0x38             /* if it's the 2nd hash */
-       bgt     second_evict
-first_evict:
-       xori    r5,r5,0x40              /* clear H bit again */
-       add     r3,r4,r2
-       b       11f
-second_evict:
-       .globl  hash_page_patch_D
-hash_page_patch_D:     
-       xoris   r3,r4,Hash_msk>>16      /* compute secondary hash */
-       xori    r3,r3,0xffc0
-       subi    r2,r2,0x40
-       addi    r3,r3,r2
-#endif
 11:            
        /* update counter of evicted pages */
        lis     r2,htab_evicts@h
@@ -1390,6 +1375,13 @@ found_slot:
        addi    r3,r3,1
        stw     r3,0(r2)
 
+#ifdef __SMP__
+       lis     r2,hash_table_lock@ha
+       tophys(r2,r2,r6)
+       li      r0,0
+       stw     r0,hash_table_lock@l(r2)
+#endif
+
        /* Return from the exception */
        lwz     r3,_CCR(r21)
        lwz     r4,_LINK(r21)
@@ -1397,13 +1389,6 @@ found_slot:
        mtcrf   0xff,r3
        mtlr    r4
        mtctr   r5
-#ifdef __SMP__
-       lis     r2,hash_table_lock@h
-       ori     r2,r2,hash_table_lock@l
-       tophys(r2,r2,r6)
-       li      r6,0
-       stw     r6,0(r2)
-#endif         
        REST_GPR(0, r21)
        REST_2GPRS(1, r21)
        REST_4GPRS(3, r21)
@@ -1418,11 +1403,10 @@ found_slot:
        
 hash_page_out:
 #ifdef __SMP__
-       lis     r2,hash_table_lock@h
-       ori     r2,r2,hash_table_lock@l
+       lis     r2,hash_table_lock@ha
        tophys(r2,r2,r6)
-       li      r6,0
-       stw     r6,0(r2)
+       li      r0,0
+       stw     r0,hash_table_lock@l(r2)
 #endif         
        blr
 next_slot:
@@ -1741,6 +1725,9 @@ start_here:
 2:
        SYNC                    /* Force all PTE updates to finish */
        tlbia                   /* Clear all TLB entries */
+#ifdef __SMP__
+       tlbsync
+#endif
 #ifndef CONFIG_8xx
        mtspr   SDR1,r6
        li      r0,16           /* load up segment register values */
@@ -2012,16 +1999,13 @@ _GLOBAL(_switch)
 
 /* FALL THROUGH into int_return */
 #ifdef __SMP__
-       /* drop scheduler_lock since we weren't called by schedule() */
+       /* call schedule_tail if this is the first time for a child process */
        lwz     r5,TSS_SMP_FORK_RET(r4)
        cmpi    0,r5,0
        beq+    int_return
        li      r3,0
-       lis     r5,scheduler_lock@ha
        stw     r3,TSS_SMP_FORK_RET(r4)
-       stw     r3,scheduler_lock@l+4(r5)       /* owner_pc */
-       stw     r3,scheduler_lock@l+8(r5)       /* owner_cpu */
-       stw     r3,scheduler_lock@l(r5)         /* lock */
+       bl      schedule_tail
 #endif /* __SMP__ */
 
 /*
@@ -2121,6 +2105,7 @@ _GLOBAL(fake_interrupt)
        li      r0,0x0fac
        stw     r0,TRAP(r1)
        addi    r3,r1,STACK_FRAME_OVERHEAD
+       li      r4,1
        bl      do_IRQ
        addi    r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
        lwz     r0,4(r1)
@@ -2227,15 +2212,6 @@ _GLOBAL(flush_page_to_ram)
  */
 #ifndef CONFIG_8xx     
 _GLOBAL(flush_hash_segments)
-#ifdef __SMP__
-       lis     r9,hash_table_lock@h
-       ori     r9,r9,hash_table_lock@l
-10:    lwarx   r6,0,r9
-       stwcx.  r9,0,r9
-       bne-    10b
-       cmpi    0,0,r6,0
-       bne     10b
-#endif
 #ifdef NO_RELOAD_HTAB
 /*
  * Bitmask of PVR numbers of 603-like chips,
@@ -2247,8 +2223,31 @@ _GLOBAL(flush_hash_segments)
        rlwinm  r0,r0,16,27,31
        lis     r9,PVR_603_LIKE@h
        rlwnm.  r0,r9,r0,0,0
-       bne     99f
+       beq+    99f
+       tlbia
+       isync
+       blr
+99:
 #endif /* NO_RELOAD_HTAB */
+#ifdef __SMP__
+       /* Note - we had better not do anything which could generate
+          a hash table miss while we have the hash table locked,
+          or we'll get a deadlock.  -paulus */
+       mfmsr   r10
+       sync
+       rlwinm  r0,r10,0,17,15  /* clear bit 16 (MSR_EE) */
+       mtmsr   r0
+       SYNC
+       lis     r9,hash_table_lock@h
+       ori     r9,r9,hash_table_lock@l
+       lwz     r8,PROCESSOR(r2)
+       oris    r8,r8,8
+10:    lwarx   r6,0,r9
+       cmpi    0,r6,0
+       bne-    10b
+       stwcx.  r8,0,r9
+       bne-    10b
+#endif
        rlwinm  r3,r3,7,1,24            /* put VSID lower limit in position */
        oris    r3,r3,0x8000            /* set V bit */
        rlwinm  r4,r4,7,1,24            /* put VSID upper limit in position */
@@ -2270,14 +2269,16 @@ _GLOBAL(flush_hash_segments)
        stw     r0,0(r5)                /* invalidate entry */
 2:     bdnz    1b                      /* continue with loop */
        sync
-99:    tlbia
+       tlbia
        isync
 #ifdef __SMP__
-       lis     r3,hash_table_lock@h
-       ori     r3,r3,hash_table_lock@l
-       li      r6,0
-       stw     r6,0(r3)
-#endif         
+       tlbsync
+       lis     r3,hash_table_lock@ha
+       li      r0,0
+       stw     r0,hash_table_lock@l(r3)
+       mtmsr   r10
+       SYNC
+#endif
        blr
 
 /*
@@ -2286,22 +2287,36 @@ _GLOBAL(flush_hash_segments)
  * flush_hash_page(unsigned context, unsigned long va)
  */
 _GLOBAL(flush_hash_page)
-#ifdef __SMP__
-       lis     r9,hash_table_lock@h
-       ori     r9,r9,hash_table_lock@l
-10:    lwarx   r6,0,r9
-       stwcx.  r9,0,r9
-       bne-    10b
-       cmpi    0,0,r6,0
-       bne     10b
-#endif
 #ifdef NO_RELOAD_HTAB
        mfspr   r0,PVR
        rlwinm  r0,r0,16,27,31
        lis     r9,PVR_603_LIKE@h
        rlwnm.  r0,r9,r0,0,0
-       bne     99f
+       beq+    99f
+       tlbie   r4                      /* in hw tlb too */
+       isync
+       blr
+99:
 #endif /* NO_RELOAD_HTAB */            
+#ifdef __SMP__
+       /* Note - we had better not do anything which could generate
+          a hash table miss while we have the hash table locked,
+          or we'll get a deadlock.  -paulus */
+       mfmsr   r10
+       sync
+       rlwinm  r0,r10,0,17,15          /* clear bit 16 (MSR_EE) */
+       mtmsr   r0
+       SYNC
+       lis     r9,hash_table_lock@h
+       ori     r9,r9,hash_table_lock@l
+       lwz     r8,PROCESSOR(r2)
+       oris    r8,r8,9
+10:    lwarx   r6,0,r9
+       cmpi    0,r6,0
+       bne-    10b
+       stwcx.  r8,0,r9
+       bne-    10b
+#endif
        rlwinm  r3,r3,11,1,20           /* put context into vsid */
        rlwimi  r3,r4,11,21,24          /* put top 4 bits of va into vsid */
        oris    r3,r3,0x8000            /* set V (valid) bit */
@@ -2334,16 +2349,19 @@ _GLOBAL(flush_hash_page)
 3:     li      r0,0
        stw     r0,0(r7)                /* invalidate entry */
 4:     sync
-99:    tlbie   r4                      /* in hw tlb too */
+       tlbie   r4                      /* in hw tlb too */
        isync
 #ifdef __SMP__
+       tlbsync
        lis     r3,hash_table_lock@h
-       ori     r3,r3,hash_table_lock@l
-       li      r6,0
-       stw     r6,0(r3)
-#endif         
+       li      r0,0
+       stw     r0,hash_table_lock@l(r3)
+       mtmsr   r10
+       SYNC
+#endif
        blr
 #endif /* CONFIG_8xx */
+
 /*
  * This routine is just here to keep GCC happy - sigh...
  */    
index b6c338946fc3cca359738f0fcfe90ed27e653236..af163699bbbceedb123ee32046c10c4caef65b83 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $
+ * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -41,26 +41,25 @@ unsigned long powersave_nap = 0;
 
 int idled(void *unused)
 {
-       int ret = -EPERM;
-
+       /* endless loop with no priority at all */
+       current->priority = 0;
+       current->counter = -100;
        for (;;)
        {
                __sti();
                
-               /* endless loop with no priority at all */
-               current->priority = 0;
-               current->counter = 0;
-
                check_pgt_cache();
 
                if ( !current->need_resched && zero_paged_on ) zero_paged();
                if ( !current->need_resched && htab_reclaim_on ) htab_reclaim();
                if ( !current->need_resched ) power_save();
-               run_task_queue(&tq_scheduler);
-               schedule();
+
+#ifdef __SMP__
+               if (current->need_resched)
+#endif
+                       schedule();
        }
-       ret = 0;
-       return ret;
+       return 0;
 }
 
 #ifdef __SMP__
index ccc5b466cb97fb7828dff7311f6d0bbe2541a948..f4a7c714389c1dfc1a340df53019cfdb182690fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.90 1998/12/10 02:39:46 cort Exp $
+ * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -457,7 +457,6 @@ static inline void wait_on_bh(void)
 }
 
 
-#define MAXCOUNT 100000000
 static inline void wait_on_irq(int cpu)
 {
        int count = MAXCOUNT;
@@ -510,7 +509,7 @@ static inline void wait_on_irq(int cpu)
 void synchronize_bh(void)
 {
        if (atomic_read(&global_bh_count) && !in_interrupt())
-                       wait_on_bh();
+               wait_on_bh();
 }
 
 
@@ -532,6 +531,8 @@ void synchronize_irq(void)
 
 static inline void get_irqlock(int cpu)
 {
+       unsigned int loops = MAXCOUNT;
+
        if (test_and_set_bit(0,&global_irq_lock)) {
                /* do we already hold the lock? */
                if ((unsigned char) cpu == global_irq_holder)
@@ -539,12 +540,17 @@ static inline void get_irqlock(int cpu)
                /* Uhhuh.. Somebody else got it. Wait.. */
                do {
                        do {
-                               
+                               if (loops-- == 0) {
+                                       printk("get_irqlock(%d) waiting, global_irq_holder=%d\n", cpu, global_irq_holder);
+#ifdef CONFIG_XMON
+                                       xmon(0);
+#endif
+                               }
                        } while (test_bit(0,&global_irq_lock));
                } while (test_and_set_bit(0,&global_irq_lock));         
        }
        /* 
-        * We also to make sure that nobody else is running
+        * We also need to make sure that nobody else is running
         * in an interrupt context. 
         */
        wait_on_irq(cpu);
@@ -640,7 +646,7 @@ void __global_restore_flags(unsigned long flags)
 
 #endif /* __SMP__ */
 
-asmlinkage void do_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
 {
        int irq;
        unsigned long bits;
@@ -659,9 +665,14 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
 #ifdef __SMP__
        if ( cpu != 0 )
        {
-               if (!atomic_read(&n_lost_interrupts))
+               if (!isfake)
                {
                        extern void smp_message_recv(void);
+#ifdef CONFIG_XMON
+                       static int xmon_2nd;
+                       if (xmon_2nd)
+                               xmon(regs);
+#endif
                        smp_message_recv();
                        goto out;
                }
@@ -669,6 +680,25 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
                   mess with the controller from the second cpu -- Cort */
                goto out;
        }
+
+       {
+               unsigned int loops = MAXCOUNT;
+               while (test_bit(0, &global_irq_lock)) {
+                       if (smp_processor_id() == global_irq_holder) {
+                               printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                               xmon(0);
+#endif
+                               break;
+                       }
+                       if (loops-- == 0) {
+                               printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                               xmon(0);
+#endif
+                       }
+               }
+       }
 #endif /* __SMP__ */                   
 
        switch ( _machine )
index 383015cf636705e11a2b0df39c95fd7b0ceeda34..e4589b1e041d73ab054c9313876a6afd6b893964 100644 (file)
@@ -610,16 +610,6 @@ _GLOBAL(__kernel_thread)
        bnelr                   /* return if parent */
        mtlr    r4              /* fn addr in lr */
        mr      r3,r5           /* load arg and call fn */
-#if 0/*def __SMP__*/
-       /* drop scheduler_lock since schedule() called us */
-       lis     r4,scheduler_lock@ha
-       li      r5,0
-       stw     r5,scheduler_lock@l+4(r4)       /* owner_pc */
-       stw     r5,scheduler_lock@l+8(r4)       /* owner_cpu */
-       stw     r5,scheduler_lock@l(r4)
-       sync
-       isync
-#endif /* __SMP__ */
        blrl
        li      r0,__NR_exit    /* exit after child exits */
         li     r3,0
index 54db1f38161abefa3183adc2860ab2a7f4abe508..9720bacfa000d06f5585e444692a17be2c00a453 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
 #include <asm/feature.h>
+#include <asm/spinlock.h>
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -32,7 +33,7 @@
 extern void transfer_to_handler(void);
 extern void int_return(void);
 extern void syscall_trace(void);
-extern void do_IRQ(struct pt_regs *regs);
+extern void do_IRQ(struct pt_regs *regs, int isfake);
 extern void MachineCheckException(struct pt_regs *regs);
 extern void AlignmentException(struct pt_regs *regs);
 extern void ProgramCheckException(struct pt_regs *regs);
@@ -156,6 +157,19 @@ EXPORT_SYMBOL(_get_PVR);
 EXPORT_SYMBOL(giveup_fpu);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
+#ifdef __SMP__
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(spin_trylock);
+EXPORT_SYMBOL(_read_lock);
+EXPORT_SYMBOL(_read_unlock);
+EXPORT_SYMBOL(_write_lock);
+EXPORT_SYMBOL(_write_unlock);
+#endif
 
 #ifndef CONFIG_MACH_SPECIFIC
 EXPORT_SYMBOL(_machine);
index 11d72054a0d1c9bbe40eef42b41131b7244620d1..0b047e60cfa3bc598e72894d509e9eca45913f69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.68 1998/11/15 19:59:02 cort Exp $
+ * $Id: process.c,v 1.69 1998/12/28 10:28:49 paulus Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -182,13 +182,6 @@ switch_to(struct task_struct *prev, struct task_struct *new)
        if ( prev->tss.regs->msr & MSR_FP )
                smp_giveup_fpu(prev);
 
-       /* be noisy about processor changes for debugging -- Cort */
-       if ( (new->last_processor != NO_PROC_ID) &&
-            (new->last_processor != new->processor) )
-               printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
-                      new->last_processor,new->processor,
-                      new->comm,new->pid);
-       
        prev->last_processor = prev->processor;
        current_set[smp_processor_id()] = new;
 #endif /* __SMP__ */
index 62b2b03af5529a4e9912b93f2c2258ea16131c12..e2c6b13a0b226eb2dfc2a5d8c0a4b093f89e240e 100644 (file)
@@ -362,7 +362,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_PEEKDATA: {
                        unsigned long tmp;
 
+                       down(&child->mm->mmap_sem);
                        ret = read_long(child, addr, &tmp);
+                       up(&child->mm->mmap_sem);
                        if (ret < 0)
                                goto out;
                        ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
@@ -410,7 +412,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
       /* If I and D space are separate, this will have to be fixed. */
                case PTRACE_POKETEXT: /* write the word at location addr. */
                case PTRACE_POKEDATA:
+                       down(&child->mm->mmap_sem);
                        ret = write_long(child,addr,data);
+                       up(&child->mm->mmap_sem);
                        goto out;
 
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
index e6dca0e806d5c7c8de68d8761074a1ef781d94ea..ba505e133eb64a460aad7f2d2f51fe953312e26b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.38 1998/12/02 21:23:49 cort Exp $
+ * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
  *
  * Smp support for ppc.
  *
@@ -43,6 +43,7 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 int first_cpu_booted = 0;
+cycles_t cacheflush_time;
 
 /* all cpu mappings are 1-1 -- Cort */
 int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
@@ -144,7 +145,14 @@ void smp_message_recv(void)
 
 void smp_send_reschedule(int cpu)
 {
-       smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
+       /* This is only used if `cpu' is running an idle task,
+          so it will reschedule itself anyway... */
+       /*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+}
+
+void smp_send_stop(void)
+{
+       smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
 spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
@@ -185,11 +193,12 @@ void __init smp_boot_cpus(void)
        extern void __secondary_start(void);
        int i;
        struct task_struct *p;
-       
+       unsigned long a;
+
         printk("Entering SMP Mode...\n");
        
        first_cpu_booted = 1;
-       dcbf(&first_cpu_booted);
+       /*dcbf(&first_cpu_booted);*/
 
        for (i = 0; i < NR_CPUS; i++) {
                prof_counter[i] = 1;
@@ -200,7 +209,13 @@ void __init smp_boot_cpus(void)
         smp_store_cpu_info(0);
         active_kernel_processor = 0;
        current->processor = 0;
-       
+
+       /*
+        * XXX very rough, assumes 20 bus cycles to read a cache line,
+        * timebase increments every 4 bus cycles, 32kB L1 data cache.
+        */
+       cacheflush_time = 5 * 1024;
+
        if ( _machine != _MACH_Pmac )
        {
                printk("SMP not supported on this machine.\n");
@@ -213,10 +228,16 @@ void __init smp_boot_cpus(void)
        if ( !p )
                panic("No idle task for secondary processor\n");
        p->processor = 1;
+       p->has_cpu = 1;
        current_set[1] = p;
 
        /* need to flush here since secondary bat's aren't setup */
-       dcbf((void *)&current_set[1]);
+       /* XXX ??? */
+       for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+               asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+       asm volatile("sync");
+
+       /*dcbf((void *)&current_set[1]);*/
        /* setup entry point of secondary processor */
        *(volatile unsigned long *)(0xf2800000) =
                (unsigned long)__secondary_start-KERNELBASE;
@@ -238,7 +259,7 @@ void __init smp_boot_cpus(void)
        if(cpu_callin_map[1]) {
                printk("Processor %d found.\n", smp_num_cpus);
                smp_num_cpus++;
-#if 0 /* this sync's the decr's, but we don't want this now -- Cort */
+#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
                set_dec(decrementer_count);
 #endif
        } else {
@@ -287,6 +308,7 @@ void __init smp_callin(void)
        while(!smp_commenced)
                barrier();
        __sti();
+       printk("SMP %d: smp_callin done\n", current->processor);
 }
 
 void __init smp_setup(char *str, int *ints)
index 0842f52fbe038e3390b71fb6785615e0fe63f39b..7a0065d0ae581a049e2270ac780c12617264d907 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: time.c,v 1.38 1998/11/16 15:56:15 cort Exp $
+ * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -78,6 +78,26 @@ void timer_interrupt(struct pt_regs * regs)
        unsigned dcache_locked = unlock_dcache();
        
        hardirq_enter(cpu);
+#ifdef __SMP__
+       {
+               unsigned int loops = 100000000;
+               while (test_bit(0, &global_irq_lock)) {
+                       if (smp_processor_id() == global_irq_holder) {
+                               printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                               xmon(0);
+#endif
+                               break;
+                       }
+                       if (loops-- == 0) {
+                               printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                               xmon(0);
+#endif
+                       }
+               }
+       }
+#endif /* __SMP__ */                   
        
        while ((dval = get_dec()) < 0) {
                /*
@@ -150,12 +170,15 @@ void do_gettimeofday(struct timeval *tv)
        save_flags(flags);
        cli();
        *tv = xtime;
+       /* XXX we don't seem to have the decrementers synced properly yet */
+#ifndef __SMP__
        tv->tv_usec += (decrementer_count - get_dec())
            * count_period_num / count_period_den;
        if (tv->tv_usec >= 1000000) {
                tv->tv_usec -= 1000000;
                tv->tv_sec++;
        }
+#endif
        restore_flags(flags);
 }
 
index 073e7076cc13ab9ac822f4783cb1eae10de00d18..2d2a2d8c04f80f8b69bae498dc27123f58671967 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: locks.c,v 1.20 1998/10/08 01:17:32 cort Exp $
+ * $Id: locks.c,v 1.21 1998/12/28 10:28:53 paulus Exp $
  *
  * Locks for smp ppc 
  * 
@@ -18,7 +18,7 @@
 #define DEBUG_LOCKS 1
 
 #undef INIT_STUCK
-#define INIT_STUCK 0xffffffff
+#define INIT_STUCK 200000000 /*0xffffffff*/
 
 void _spin_lock(spinlock_t *lock)
 {
@@ -76,9 +76,9 @@ void _spin_unlock(spinlock_t *lp)
                      lp->owner_pc,lp->lock);
 #endif /* DEBUG_LOCKS */
        lp->owner_pc = lp->owner_cpu = 0;
-       eieio();
-       lp->lock = 0;
-       eieio();
+       eieio();        /* actually I believe eieio only orders */
+       lp->lock = 0;   /* non-cacheable accesses (on 604 at least) */
+       eieio();        /*  - paulus. */
 }
                
 /*
index b0c9ad966f43a59294165cb2ef9ffb7e4b744a48..efa2c69ee81895b045c9f175765defd5c4038041 100644 (file)
@@ -14,8 +14,8 @@ CONFIG_PMAC=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
+# CONFIG_SMP is not set
 
 #
 # General setup
@@ -165,6 +165,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -175,14 +176,16 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
@@ -192,6 +195,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -219,6 +223,7 @@ CONFIG_BMAC=y
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 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 is not set
@@ -226,7 +231,7 @@ CONFIG_NET_EISA=y
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
-CONFIG_DEC_ELCP=m
+# CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
 # CONFIG_LNE390 is not set
@@ -254,6 +259,7 @@ CONFIG_PPP=y
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
 
 #
 # Amateur Radio support
@@ -283,6 +289,7 @@ 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_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -312,9 +319,17 @@ CONFIG_UNIX98_PTY_COUNT=256
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
 # CONFIG_VIDEO_DEV is not set
-CONFIG_NVRAM=y
+
+#
+# Joystick support
+#
 # CONFIG_JOYSTICK is not set
 
 #
@@ -326,37 +341,47 @@ CONFIG_NVRAM=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+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_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
 # CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_NLS=y
 
 #
@@ -387,6 +412,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_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
index f5c61bd6e3b8d817bc2c5f40118a3c357fffaa04..e322d138b01869bcecc703e0fef5187fb1e91379 100644 (file)
@@ -64,6 +64,9 @@ SECTIONS
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
   . = ALIGN(4096);
   __init_begin = .;
   .text.init : { *(.text.init) }
index 40e23fa0eec9c9074fb6d933d0c3f13487178c12..ed8fe6a25e64f2d3ba752dc58d0871908f5d2540 100644 (file)
@@ -592,7 +592,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        pt_error_return(regs, EINVAL);
                        goto out;
                }
+               down(&child->mm->mmap_sem);
                res = read_long(child, addr, &tmp);
+               up(&child->mm->mmap_sem);
                if (res < 0) {
                        pt_error_return(regs, -res);
                        goto out;
@@ -619,8 +621,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        pt_error_return(regs, EINVAL);
                        goto out;
                }
+               down(&child->mm->mmap_sem);
                vma = find_extend_vma(child, addr);
                res = write_long(child, addr, data);
+               up(&child->mm->mmap_sem);
                if(res < 0)
                        pt_error_return(regs, -res);
                else
@@ -761,7 +765,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        goto out;
                }
                while(len) {
+                       down(&child->mm->mmap_sem);
                        res = read_byte(child, src, &tmp);
+                       up(&child->mm->mmap_sem);
                        if(res < 0) {
                                pt_error_return(regs, -res);
                                goto out;
@@ -788,7 +794,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                        unsigned long tmp;
 
                        __get_user(tmp, src);
+                       down(&child->mm->mmap_sem);
                        res = write_byte(child, dest, tmp);
+                       up(&child->mm->mmap_sem);
                        if(res < 0) {
                                pt_error_return(regs, -res);
                                goto out;
index a4920df2ab9eaf15f0cfcb239e13d83f326b0afe..de2ca9c88c6abfd5bfe1f3ffc4fabccf814b363f 100644 (file)
@@ -69,7 +69,7 @@ else
       bool '     QDI QD6580 support' CONFIG_BLK_DEV_QD6580
       bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
+        if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then
         bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
         fi
       fi
index 9d6c4fb00edba190eb3d82ae1599ced9df8e0476..b1433046f2d348343da218679091c8ff8158f25f 100644 (file)
@@ -425,7 +425,7 @@ int acsi_wait_for_IRQ( unsigned timeout )
 {
        if (INT_LEVEL < 6) {
                unsigned long maxjif;
-               for( maxjif = jiffies + timeout; jiffies < maxjif; )
+               for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
                        if (!(mfp.par_dt_reg & 0x20)) return( 1 );
        }
        else {
@@ -442,7 +442,7 @@ int acsi_wait_for_noIRQ( unsigned timeout )
 {
        if (INT_LEVEL < 6) {
                unsigned long maxjif;
-               for( maxjif = jiffies + timeout; jiffies < maxjif; )
+               for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); )
                        if (mfp.par_dt_reg & 0x20) return( 1 );
        }
        else {
index 66121340f1bf107753ff5f074ab48d2f18e8e465..1f5d31b8897b187752bcf83b0161834afa5526d1 100644 (file)
@@ -101,17 +101,8 @@ not be guaranteed. There are several ways to assure this:
                cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5;   \
        } while(0)
 
-#define        START_TIMER(to)                                                 \
-    do {                                                                               \
-        del_timer( &slm_timer );                               \
-        slm_timer.expires = jiffies + (to);                    \
-        add_timer( &slm_timer );                               \
-       } while(0)
-
-#define        STOP_TIMER()                                                    \
-    do {                                                                               \
-        del_timer( &slm_timer );                               \
-       } while(0)
+#define        START_TIMER(to) mod_timer(&slm_timer, jiffies + (to))
+#define        STOP_TIMER()    del_timer(&slm_timer)
 
 
 static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 };
index 5c55700a7cd877e51044bec7285a4092f17f517d..4f22bd609f1d8201e5aeff92a4950c46ee3e2213 100644 (file)
@@ -1838,7 +1838,7 @@ __initfunc(static int fd_test_drive_present( int drive ))
        FDC_WRITE (FDCREG_TRACK, 0xff00);
        FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );
 
-       for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; jiffies < timeout; ) {
+       for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; time_before(jiffies, timeout); ) {
                if (!(mfp.par_dt_reg & 0x20))
                        break;
        }
index 2062f5cdf31f83e78afd2ae14680493efd346aee..222a008cf45282798d5a836b22ebf8010783d9ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-disk.c     Version 1.04  Jan   7, 1998
+ *  linux/drivers/block/ide-disk.c     Version 1.08  Dec   10, 1998
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -7,6 +7,7 @@
 /*
  *  Maintained by Mark Lord  <mlord@pobox.com>
  *            and Gadi Oxman <gadio@netvision.net.il>
+ *            and Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
  *
  * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
  *
  * Version 1.05                add capacity support for ATA3 >= 8GB
  * Version 1.06                get boot-up messages to show full cyl count
  * Version 1.07                disable door-locking if it fails
- * Version 1.07a       fixed mult_count enables
+ * Version 1.08                fixed CHS/LBA translations for ATA4 > 8GB,
+ *                     process of adding new ATA4 compliance.
+ *                     fixed problems in allowing fdisk to see
+ *                     the entire disk.
  */
 
-#define IDEDISK_VERSION        "1.07"
+#define IDEDISK_VERSION        "1.08"
 
 #undef REALLY_SLOW_IO          /* most systems can safely undef this */
 
@@ -87,15 +91,28 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
        unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
        unsigned long _10_percent = chs_sects / 10;
 
-       /* very large drives (8GB+) may lie about the number of cylinders */
-       if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+       /*
+        * very large drives (8GB+) may lie about the number of cylinders
+        * This is a split test for drives 8 Gig and Bigger only.
+        */
+       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 */
+       }
+       /*
+        * very large drives (8GB+) may lie about the number of cylinders
+        * This is a split test for drives less than 8 Gig only.
+        */
+       if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) &&
+           (id->heads == 16) && (id->sectors == 63)) {
                id->cyls = lba_sects / (16 * 63); /* correct cyls */
                return 1;       /* lba_capacity is our only option */
        }
        /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
-       if ((lba_sects - chs_sects) < _10_percent)
+       if ((lba_sects - chs_sects) < _10_percent) {
                return 1;       /* lba_capacity is good */
-
+       }
        /* some drives have the word order reversed */
        lba_sects = (lba_sects << 16) | (lba_sects >> 16);
        if ((lba_sects - chs_sects) < _10_percent) {
@@ -487,13 +504,13 @@ static void idedisk_pre_reset (ide_drive_t *drive)
                drive->special.b.set_multmode = 1;
 }
 
+#ifdef CONFIG_PROC_FS
+
 static int smart_enable(ide_drive_t *drive)
 {
        return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
 }
 
-#ifdef CONFIG_PROC_FS
-
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
        (void) smart_enable(drive);
@@ -603,7 +620,7 @@ static void idedisk_add_settings(ide_drive_t *drive)
        int major = HWIF(drive)->major;
        int minor = drive->select.b.unit << PARTN_BITS;
 
-       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_SHORT,     0,      1023,                           1,      1,      &drive->bios_cyl,               NULL);
+       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_SHORT,     0,      65535,                          1,      1,      &drive->bios_cyl,               NULL);
        ide_add_setting(drive,  "bios_head",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &drive->bios_head,              NULL);
        ide_add_setting(drive,  "bios_sect",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      63,                             1,      1,      &drive->bios_sect,              NULL);
        ide_add_setting(drive,  "bswap",                SETTING_READ,                                   -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,      1,      &drive->bswap,                  NULL);
@@ -676,9 +693,8 @@ static void idedisk_setup (ide_drive_t *drive)
                drive->sect    = drive->bios_sect = id->sectors;
        }
        /* Handle logical geometry translation by the drive */
-       if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
-        && (id->cur_heads <= 16) && id->cur_sectors)
-       {
+       if ((id->field_valid & 1) && id->cur_cyls &&
+           id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
                /*
                 * Extract the physical drive geometry for our use.
                 * Note that we purposely do *not* update the bios info.
@@ -703,27 +719,49 @@ static void idedisk_setup (ide_drive_t *drive)
                }
        }
        /* Use physical geometry if what we have still makes no sense */
-       if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
-               drive->cyl  = id->cyls;
-               drive->head = id->heads;
-               drive->sect = id->sectors;
+       if ((!drive->head || drive->head > 16) &&
+           id->heads && id->heads <= 16) {
+               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;
        }
 
        /* calculate drive capacity, and select LBA if possible */
-       (void) idedisk_capacity (drive);
+       capacity = idedisk_capacity (drive);
 
-       /* Correct the number of cyls if the bios value is too small */
-       if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
-               if (drive->cyl > drive->bios_cyl)
-                       drive->bios_cyl = drive->cyl;
+       /*
+        * if possible, give fdisk access to more of the drive,
+        * by correcting bios_cyls:
+        */
+       if ((capacity >= (id->cyls * id->heads * id->sectors)) &&
+           (!drive->forced_geom)) {
+               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 0  /* done instead for entire identify block in arch/ide.h stuff */
        /* fix byte-ordering of buffer size field */
        id->buf_size = le16_to_cpu(id->buf_size);
 #endif
        printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
-        drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2,
-        drive->bios_cyl, drive->bios_head, drive->bios_sect);
+                       drive->name, id->model,
+                       capacity/2048L, id->buf_size/2,
+                       drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
        if (drive->using_dma) {
                if ((id->field_valid & 4) &&
                    (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
@@ -735,12 +773,34 @@ 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 */
+               drive->mult_req = INITIAL_MULT_COUNT;
+               if (drive->mult_req > id->max_multsect)
+                       drive->mult_req = id->max_multsect;
+               if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+                       drive->special.b.set_multmode = 1;
+#else
                id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
                id->multsect_valid = id->multsect ? 1 : 0;
                drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
                drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#endif
        }
        drive->no_io_32bit = id->dword_io ? 1 : 0;
 }
index 058d93b8588f7e8f669a092dad0316e57f14c564..cbde66a81b0ca162ec77d18d516ba45c8801aa8c 100644 (file)
@@ -68,8 +68,9 @@
  *       SIIG's UltraIDE Pro CN-2449
  * TTI   HPT343 Chipset "Modified SCSI Class" but reports as an
  *       unknown storage device.
- * NEW check_drive_lists(ide_drive_t *drive, int good_bad)
+ * NEW  check_drive_lists(ide_drive_t *drive, int good_bad)
  */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -91,9 +92,8 @@
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
                                 "CONNER CTMA 4000",
+                                "CONNER CTT8000-A",
                                 "ST34342A",    /* for Sun Ultra */
-                                "WDC AC2340F", /* DMA mode1 */
-                                "WDC AC2340H", /* DMA mode1 */
                                 NULL};
 
 /*
@@ -101,7 +101,10 @@ const char *good_dma_drives[] = {"Micropolis 2112A",
  * of drives which supposedly support (U)DMA but which are
  * known to corrupt data with this interface under Linux.
  */
-const char *bad_dma_drives[] = {"WDC AC22100H",
+const char *bad_dma_drives[] = {"WDC AC11000H",
+                               "WDC AC22100H",
+                               "WDC AC32500H",
+                               "WDC AC33100H",
                                NULL};
 
 /*
@@ -331,8 +334,8 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                        return 0;
                case ide_dma_end: /* returns 1 on error, 0 otherwise */
                        drive->waiting_for_dma = 0;
-                       dma_stat = inb(dma_base+2);
-                       outb(inb(dma_base)&~1, dma_base);               /* stop DMA */
+                       outb(inb(dma_base)&~1, dma_base);       /* stop DMA */
+                       dma_stat = inb(dma_base+2);             /* get DMA status */
                        outb(dma_stat|6, dma_base+2);   /* clear the INTR & ERROR bits */
                        return (dma_stat & 7) != 4;     /* verify good DMA status */
                case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
index f99fe7d417ab91a363dfb20bc5a18d0d64fc7a78..de1431dac1a719511a588a12973c33401ec9612b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-tape.c      Version 1.13            Jan   2, 1998
+ * linux/drivers/block/ide-tape.c      Version 1.14            Dec  30, 1998
  *
  * Copyright (C) 1995 - 1998 Gadi Oxman <gadio@netvision.net.il>
  *
  *                        number of tape blocks.
  *                       Add support for INTERRUPT DRQ devices.
  * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
+ * Ver 1.14  Dec 30 99   Partial fixes for the Sony/AIWA tape drives.
+ *                       Replace cli()/sti() with hwgroup spinlocks.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
  */
 #define IDETAPE_FIFO_THRESHOLD                 2
 
+/*
+ *     Some tape drives require a long irq timeout
+ */
+#define IDETAPE_WAIT_CMD               60
+
 /*
  *     DSC timings.
  */
@@ -1432,8 +1439,7 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
 #if IDETAPE_DEBUG_LOG
        printk (KERN_INFO "Reached idetape_add_stage_tail\n");
 #endif /* IDETAPE_DEBUG_LOG */
-       save_flags (flags);     /* all CPUs (overkill?) */
-       cli();                  /* all CPUs (overkill?) */
+       spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
        stage->next=NULL;
        if (tape->last_stage != NULL)
                tape->last_stage->next=stage;
@@ -1444,7 +1450,7 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
                tape->next_stage=tape->last_stage;
        tape->nr_stages++;
        tape->nr_pending_stages++;
-       restore_flags (flags);  /* all CPUs (overkill?) */
+       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 }
 
 /*
@@ -1756,6 +1762,8 @@ static void idetape_pc_intr (ide_drive_t *drive)
 
                ide__sti();     /* local CPU only */
 
+               if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+                       status.b.check = 0;
                if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {    /* Error detected */
 #if IDETAPE_DEBUG_LOG
                        printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
@@ -1811,7 +1819,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
                        if (temp > pc->buffer_size) {
                                printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
                                idetape_discard_data (drive,bcount.all);
-                               ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);
+                               ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);
                                return;
                        }
 #if IDETAPE_DEBUG_LOG
@@ -1833,7 +1841,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
        pc->actually_transferred+=bcount.all;                                   /* Update the current position */
        pc->current_position+=bcount.all;
 
-       ide_set_handler (drive,&idetape_pc_intr,WAIT_CMD);              /* And set the interrupt handler again */
+       ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD);              /* And set the interrupt handler again */
 }
 
 /*
@@ -1884,18 +1892,29 @@ static void idetape_transfer_pc(ide_drive_t *drive)
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
        idetape_ireason_reg_t ireason;
+       int retries = 100;
 
        if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
                printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
                return;
        }
        ireason.all=IN_BYTE (IDE_IREASON_REG);
+       while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+               printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+               udelay(100);
+               ireason.all = IN_BYTE(IDE_IREASON_REG);
+               if (retries == 0) {
+                       printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+                       ireason.b.cod = 1;
+                       ireason.b.io = 0;
+               }
+       }
        if (!ireason.b.cod || ireason.b.io) {
                printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
                ide_do_reset (drive);
                return;
        }
-       ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD);     /* Set the interrupt routine */
+       ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD);     /* Set the interrupt routine */
        atapi_output_bytes (drive,pc->c,12);                    /* Send the actual packet */
 }
 
@@ -1961,7 +1980,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
        }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
        if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-               ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD);
+               ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD);
                OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
        } else {
                OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -2313,7 +2332,7 @@ static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
  *     The caller should ensure that the request will not be serviced
  *     before we install the semaphore (usually by disabling interrupts).
  */
-static void idetape_wait_for_request (struct request *rq)
+static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
 {
        struct semaphore sem = MUTEX_LOCKED;
 
@@ -2324,7 +2343,9 @@ static void idetape_wait_for_request (struct request *rq)
        }
 #endif /* IDETAPE_DEBUG_BUGS */
        rq->sem = &sem;
-       down (&sem);
+       spin_unlock(&HWGROUP(drive)->spinlock);
+       down(&sem);
+       spin_lock_irq(&HWGROUP(drive)->spinlock);
 }
 
 /*
@@ -2398,11 +2419,10 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
                 */
                return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh));
        }
-       save_flags (flags);     /* all CPUs (overkill?) */
-       cli();                  /* all CPUs (overkill?) */
+       spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
        if (tape->active_stage == tape->first_stage)
-               idetape_wait_for_request (tape->active_data_request);
-       restore_flags (flags);  /* all CPUs (overkill?) */
+               idetape_wait_for_request(drive, tape->active_data_request);
+       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 
        rq_ptr = &tape->first_stage->rq;
        bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -2451,13 +2471,12 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
         *      Pay special attention to possible race conditions.
         */
        while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
-               save_flags (flags);     /* all CPUs (overkill?) */
-               cli();                  /* all CPUs (overkill?) */
+               spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
                if (idetape_pipeline_active (tape)) {
-                       idetape_wait_for_request (tape->active_data_request);
-                       restore_flags (flags);  /* all CPUs (overkill?) */
+                       idetape_wait_for_request(drive, tape->active_data_request);
+                       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
                } else {
-                       restore_flags (flags);  /* all CPUs (overkill?) */
+                       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
                        idetape_insert_pipeline_into_queue (drive);
                        if (idetape_pipeline_active (tape))
                                continue;
@@ -2513,13 +2532,12 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive)
        
        if (tape->first_stage == NULL)
                return;
-               
-       save_flags (flags);     /* all CPUs (overkill?) */
-       cli();                  /* all CPUs (overkill?) */
+
+       spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
        tape->next_stage = NULL;
        if (idetape_pipeline_active (tape))
-               idetape_wait_for_request (tape->active_data_request);
-       restore_flags (flags);  /* all CPUs (overkill?) */
+               idetape_wait_for_request(drive, tape->active_data_request);
+       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 
        while (tape->first_stage != NULL)
                idetape_remove_stage_head (drive);
@@ -2539,8 +2557,7 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive)
        if (!idetape_pipeline_active (tape))
                idetape_insert_pipeline_into_queue (drive);
 
-       save_flags (flags);     /* all CPUs (overkill?) */
-       cli();                  /* all CPUs (overkill?) */
+       spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
        if (!idetape_pipeline_active (tape))
                goto abort;
 #if IDETAPE_DEBUG_BUGS
@@ -2548,9 +2565,9 @@ static void idetape_wait_for_pipeline (ide_drive_t *drive)
                printk ("ide-tape: tape->last_stage == NULL\n");
        else
 #endif /* IDETAPE_DEBUG_BUGS */
-       idetape_wait_for_request (&tape->last_stage->rq);
+       idetape_wait_for_request(drive, &tape->last_stage->rq);
 abort:
-       restore_flags (flags);  /* all CPUs (overkill?) */
+       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 }
 
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
@@ -2795,11 +2812,10 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
                         *      Wait until the first read-ahead request
                         *      is serviced.
                         */
-                       save_flags (flags);     /* all CPUs (overkill?) */
-                       cli();                  /* all CPUs (overkill?) */
+                       spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
                        if (tape->active_stage == tape->first_stage)
-                               idetape_wait_for_request (tape->active_data_request);
-                       restore_flags (flags);  /* all CPUs (overkill?) */
+                               idetape_wait_for_request(drive, tape->active_data_request);
+                       spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
 
                        if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
                                count++;
@@ -3457,7 +3473,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
                return;
        }
        header = (idetape_mode_parameter_header_t *) pc.buffer;
-       capabilities = (idetape_capabilities_page_t *) (header + 1);
+       capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
        capabilities->max_speed = ntohs (capabilities->max_speed);
        capabilities->ctl = ntohs (capabilities->ctl);
index 23a554398d05d4fd2eac1b2d74a1f323414350b0..f4e8138cb169c3153b359b476decce4281c8282e 100644 (file)
@@ -2275,6 +2275,12 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
  *                             and quite likely to cause trouble with
  *                             older/odd IDE drives.
  *
+ * "hdx=slow"          : insert a huge pause after each access to the data
+ *                             port. Should be used only as a last resort.
+ *
+ * "hdx=swapdata"      : when the drive is a disk, byte swap all data
+ * "hdx=bswap"         : same as above..........
+ *
  * "idebus=xx"         : inform IDE driver of VESA/PCI bus speed in MHz,
  *                             where "xx" is between 20 and 66 inclusive,
  *                             used when tuning chipset PIO modes.
@@ -2333,12 +2339,16 @@ __initfunc(void ide_setup (char *s))
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
                const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
                                "serialize", "autotune", "noautotune",
-                               "slow", "swapdata", NULL};
+                               "slow", "swapdata", "bswap", NULL};
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
                hwif = &ide_hwifs[hw];
                drive = &hwif->drives[unit];
+               if (strncmp(s + 4, "ide-", 4) == 0) {
+                       strncpy(drive->driver_req, s + 4, 9);
+                       goto done;
+               }
                switch (match_parm(&s[3], hd_words, vals, 3)) {
                        case -1: /* "none" */
                                drive->nobios = 1;  /* drop into "noprobe" */
@@ -2366,7 +2376,8 @@ __initfunc(void ide_setup (char *s))
                        case -8: /* "slow" */
                                drive->slow = 1;
                                goto done;
-                       case -9: /* swapdata */
+                       case -9: /* swapdata or bswap */
+                       case -10:
                                drive->bswap = 1;
                                goto done;
                        case 3: /* cyl,head,sect */
@@ -2567,16 +2578,44 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
        const byte *heads = head_vals;
        unsigned long tracks;
 
-       if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
+       drive = get_info_ptr(i_rdev);
+       if (!drive)
                return 0;
 
-       if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
+       if (drive->forced_geom) {
+               /* bombs otherwise /axboe */
+               if (drive == NULL) 
+                       return 0;
+               /*
+                * Update the current 3D drive values.
+                */
+               drive->id->cur_cyls     = drive->bios_cyl;
+               drive->id->cur_heads    = drive->bios_head;
+               drive->id->cur_sectors  = drive->bios_sect;
+               return 0;
+       }
+
+       if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
+               /*
+                * Update the current 3D drive values.
+                */
+               drive->id->cur_cyls     = drive->bios_cyl;
+               drive->id->cur_heads    = drive->bios_head;
+               drive->id->cur_sectors  = drive->bios_sect;
                return 0;               /* we already have a translation */
+       }
 
        printk("%s ", msg);
 
-       if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63))
+       if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
+               /*
+                * Update the current 3D drive values.
+                */
+               drive->id->cur_cyls     = drive->bios_cyl;
+               drive->id->cur_heads    = drive->bios_head;
+               drive->id->cur_sectors  = drive->bios_sect;
                return 0;               /* small disk: no translation needed */
+       }
 
        if (drive->id) {
                drive->cyl  = drive->id->cyls;
@@ -2614,6 +2653,12 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
        }
        drive->part[0].nr_sects = current_capacity(drive);
        printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+       /*
+        * Update the current 3D drive values.
+        */
+       drive->id->cur_cyls    = drive->bios_cyl;
+       drive->id->cur_heads   = drive->bios_head;
+       drive->id->cur_sectors = drive->bios_sect;
        return 1;
 }
 
@@ -2703,7 +2748,11 @@ __initfunc(void ide_init_builtin_drivers (void))
        (void) idefloppy_init();
 #endif /* CONFIG_BLK_DEV_IDEFLOPPY */
 #ifdef CONFIG_BLK_DEV_IDESCSI
+ #ifdef CONFIG_SCSI
        (void) idescsi_init();
+ #else
+    #warning ide scsi-emulation selected but no SCSI-subsystem in kernel
+ #endif
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 }
 
index 095bc51b15d8c67e743f4b3b1099b29f30df20f6..f9c7bbbeb1dff435f2ff13134953a2962214f88b 100644 (file)
@@ -438,6 +438,8 @@ read_proc_t proc_ide_read_geometry;
        *start = page + off;            \
        return len;                     \
 }
+#else
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
 /*
index b5b13b9cbb08919c1b5bf35b8003297feadb0953..e032da579f5775d8d4cf620aa640f42d8090e585 100644 (file)
@@ -92,13 +92,13 @@ int pdc4030_cmd(ide_drive_t *drive, byte cmd)
        timeout = HZ * 10;
        timeout += jiffies;
        do {
-               if(jiffies > timeout) {
+               if(time_after(jiffies, timeout)) {
                        return 2; /* device timed out */
                }
                /* This is out of delay_10ms() */
                /* Delays at least 10ms to give interface a chance */
                timer = jiffies + (HZ + 99)/100 + 1;
-               while (timer > jiffies);
+               while (time_after(timer, jiffies));
                status_val = IN_BYTE(IDE_SECTOR_REG);
        } while (status_val != 0x50 && status_val != 0x70);
 
@@ -257,7 +257,7 @@ static void promise_write_pollfunc (ide_drive_t *drive)
        struct request *rq;
 
         if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-            if (jiffies < hwgroup->poll_timeout) {
+            if (time_before(jiffies, hwgroup->poll_timeout)) {
                 ide_set_handler (drive, &promise_write_pollfunc, 1);
                 return; /* continue polling... */
             }
@@ -335,7 +335,7 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq)
                if(IN_BYTE(IDE_SELECT_REG) & 0x01)
                    return;
                udelay(1);
-           } while (jiffies < timeout);
+           } while (time_before(jiffies, timeout));
            printk("%s: reading: No DRQ and not waiting - Odd!\n",
                   drive->name);
            return;
index ed00c865967b0cae9cd80abc0e2b73b8fc333d72..aab3f377ddad40ccbf370267455cba388e3ffe8d 100644 (file)
@@ -1029,7 +1029,7 @@ static void csi_m(int currcons)
                                  */
                                translate = set_translate(charset == 0
                                                ? G0_charset
-                                               : G1_charset);
+                                               : G1_charset,currcons);
                                disp_ctrl = 0;
                                toggle_meta = 0;
                                break;
@@ -1037,7 +1037,7 @@ static void csi_m(int currcons)
                                  * Select first alternate font, lets
                                  * chars < 32 be displayed as ROM chars.
                                  */
-                               translate = set_translate(IBMPC_MAP);
+                               translate = set_translate(IBMPC_MAP,currcons);
                                disp_ctrl = 1;
                                toggle_meta = 0;
                                break;
@@ -1045,7 +1045,7 @@ static void csi_m(int currcons)
                                  * Select second alternate font, toggle
                                  * high bit before displaying as ROM char.
                                  */
-                               translate = set_translate(IBMPC_MAP);
+                               translate = set_translate(IBMPC_MAP,currcons);
                                disp_ctrl = 1;
                                toggle_meta = 1;
                                break;
@@ -1328,7 +1328,7 @@ static void restore_cur(int currcons)
        color           = s_color;
        G0_charset      = saved_G0;
        G1_charset      = saved_G1;
-       translate       = set_translate(charset ? G1_charset : G0_charset);
+       translate       = set_translate(charset ? G1_charset : G0_charset,currcons);
        update_attr(currcons);
        need_wrap = 0;
 }
@@ -1343,7 +1343,7 @@ static void reset_terminal(int currcons, int do_clear)
        bottom          = video_num_lines;
        vc_state        = ESnormal;
        ques            = 0;
-       translate       = set_translate(LAT1_MAP);
+       translate       = set_translate(LAT1_MAP,currcons);
        G0_charset      = LAT1_MAP;
        G1_charset      = GRAF_MAP;
        charset         = 0;
@@ -1426,12 +1426,12 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
                return;
        case 14:
                charset = 1;
-               translate = set_translate(G1_charset);
+               translate = set_translate(G1_charset,currcons);
                disp_ctrl = 1;
                return;
        case 15:
                charset = 0;
-               translate = set_translate(G0_charset);
+               translate = set_translate(G0_charset,currcons);
                disp_ctrl = 0;
                return;
        case 24: case 26:
@@ -1738,7 +1738,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
                else if (c == 'K')
                        G0_charset = USER_MAP;
                if (charset == 0)
-                       translate = set_translate(G0_charset);
+                       translate = set_translate(G0_charset,currcons);
                vc_state = ESnormal;
                return;
        case ESsetG1:
@@ -1751,7 +1751,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
                else if (c == 'K')
                        G1_charset = USER_MAP;
                if (charset == 1)
-                       translate = set_translate(G1_charset);
+                       translate = set_translate(G1_charset,currcons);
                vc_state = ESnormal;
                return;
        default:
index 95bb6f20429ddc087f8bab8e0273afdcc6e54c5d..7e97e1fe7ea2eaa4ac557e784fc6cfa458411756 100644 (file)
@@ -7,6 +7,8 @@
  * aeb, 950210
  *
  * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
+ *
+ * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
  */
 
 #include <linux/kd.h>
@@ -167,7 +169,7 @@ static unsigned short translations[][256] = {
 
 #define MAX_GLYPH 512          /* Max possible glyph value */
 
-static int inv_translate;
+static int inv_translate[MAX_NR_CONSOLES];
 
 struct uni_pagedir {
        u16             **uni_pgdir[32];
@@ -204,9 +206,9 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
        }
 }
 
-unsigned short *set_translate(int m)
+unsigned short *set_translate(int m,int currcons)
 {
-       inv_translate = m;
+       inv_translate[currcons] = m;
        return translations[m];
 }
 
@@ -220,14 +222,13 @@ unsigned short *set_translate(int m)
 unsigned char inverse_translate(struct vc_data *conp, int glyph)
 {
        struct uni_pagedir *p;
-       
        if (glyph < 0 || glyph >= MAX_GLYPH)
                return 0;
        else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
-                !p->inverse_translations[inv_translate])
+                !p->inverse_translations[inv_translate[conp->vc_num]])
                return glyph;
        else
-               return p->inverse_translations[inv_translate][glyph];
+               return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
 }
 
 static void update_user_maps(void)
index 62e31d9c96d8e5be4d49cd37e7b6daecfd579f94..a349a4eb6ffdcc7ef309cdf5be6a28782a3bd1cd 100644 (file)
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define        Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.1.8 $$Date: 1998/11/13 12:46:20 $";
+"$Revision: 2.2.1.9 $$Date: 1998/12/30 18:18:30 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -31,6 +31,10 @@ static char rcsid[] =
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.1.9  1998/12/30 18:18:30 ivan
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in 
+ * order to make PLX9050-based boards work with certain motherboards.
+ *
  * Revision 2.2.1.8  1998/11/13 12:46:20 ivan
  * cy_close function now resets (correctly) the tty->closing flag;
  * JIFFIES_DIFF macro fixed.
@@ -4545,7 +4549,6 @@ cy_detect_pci(void))
 
   struct pci_dev       *pdev = NULL;
   unsigned char                cyy_rev_id;
-  unsigned long         pci_intr_ctrl;
   unsigned char         cy_pci_irq = 0;
   uclong                cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan, plx_ver;
@@ -4587,7 +4590,7 @@ cy_detect_pci(void))
             printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
                (ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
 #endif
-                cy_pci_addr1  &= PCI_BASE_ADDRESS_IO_MASK;
+                cy_pci_addr0  &= PCI_BASE_ADDRESS_MEM_MASK;
                 cy_pci_addr2  &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #if defined(__alpha__)
@@ -4604,7 +4607,8 @@ cy_detect_pci(void))
                    continue;
                 }
 #else
-                    cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin);
+                   cy_pci_addr0  = (ulong) ioremap(cy_pci_addr0, CyPCI_Yctl);
+                   cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin);
 #endif
 
 #ifdef CY_PCI_DEBUG
@@ -4652,7 +4656,7 @@ cy_detect_pci(void))
 
                 /* set cy_card */
                 cy_card[j].base_addr = (ulong)cy_pci_addr2;
-                cy_card[j].ctl_addr = 0;
+                cy_card[j].ctl_addr = (ulong)cy_pci_addr0;
                 cy_card[j].irq = (int) cy_pci_irq;
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
@@ -4664,20 +4668,16 @@ cy_detect_pci(void))
                switch (plx_ver) {
                    case PLX_9050:
 
-                   outw(inw(cy_pci_addr1+0x4c)|0x0040,cy_pci_addr1+0x4c);
-                   pci_intr_ctrl = (unsigned long)
-                               (inw(cy_pci_addr1+0x4c)
-                               | inw(cy_pci_addr1+0x4e)<<16);
+                   cy_writew(cy_pci_addr0+0x4c, 
+                       cy_readw(cy_pci_addr0+0x4c)|0x0040);
                    break;
 
                    case PLX_9060:
                    case PLX_9080:
                    default: /* Old boards, use PLX_9060 */
 
-                   outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
-                   pci_intr_ctrl = (unsigned long)
-                               (inw(cy_pci_addr1+0x68)
-                               | inw(cy_pci_addr1+0x6a)<<16);
+                   cy_writew(cy_pci_addr0+0x68, 
+                       cy_readw(cy_pci_addr0+0x68)|0x0900);
                    break;
                }
 
index f4224bd557737b63e704c7ad97a9fb1d34573bde..6f0521df613dca789603d6be31fed0bcf9910d17 100644 (file)
@@ -286,7 +286,8 @@ int pc_init(void);
 
 #ifdef ENABLE_PCI
 static int init_PCI(int);
-static int get_PCI_configuration(char, char, unsigned int *, unsigned int *,
+static int get_PCI_configuration(unsigned char, unsigned char, 
+                                            unsigned int *, unsigned int *,
                                              unsigned int *, unsigned int *,
                                              unsigned int *, unsigned int *);
 #endif /* ENABLE_PCI */
@@ -4037,7 +4038,7 @@ void epca_setup(char *str, int *ints)
 #ifdef ENABLE_PCI
 /* --------------------- Begin get_PCI_configuration  ---------------------- */
 
-int get_PCI_configuration(char bus, char device_fn,
+int get_PCI_configuration(unsigned char bus, unsigned char device_fn,
                           unsigned int *base_addr0, unsigned int *base_addr1,
                           unsigned int *base_addr2, unsigned int *base_addr3,
                           unsigned int *base_addr4, unsigned int *base_addr5)
index dcc2508080c8e7a86e89d037fbc87e7016e442d2..03799dbc05a4f93774aac309ea184b1e7c1f9585 100644 (file)
@@ -423,9 +423,7 @@ Another simple bugfix version.
 
 This release is a simple bugfix version.
 
-- Linux/SMP: ftape *should* work, if you remember to add the symbol __SMP__
-  to the Makefile (you know what I'm talking about, if you're playing with
-  Linux/SMP :).
+- Linux/SMP: ftape *should* work.
 - FC-10/20: Only accepts IRQs 3-7, or 9.  If IRQ 9, properly tell the card
   to use IRQ 2.  Thanks to Greg Crider (gcrider@iclnet.org) for finding and
   locating this bug and testing the patch.
index 9fb9269f83394fd4fb467c02083eace1cb6b64b2..6890df0fa29237de17f348ec1c86befe0b7704a3 100644 (file)
@@ -1348,21 +1348,12 @@ int fdc_grab_irq_and_dma(void)
        if (fdc.hook == &do_ftape) {
                /*  Get fast interrupt handler.
                 */
-#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
                if (request_irq(fdc.irq, ftape_interrupt,
                                SA_INTERRUPT, "ft", ftape_id)) {
                        TRACE_ABORT(-EIO, ft_t_bug,
                                    "Unable to grab IRQ%d for ftape driver",
                                    fdc.irq);
                }
-#else
-               if (request_irq(fdc.irq, ftape_interrupt, SA_INTERRUPT,
-                               ftape_id)) {
-                       TRACE_ABORT(-EIO, ft_t_bug,
-                                   "Unable to grab IRQ%d for ftape driver",
-                                   fdc.irq);
-               }
-#endif
                if (request_dma(fdc.dma, ftape_id)) {
 #if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
                        free_irq(fdc.irq, ftape_id);
@@ -1373,7 +1364,6 @@ int fdc_grab_irq_and_dma(void)
                              "Unable to grab DMA%d for ftape driver",
                              fdc.dma);
                }
-               enable_irq(fdc.irq);
        }
        if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
                /* Using same dma channel or irq as standard fdc, need
@@ -1395,12 +1385,7 @@ int fdc_release_irq_and_dma(void)
        if (fdc.hook == &do_ftape) {
                disable_dma(fdc.dma);   /* just in case... */
                free_dma(fdc.dma);
-               disable_irq(fdc.irq);
-#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
                free_irq(fdc.irq, ftape_id);
-#else
-                free_irq(fdc.irq);
-#endif
        }
        if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
                /* Using same dma channel as standard fdc, need to
index a23281f3e06203ed7c22a0b390ed128924104992..9d2799adb9201176c5669c6ef6d560e36729a6ab 100644 (file)
@@ -1,5 +1,5 @@
 comment 'Misc. hamradio protocols'
-tristate 'Shortwave radio modem driver' CONFIG_HFMODEM
+dep_tristate 'Shortwave radio modem driver' CONFIG_HFMODEM $CONFIG_PARPORT
 if [ "$CONFIG_HFMODEM" != "n" ]; then
   bool '   HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC
   bool '   HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS
index f52f452b50714c21b6b6df1a50f7ec6750c55905..a1a6d93a1a3307cec24dc28f27db64dae99fb4f7 100644 (file)
@@ -2311,7 +2311,7 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
                if (signal_pending(current))
                        break;
                stli_delay(2);
-               if (jiffies >= tend)
+               if (time_after_eq(jiffies, tend))
                        break;
        }
 }
index 7da0fa51240860b97011b5e6efa1bd4c2acd7a15..7764997b580fecfc30642f35fae1e1a635948453 100644 (file)
@@ -228,7 +228,7 @@ extern inline void rc_long_delay(unsigned long delay)
 {
        unsigned long i;
        
-       for (i = jiffies + delay; i > jiffies; ) ;
+       for (i = jiffies + delay; time_after(i,jiffies); ) ;
 }
 
 /* Reset and setup CD180 chip */
@@ -1172,8 +1172,8 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
                timeout = jiffies+HZ;
                while(port->IER & IER_TXEMPTY)  {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->timeout);
-                       if (jiffies > timeout)
+                       schedule_timeout(port->timeout);
+                       if (time_after(jiffies, timeout))
                                break;
                }
        }
index 72d1f6276011b52fa1722ad9911eae85fa2becb2..57bae3ebf0f6f7e72f003083cf5014b6b55a2c75 100644 (file)
@@ -353,7 +353,7 @@ extern inline void sx_long_delay(unsigned long delay)
 {
        unsigned long i;
        
-       for (i = jiffies + delay; i > jiffies; ) ;
+       for (i = jiffies + delay; time_after(i, jiffies); ) ;
 }
 
 
@@ -1073,7 +1073,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
        /* Set baud rate for port */
        tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
                CD186x_TPC/2) / CD186x_TPC);
-       if ((tmp < 0x10) && (again < jiffies)) { 
+       if ((tmp < 0x10) && time_before(again, jiffies)) { 
                again = jiffies + HZ * 60;
                /* Page 48 of version 2.0 of the CL-CD1865 databook */
                if (tmp >= 12) {
@@ -1551,8 +1551,8 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
                timeout = jiffies+HZ;
                while(port->IER & IER_TXEMPTY) {
                        current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(port->timeout);
-                       if (jiffies > timeout) {
+                       schedule_timeout(port->timeout);
+                       if (time_after(jiffies, timeout)) {
                                printk (KERN_INFO "Timeout waiting for close\n");
                                break;
                        }
index 0b2f495b18496a71d6b2c173e3d52f17c5d70925..dd27a4e26a79783c21299ac7fe684492a4f3a2f0 100644 (file)
@@ -1697,7 +1697,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
                if (signal_pending(current))
                        break;
                stl_delay(2);
-               if (jiffies >= tend)
+               if (time_after_eq(jiffies, tend))
                        break;
        }
 }
index 3787c735fbe1116773284aad9271c7a82fdbb54e..08e3b78b8eba65f42cb994f417fdffbe88fb004d 100644 (file)
@@ -38,7 +38,9 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
     bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
     bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
     if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+      if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
         bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+      fi
     fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
index 074fd01c24320c8d43737a77cb921ad19d8ae15c..73f6f30feb9a59e5f1a4419b651739e0ff2562fa 100644 (file)
@@ -1035,13 +1035,6 @@ endif
 #
 # HIPPI adapters
 #
-ifeq ($(CONFIG_CERN_HIPPI),y)
-L_OBJS += cern_hippi.o
-else
-  ifeq ($(CONFIG_CERN_HIPPI),m)
-  M_OBJS += cern_hippi.o
-  endif
-endif
 
 ifeq ($(CONFIG_ROADRUNNER),y)
 L_OBJS += rrunner.o
index c2e26819bcaf98e317d264648a7b20a6eb5ae021..f9be725cd473dc2311e40ae1b0ecd8ef24ae9b0f 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 1998 Randy Gobbel.
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -59,7 +60,6 @@ struct bmac_data {
        int rx_fill;
        int rx_empty;
        struct sk_buff *tx_bufs[N_TX_RING];
-       char *tx_double[N_TX_RING]; /* yuck--double buffering */
        int tx_fill;
        int tx_empty;
        unsigned char tx_fullup;
@@ -297,7 +297,7 @@ bmac_mif_read(struct device *dev, unsigned int addr)
        val = bmac_mif_readbits(dev, 17);
        bmwrite(dev, MIFCSR, 4);
        MIFDELAY;
-       printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val);
+       /* printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val); */
        return val;
 }
 
@@ -438,9 +438,11 @@ bmac_init_chip(struct device *dev)
                        bmac_mif_write(dev, 4, 0xa1);
                        bmac_mif_write(dev, 0, 0x1200);
                }
+#if 0
                /* XXX debugging */
                bmac_mif_read(dev, 0);
                bmac_mif_read(dev, 4);
+#endif
        }
        bmac_init_registers(dev);
        return 1;
@@ -488,23 +490,15 @@ static inline void bmac_set_timeout(struct device *dev)
 }
 
 static void
-bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp,
-                  char *doubleBuf)
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
 {
-       void *vaddr, *page_break;
+       void *vaddr;
        unsigned long baddr;
        unsigned long len;
 
        len = skb->len;
        vaddr = skb->data;
        baddr = virt_to_bus(vaddr);
-       page_break = round_page(vaddr);
-       if (trunc_page(vaddr) != trunc_page(vaddr+len) &&
-           (unsigned long)round_page(baddr) != virt_to_bus(page_break))  {
-               baddr = virt_to_bus(doubleBuf);
-               XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len));
-       } else
-               flush_page_to_ram((unsigned long)vaddr);
 
        dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
 }
@@ -530,17 +524,8 @@ bitrev(unsigned char b)
 static int
 bmac_init_tx_ring(struct bmac_data *bp)
 {
-       int i;
        volatile struct dbdma_regs *td = bp->tx_dma;
-       char *addr;
-
-       if (!bp->tx_allocated) {
-               /* zero out tx cmds, alloc space for double buffering */
-               addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA);
-               if (addr == NULL) return 0;
-               for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr;
-               bp->tx_allocated = 1;
-       }
+
        memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
 
        bp->tx_empty = 0;
@@ -615,7 +600,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev)
 
        dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
 
-       bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]);
+       bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]);
 
        bp->tx_bufs[bp->tx_fill] = skb;
        bp->tx_fill = i;
@@ -1177,6 +1162,8 @@ static int bmac_reset_and_enable(struct device *dev, int enable)
 {
        struct bmac_data *bp = dev->priv;
        unsigned long flags;
+       struct sk_buff *skb;
+       unsigned char *data;
 
        save_flags(flags); cli();
        bp->reset_and_enabled = 0;
@@ -1187,16 +1174,17 @@ static int bmac_reset_and_enable(struct device *dev, int enable)
                bmac_start_chip(dev);
                bmwrite(dev, INTDISABLE, EnableNormal);
                bp->reset_and_enabled = 1;
-               /*      { */
-               /*          unsigned char random_packet[100]; */
-               /*          unsigned int i; */
-               /*          struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */
-               /*          unsigned char *data = skb_put(skb, sizeof(random_packet)); */
-               /* XXDEBUG(("transmitting random packet\n")); */
-               /*          for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */
-               /*          bmac_transmit_packet(skb, dev); */
-               /* XXDEBUG(("done transmitting random packet\n")); */
-               /*      } */
+
+               /*
+                * It seems that the bmac can't receive until it's transmitted
+                * a packet.  So we give it a dummy packet to transmit.
+                */
+               skb = dev_alloc_skb(ETHERMINPACKET);
+               data = skb_put(skb, ETHERMINPACKET);
+               memset(data, 0, ETHERMINPACKET);
+               memcpy(data, dev->dev_addr, 6);
+               memcpy(data+6, dev->dev_addr, 6);
+               bmac_transmit_packet(skb, dev);
        }
        restore_flags(flags);
        return 1;
@@ -1241,8 +1229,13 @@ bmac_probe(struct device *dev)
                dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
                if (dev->priv == 0) return -ENOMEM;
        }
+
+#ifdef MODULE
+       bmac_devs = dev;
+#endif
     
-       dev->base_addr = bmacs->addrs[0].address;
+       dev->base_addr = (unsigned long)
+               ioremap(bmacs->addrs[0].address, bmacs->addrs[0].size);
        dev->irq = bmacs->intrs[0].line;
 
        bmwrite(dev, INTDISABLE, DisableAll);
@@ -1257,7 +1250,7 @@ bmac_probe(struct device *dev)
                }
        }
     
-       printk(KERN_INFO "%s: BMAC at", dev->name);
+       printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
        rev = addr[0] == 0 && addr[1] == 0xA0;
        for (j = 0; j < 6; ++j) {
                dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
@@ -1280,9 +1273,11 @@ bmac_probe(struct device *dev)
     
        bp = (struct bmac_data *) dev->priv;
        memset(bp, 0, sizeof(struct bmac_data));
-       bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address;
+       bp->tx_dma = (volatile struct dbdma_regs *)
+               ioremap(bmacs->addrs[1].address, bmacs->addrs[1].size);
        bp->tx_dma_intr = bmacs->intrs[1].line;
-       bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address;
+       bp->rx_dma = (volatile struct dbdma_regs *)
+               ioremap(bmacs->addrs[2].address, bmacs->addrs[2].size);
        bp->rx_dma_intr = bmacs->intrs[2].line;
     
        bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
@@ -1370,8 +1365,6 @@ static int bmac_close(struct device *dev)
                }
        }
        bp->rx_allocated = 0;
-       XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */
-       if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]);
        XXDEBUG(("bmac: free tx bufs\n"));
        for (i = 0; i<N_TX_RING; i++) {
                if (bp->tx_bufs[i] != NULL) {
@@ -1379,7 +1372,6 @@ static int bmac_close(struct device *dev)
                        bp->tx_bufs[i] = NULL;
                }
        }
-       bp->tx_allocated = 0;
        bp->reset_and_enabled = 0;
        XXDEBUG(("bmac: all bufs freed\n"));
 
@@ -1539,3 +1531,32 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
   
        return len;
 }
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
+
+int init_module(void)
+{
+    int res;
+   
+    if(bmac_devs != NULL)
+        return -EBUSY;
+    res = bmac_probe(NULL);
+    return res;
+}
+void cleanup_module(void)
+{
+    struct bmac_data *bp = (struct bmac_data *) bmac_devs->priv;
+    unregister_netdev(bmac_devs);
+
+    free_irq(bmac_devs->irq, bmac_misc_intr);
+    free_irq(bp->tx_dma_intr, bmac_txdma_intr);
+    free_irq(bp->rx_dma_intr, bmac_rxdma_intr);
+
+    kfree(bmac_devs);
+    bmac_devs = NULL;
+}
+
+#endif
index bbc86f2a2c14aae208ca47d418c088c5ffcbcf86..0ce0e89f90990c4897b45987c2add20f36baad34 100644 (file)
                           alignment for Alpha's and avoid their unaligned
                           access traps. This flag is merely for log messages:
                           should do something more definitive though...
+      0.543  30-Dec-98    Add SMP spin locking.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.542 1998/9/15 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.543 1998/12/30 davies@maniac.ultranet.com\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -443,6 +444,7 @@ static const char *version = "de4x5.c:V0.542 1998/9/15 davies@maniac.ultranet.co
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
+#include <asm/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -508,11 +510,11 @@ struct sia_phy {
 ** recognised by this driver.
 */
 static struct phy_table phy_info[] = {
-    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},       /* National TX */
-    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},       /* Broadcom T4 */
-    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},       /* SEEQ T4     */
-    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}},       /* Cypress T4  */
-    {0, 0x7810     , 1, {0x05, 0x0380, 0x0380}}    /* Level One?  */
+    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},       /* National TX      */
+    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},       /* Broadcom T4      */
+    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},       /* SEEQ T4          */
+    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}},       /* Cypress T4       */
+    {0, 0x7810     , 1, {0x14, 0x0800, 0x0800}}    /* Level One LTX970 */
 };
 
 /*
@@ -759,7 +761,8 @@ struct de4x5_private {
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
     char frame[64];                         /* Min sized packet for loopback*/
-    struct net_device_stats stats;           /* Public stats                 */
+    spinlock_t lock;                        /* Adapter specific spinlock    */
+    struct net_device_stats stats;          /* Public stats                 */
     struct {
        u_int bins[DE4X5_PKT_STAT_SZ];      /* Private stats counters       */
        u_int unicast;
@@ -1192,6 +1195,7 @@ de4x5_hw_init(struct device *dev, u_long iobase))
        lp->timeout = -1;
        lp->useSROM = useSROM;
        memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
+       lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
        de4x5_parse_params(dev);
 
        /*
@@ -1345,7 +1349,7 @@ de4x5_open(struct device *dev)
     ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
-    
+    lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
     lp->state = OPEN;
     de4x5_dbg_open(dev);
     
@@ -1497,6 +1501,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int status = 0;
+    u_long flags = 0;
 
     test_and_set_bit(0, (void*)&dev->tbusy);     /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
@@ -1508,9 +1513,9 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     ** interrupts are lost by delayed descriptor status updates relative to
     ** the irq assertion, especially with a busy PCI bus.
     */
-    cli();
+    spin_lock_irqsave(&lp->lock, flags);
     de4x5_tx(dev);
-    sti();
+    spin_unlock_irqrestore(&lp->lock, flags);
 
     /* Test if cache is already locked - requeue skb if so */
     if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) 
@@ -1534,7 +1539,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
        }
 
        while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
-           cli();
+           spin_lock_irqsave(&lp->lock, flags);
            test_and_set_bit(0, (void*)&dev->tbusy);
            load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
            lp->stats.tx_bytes += skb->len;
@@ -1547,7 +1552,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
                dev->tbusy = 0;         /* Another pkt may be queued */
            }
            skb = de4x5_get_cache(dev);
-           sti();
+           spin_unlock_irqrestore(&lp->lock, flags);
        }
        if (skb) de4x5_putb_cache(dev, skb);
     }
@@ -1581,6 +1586,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        return;
     }
     lp = (struct de4x5_private *)dev->priv;
+    spin_lock(&lp->lock);
     iobase = dev->base_addr;
        
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
@@ -1628,6 +1634,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
     lp->interrupt = UNMASK_INTERRUPTS;
     ENABLE_IRQs;
+    spin_unlock(&lp->lock);
     
     return;
 }
@@ -2069,7 +2076,9 @@ eisa_probe(struct device *dev, u_long ioaddr))
            irq = inb(EISA_REG0);
            irq = de4x5_irq[(irq >> 1) & 0x03];
 
-           if (is_DC2114x) device |= (cfrv & CFRV_RN);
+           if (is_DC2114x) {
+               device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+           }
            lp->chipset = device;
 
            /* Write the PCI Configuration Registers */
@@ -2165,7 +2174,9 @@ pci_probe(struct device *dev, u_long ioaddr))
        lp->bus_num = pb;
            
        /* Set the chipset information */
-       if (is_DC2114x) device |= (cfrv & CFRV_RN);
+       if (is_DC2114x) {
+           device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+       }
        lp->chipset = device;
 
        /* Get the board I/O address (64 bits on sparc64) */
@@ -2249,7 +2260,9 @@ srom_search(struct pci_dev *dev))
        lp->bus_num = pb;
            
        /* Set the chipset information */
-       if (is_DC2114x) device |= (cfrv & CFRV_RN);
+       if (is_DC2114x) {
+           device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+       }
        lp->chipset = device;
 
        /* Get the board I/O address (64 bits on sparc64) */
@@ -3223,18 +3236,19 @@ de4x5_init_connection(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
+    u_long flags = 0;
 
     if (lp->media != lp->c_media) {
         de4x5_dbg_media(dev);
        lp->c_media = lp->media;          /* Stop scrolling media messages */
     }
 
-    cli();
+    spin_lock_irqsave(&lp->lock, flags);
     de4x5_rst_desc_ring(dev);
     de4x5_setup_intr(dev);
     lp->tx_enable = YES;
     dev->tbusy = 0;
-    sti();
+    spin_unlock_irqrestore(&lp->lock, flags);
     outl(POLL_DEMAND, DE4X5_TPD);
     mark_bh(NET_BH);
 
@@ -5524,116 +5538,90 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        u16 sval[72];
        u32 lval[36];
     } tmp;
+    u_long flags = 0;
     
     switch(ioc->cmd) {
     case DE4X5_GET_HWADDR:           /* Get the hardware address */
        ioc->len = ETH_ALEN;
-       status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
-       if (status)
-           break;
+       if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
        for (i=0; i<ETH_ALEN; i++) {
            tmp.addr[i] = dev->dev_addr[i];
        }
        copy_to_user(ioc->data, tmp.addr, ioc->len);
-       
        break;
+
     case DE4X5_SET_HWADDR:           /* Set the hardware address */
-       status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
-       if (status)
-           break;
-       status = -EPERM;
-       if (!capable(CAP_NET_ADMIN))
-           break;
-       status = 0;
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN)) return -EFAULT;
        copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
        for (i=0; i<ETH_ALEN; i++) {
            dev->dev_addr[i] = tmp.addr[i];
        }
        build_setup_frame(dev, PHYS_ADDR_ONLY);
        /* Set up the descriptor and give ownership to the card */
-       while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
+       while (test_and_set_bit(0, (void *)&dev->tbusy) != 0) barrier();
        load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
                                                       SETUP_FRAME_LEN, NULL);
        lp->tx_new = (++lp->tx_new) % lp->txRingSize;
        outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
        dev->tbusy = 0;                              /* Unlock the TX ring */
-       
        break;
+
     case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
-       if (capable(CAP_NET_ADMIN)) {
-           omr = inl(DE4X5_OMR);
-           omr |= OMR_PR;
-           outl(omr, DE4X5_OMR);
-           dev->flags |= IFF_PROMISC;
-       } else {
-           status = -EPERM;
-       }
-       
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       omr = inl(DE4X5_OMR);
+       omr |= OMR_PR;
+       outl(omr, DE4X5_OMR);
+       dev->flags |= IFF_PROMISC;
        break;
+
     case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
-       if (capable(CAP_NET_ADMIN)) {
-           omr = inl(DE4X5_OMR);
-           omr &= ~OMR_PR;
-           outb(omr, DE4X5_OMR);
-           dev->flags &= ~IFF_PROMISC;
-       } else {
-           status = -EPERM;
-       }
-       
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       omr = inl(DE4X5_OMR);
+       omr &= ~OMR_PR;
+       outb(omr, DE4X5_OMR);
+       dev->flags &= ~IFF_PROMISC;
        break;
+
     case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
        printk("%s: Boo!\n", dev->name);
-       
        break;
+
     case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
-       if (capable(CAP_NET_ADMIN)) {
-           omr = inl(DE4X5_OMR);
-           omr |= OMR_PM;
-           outl(omr, DE4X5_OMR);
-       } else {
-           status = -EPERM;
-       }
-       
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       omr = inl(DE4X5_OMR);
+       omr |= OMR_PM;
+       outl(omr, DE4X5_OMR);
        break;
+
     case DE4X5_GET_STATS:            /* Get the driver statistics */
        ioc->len = sizeof(lp->pktStats);
-       status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
-       if (status)
-           break;
-       
-       cli();
+       if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+       spin_lock_irqsave(&lp->lock, flags);
        copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
-       sti();
-       
+       spin_unlock_irqrestore(&lp->lock, flags);
        break;
+
     case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
-       if (capable(CAP_NET_ADMIN)) {
-           cli();
-           memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-           sti();
-       } else {
-           status = -EPERM;
-       }
-       
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       spin_lock_irqsave(&lp->lock, flags);
+       memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+       spin_unlock_irqrestore(&lp->lock, flags);
        break;
+
     case DE4X5_GET_OMR:              /* Get the OMR Register contents */
        tmp.addr[0] = inl(DE4X5_OMR);
-       if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
-           copy_to_user(ioc->data, tmp.addr, 1);
-       }
-       
+       if (verify_area(VERIFY_WRITE, ioc->data, 1)) return -EFAULT;
+       copy_to_user(ioc->data, tmp.addr, 1);
        break;
+
     case DE4X5_SET_OMR:              /* Set the OMR Register contents */
-       if (capable(CAP_NET_ADMIN)) {
-           if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
-               copy_from_user(tmp.addr, ioc->data, 1);
-               outl(tmp.addr[0], DE4X5_OMR);
-           }
-       } else {
-           status = -EPERM;
-       }
-       
+       if (!capable(CAP_NET_ADMIN)) return -EPERM;
+       if (verify_area(VERIFY_READ, ioc->data, 1)) return -EFAULT;
+       copy_from_user(tmp.addr, ioc->data, 1);
+       outl(tmp.addr[0], DE4X5_OMR);
        break;
+
     case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
        j = 0;
        tmp.lval[0] = inl(DE4X5_STS); j+=4;
@@ -5645,9 +5633,8 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        tmp.lval[6] = inl(DE4X5_STRR); j+=4;
        tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
        ioc->len = j;
-       if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
-           copy_to_user(ioc->data, tmp.addr, ioc->len);
-       }
+       if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+       copy_to_user(ioc->data, tmp.addr, ioc->len);
        break;
        
 #define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
@@ -5736,14 +5723,13 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        tmp.addr[j++] = dev->tbusy;
        
        ioc->len = j;
-       if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
-           copy_to_user(ioc->data, tmp.addr, ioc->len);
-       }
-       
+       if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
+       copy_to_user(ioc->data, tmp.addr, ioc->len);
        break;
+
 */
     default:
-       status = -EOPNOTSUPP;
+       return -EOPNOTSUPP;
     }
     
     return status;
@@ -5775,6 +5761,12 @@ init_module(void)
        if (!mdev) mdev = p;
 
        if (register_netdev(p) != 0) {
+           struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+           if (lp) {
+               release_region(p->base_addr, (lp->bus == PCI ? 
+                                             DE4X5_PCI_TOTAL_SIZE :
+                                             DE4X5_EISA_TOTAL_SIZE));
+           }
            kfree(p);
        } else {
            status = 0;                 /* At least one adapter will work */
index 24ab3387386b34eb062adbf1c8e9119826006517..6e5aeae0fd0eea248f5f0b65bf308e28e1fe5973 100644 (file)
 #define DC2114x     DC2114x_DID
 #define DC21142     (DC2114x_DID | 0x0010)
 #define DC21143     (DC2114x_DID | 0x0030)
+#define DC2114x_BRK 0x0020           /* CFRV break between DC21142 & DC21143 */
 
 #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
 #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
index c379b3a4392af79a08f44a09c276fcc7870450f7..2d4e0848288cf0a40b69c730b2b0f043801e67f4 100644 (file)
@@ -1098,7 +1098,7 @@ dgrs_download(struct device *dev0))
         */
        proc_reset(dev0, 0);
 
-       for (i = jiffies + 8 * HZ; i > jiffies; )
+       for (i = jiffies + 8 * HZ; time_after(i, jiffies); )
        {
                if (priv0->bcomm->bc_status >= BC_RUN)
                        break;
@@ -1196,7 +1196,7 @@ dgrs_probe1(struct device *dev))
                return (rc);
 
        priv->intrcnt = 0;
-       for (i = jiffies + 2*HZ + HZ/2; i > jiffies; )
+       for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
                if (priv->intrcnt >= 2)
                        break;
        if (priv->intrcnt < 2)
index b26a1bfc01165e869f03781db77e8e7e3068e16e..edb80ac1ea63abe9d5c5c7d10a3dd51ade8ff5c5 100644 (file)
@@ -8,7 +8,7 @@
        according to the terms of the GNU Public License,
        incorporated herein by reference.
 
-       The author may be reached at bao.ha@srs.gov
+       The author may be reached at bao.ha@srs.gov 
        or 418 Hastings Place, Martinez, GA 30907.
 
        Things remaining to do:
        This is a compatibility hardware problem.
 
        Versions:
+       0.11b   Pascal Dupuis : works as a module under 2.1.xx
+               debug messages are flagged as KERN_DEBUG to avoid console 
+               flooding 
+               added locking at critical parts
+       0.11a   Attempt to get 2.1.xx support up (RMC)
+       0.11    Brian Candler added support for multiple cards. Tested as
+               a module, no idea if it works when compiled into kernel.
+
+       0.10e   Rick Bressler notified me that ifconfig up;ifconfig down fails
+               because the irq is lost somewhere. Fixed that by moving 
+               request_irq and free_irq to eepro_open and eepro_close respectively.
+       0.10d   Ugh! Now Wakeup works. Was seriously broken in my first attempt.
+               I'll need to find a way to specify an ioport other than
+               the default one in the PnP case. PnP definitively sucks.
+               And, yes, this is not the only reason.
+       0.10c   PnP Wakeup Test for 595FX. uncomment #define PnPWakeup;
+               to use.
+       0.10b   Should work now with (some) Pro/10+. At least for 
+               me (and my two cards) it does. _No_ guarantee for 
+               function with non-Pro/10+ cards! (don't have any)
+               (RMC, 9/11/96)
+
+       0.10    Added support for the Etherexpress Pro/10+.  The
+               IRQ map was changed significantly from the old
+               pro/10.  The new interrupt map was provided by
+               Rainer M. Canavan (Canavan@Zeus.cs.bonn.edu).
+               (BCH, 9/3/96)
 
        0.09    Fixed a race condition in the transmit algorithm,
                which causes crashes under heavy load with fast
@@ -38,7 +65,7 @@
        0.07a   Fix a stat report which counts every packet as a
                heart-beat failure. (BCH, 6/3/95)
 
-       0.07    Modified to support all other 82595-based lan cards.
+       0.07    Modified to support all other 82595-based lan cards.  
                The IRQ vector of the EtherExpress Pro will be set
                according to the value saved in the EEPROM.  For other
                cards, I will do autoirq_request() to grab the next
                print out format. (BCH, 3/9/95 and 3/14/95)
 
        0.06    First stable release that I am comfortable with. (BCH,
-               3/2/95)
+               3/2/95) 
 
-       0.05    Complete testing of multicast. (BCH, 2/23/95)
+       0.05    Complete testing of multicast. (BCH, 2/23/95)   
 
-       0.04    Adding multicast support. (BCH, 2/14/95)
+       0.04    Adding multicast support. (BCH, 2/14/95)        
 
-       0.03    First widely alpha release for public testing.
-               (BCH, 2/14/95)
+       0.03    First widely alpha release for public testing. 
+               (BCH, 2/14/95)  
 
 */
 
 static const char *version =
-       "eepro.c: v0.09 7/31/96 Bao C. Ha (bao.ha@srs.gov)\n";
+       "eepro.c: v0.11b 08/12/1998 dupuis@lei.ucl.ac.be\n";
 
 #include <linux/module.h>
 
 /*
   Sources:
 
-       This driver wouldn't have been written without the availability
-       of the Crynwr's Lan595 driver source code.  It helps me to
-       familiarize with the 82595 chipset while waiting for the Intel
-       documentation.  I also learned how to detect the 82595 using
+       This driver wouldn't have been written without the availability 
+       of the Crynwr's Lan595 driver source code.  It helps me to 
+       familiarize with the 82595 chipset while waiting for the Intel 
+       documentation.  I also learned how to detect the 82595 using 
        the packet driver's technique.
 
        This driver is written by cutting and pasting the skeleton.c driver
        provided by Donald Becker.  I also borrowed the EEPROM routine from
        Donald Becker's 82586 driver.
 
-       Datasheet for the Intel 82595 (including the TX and FX version). It
-       provides just enough info that the casual reader might think that it
+       Datasheet for the Intel 82595 (including the TX and FX version). It 
+       provides just enough info that the casual reader might think that it 
        documents the i82595.
 
        The User Manual for the 82595.  It provides a lot of the missing
@@ -100,23 +127,59 @@ static const char *version =
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+#include <asm/spinlock.h>
+#endif
 #include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
 
+/* need to remove these asap      */
+/* 2.1.xx compatibility macros... */
+/*                                */
+
+
+#include <linux/version.h>
+
+/* For linux 2.1.xx */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
+/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
+#define SLOW_DOWN inb(0x80)
+/* udelay(2) */
+
+#else 
+/* for 2.x */
+
+#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb), (mode) )
+#define test_and_set_bit(a,b) set_bit((a),(b))
+#define SLOW_DOWN SLOW_DOWN_IO
+
+#endif
+
+
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int eepro_portlist[] __initdata =
-   { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0x360, 0};
+static unsigned int eepro_portlist[] =
+   { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
+/* note: 0x300 is default, the 595FX supports ALL IO Ports 
+  from 0x000 to 0x3F0, some of which are reserved in PCs */
+
+/* To try the (not-really PnP Wakeup: */
+/*
+#define PnPWakeup
+*/
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
-#define NET_DEBUG 3
+#define NET_DEBUG 0
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
@@ -130,23 +193,107 @@ static unsigned int net_debug = NET_DEBUG;
 
 /* Information that need to be kept for each board. */
 struct eepro_local {
-       struct net_device_stats stats;
+       struct enet_statistics stats;
        unsigned rx_start;
        unsigned tx_start; /* start of the transmit chain */
        int tx_last;  /* pointer to last packet in the transmit chain */
        unsigned tx_end;   /* end of the transmit chain (plus 1) */
-       int eepro;      /* a flag, TRUE=1 for the EtherExpress Pro/10,
-                          FALSE = 0 for other 82595-based lan cards. */
+       int eepro;      /* 1 for the EtherExpress Pro/10,
+                          2 for the EtherExpress Pro/10+,
+                          0 for other 82595-based lan cards. */
        int version;    /* a flag to indicate if this is a TX or FX
                                   version of the 82595 chip. */
        int stepping;
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+        spinlock_t lock; /* to prevent interrupt within interrupts */ 
+#endif
 };
 
 /* The station (ethernet) address prefix, used for IDing the board. */
-#define SA_ADDR0 0x00
+#define SA_ADDR0 0x00  /* Etherexpress Pro/10 */
 #define SA_ADDR1 0xaa
 #define SA_ADDR2 0x00
 
+#define GetBit(x,y) ((x & (1<<y))>>y)
+
+/* EEPROM Word 0: */
+#define ee_PnP       0  /* Plug 'n Play enable bit */
+#define ee_Word1     1  /* Word 1? */
+#define ee_BusWidth  2  /* 8/16 bit */
+#define ee_FlashAddr 3  /* Flash Address */
+#define ee_FlashMask 0x7   /* Mask */
+#define ee_AutoIO    6  /* */
+#define ee_reserved0 7  /* =0! */
+#define ee_Flash     8  /* Flash there? */
+#define ee_AutoNeg   9  /* Auto Negotiation enabled? */
+#define ee_IO0       10 /* IO Address LSB */
+#define ee_IO0Mask   0x /*...*/
+#define ee_IO1       15 /* IO MSB */
+
+/* EEPROM Word 1: */
+#define ee_IntSel    0   /* Interrupt */
+#define ee_IntMask   0x7
+#define ee_LI        3   /* Link Integrity 0= enabled */
+#define ee_PC        4   /* Polarity Correction 0= enabled */
+#define ee_TPE_AUI   5   /* PortSelection 1=TPE */
+#define ee_Jabber    6   /* Jabber prevention 0= enabled */
+#define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */
+#define ee_SMOUT     8   /* SMout Pin Control 0= Input */
+#define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */
+#define ee_reserved1 10  /* .. 12 =0! */
+#define ee_AltReady  13  /* Alternate Ready, 0=normal */
+#define ee_reserved2 14  /* =0! */
+#define ee_Duplex    15
+
+/* Word2,3,4: */
+#define ee_IA5       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA4       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA3       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA2       8 /*bit start for individual Addr Byte 5 */
+#define ee_IA1       0 /*bit start for individual Addr Byte 5 */
+#define ee_IA0       8 /*bit start for individual Addr Byte 5 */
+
+/* Word 5: */
+#define ee_BNC_TPE   0 /* 0=TPE */
+#define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
+#define ee_BootTypeMask 0x3 
+#define ee_NumConn   3  /* Number of Connections 0= One or Two */
+#define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */
+#define ee_PortTPE   5
+#define ee_PortBNC   6
+#define ee_PortAUI   7
+#define ee_PowerMgt  10 /* 0= disabled */
+#define ee_CP        13 /* Concurrent Processing */
+#define ee_CPMask    0x7
+
+/* Word 6: */
+#define ee_Stepping  0 /* Stepping info */
+#define ee_StepMask  0x0F
+#define ee_BoardID   4 /* Manucaturer Board ID, reserved */
+#define ee_BoardMask 0x0FFF
+
+/* Word 7: */
+#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */
+#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
+
+/*..*/
+#define ee_SIZE 0x40 /* total EEprom Size */
+#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
+
+
+/* Card identification via EEprom:   */
+#define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */
+#define ee_addr_id 0x11      /* Word offset for Card ID */
+#define ee_addr_SN 0x12      /* Serial Number */
+#define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */
+
+
+#define ee_vendor_intel0 0x25  /* Vendor ID Intel */
+#define ee_vendor_intel1 0xD4
+#define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */
+#define ee_id_eepro10p1 0x31
+
+
 /* Index to functions, as function prototypes. */
 
 extern int eepro_probe(struct device *dev);
@@ -158,8 +305,8 @@ static void eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void    eepro_rx(struct device *dev);
 static void    eepro_transmit_interrupt(struct device *dev);
 static int     eepro_close(struct device *dev);
-static struct net_device_stats *eepro_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
+static struct enet_statistics *eepro_get_stats(struct device *dev);
+static void     set_multicast_list(struct device *dev);
 
 static int read_eeprom(int ioaddr, int location);
 static void hardware_send_packet(struct device *dev, void *buf, short length);
@@ -186,10 +333,10 @@ single packet.  In other systems with faster computers and more congested
 network traffics, the ring linked list should improve performance by
 allowing up to 8K worth of packets to be queued.
 
-The sizes of the receive and transmit buffers can now be changed via lilo
+The sizes of the receive and transmit buffers can now be changed via lilo 
 or insmod.  Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
 where rx-buffer is in KB unit.  Modules uses the parameter mem which is
-also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
+also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."  
 The receive buffer has to be more than 3K or less than 29K.  Otherwise,
 it is reset to the default of 24K, and, hence, 8K for the trasnmit
 buffer (transmit-buffer = 32K - receive-buffer).
@@ -200,11 +347,11 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #define RCV_RAM         0x6000  /* 24KB default for RCV buffer */
 #define RCV_LOWER_LIMIT 0x00    /* 0x0000 */
 /* #define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) */    /* 0x5ffe */
-#define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8)
+#define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8)   
 /* #define XMT_RAM         (RAM_SIZE - RCV_RAM) */    /* 8KB for XMT buffer */
 #define XMT_RAM         (RAM_SIZE - (rcv_ram))    /* 8KB for XMT buffer */
 /* #define XMT_LOWER_LIMIT (RCV_RAM >> 8) */  /* 0x6000 */
-#define XMT_LOWER_LIMIT ((rcv_ram) >> 8)
+#define XMT_LOWER_LIMIT ((rcv_ram) >> 8) 
 #define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8)   /* 0x7ffe */
 #define        XMT_HEADER      8
 
@@ -218,9 +365,9 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #define        XMT_CHAIN       0x04
 #define        XMT_COUNT       0x06
 
-#define        BANK0_SELECT    0x00
-#define        BANK1_SELECT    0x40
-#define        BANK2_SELECT    0x80
+#define        BANK0_SELECT    0x00            
+#define        BANK1_SELECT    0x40            
+#define        BANK2_SELECT    0x80            
 
 /* Bank 0 registers */
 #define        COMMAND_REG     0x00    /* Register 0 */
@@ -280,7 +427,7 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #define        REG13           0x0d
 #define        FDX             0x00
 #define        A_N_ENABLE      0x02
-
+       
 #define        I_ADD_REG0      0x04
 #define        I_ADD_REG1      0x05
 #define        I_ADD_REG2      0x06
@@ -295,7 +442,7 @@ buffer (transmit-buffer = 32K - receive-buffer).
 #define EEDO 0x08
 
 
-/* Check for a network adaptor of this type, and return '0' iff one exists.
+/* Check for a network adaptor of this type, and return '0' if one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
    If dev->base_addr == 2, allocate space for the device and return success
@@ -307,17 +454,48 @@ buffer (transmit-buffer = 32K - receive-buffer).
 struct netdev_entry netcard_drv =
 {"eepro", eepro_probe1, EEPRO_IO_EXTENT, eepro_portlist};
 #else
-__initfunc(int
-eepro_probe(struct device *dev))
+int
+eepro_probe(struct device *dev)
 {
        int i;
        int base_addr = dev ? dev->base_addr : 0;
 
+
+#ifdef PnPWakeup
+       /* XXXX for multiple cards should this only be run once? */
+       
+       /* Wakeup: */
+       #define WakeupPort 0x279
+       #define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
+                              0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
+                              0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
+                              0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
+
+       {
+               unsigned short int WS[32]=WakeupSeq;
+
+               if (check_region(WakeupPort, 2)==0) {
+
+                       if (net_debug>5)
+                               printk(KERN_DEBUG "Waking UP\n");
+
+                       outb_p(0,WakeupPort);
+                       outb_p(0,WakeupPort);
+                       for (i=0; i<32; i++) {
+                               outb_p(WS[i],WakeupPort);
+                               if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
+                       }
+               } else printk("Checkregion Failed!\n");
+       }
+#endif
+
+
        if (base_addr > 0x1ff)          /* Check a single specified location. */
                return eepro_probe1(dev, base_addr);
        else if (base_addr != 0)        /* Don't probe at all. */
                return ENXIO;
 
+
        for (i = 0; eepro_portlist[i]; i++) {
                int ioaddr = eepro_portlist[i];
                if (check_region(ioaddr, EEPRO_IO_EXTENT))
@@ -330,30 +508,89 @@ eepro_probe(struct device *dev))
 }
 #endif
 
+void printEEPROMInfo(short ioaddr)
+{
+       unsigned short Word;
+       int i,j;
+  
+       for (i=0, j=ee_Checksum; i<ee_SIZE; i++)
+               j+=read_eeprom(ioaddr,i);
+       printk("Checksum: %#x\n",j&0xffff);
+     
+       Word=read_eeprom(ioaddr, 0);
+       printk(KERN_DEBUG "Word0:\n");
+       printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
+       printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
+       printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg)); 
+       printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
+
+       if (net_debug>4)  {
+               Word=read_eeprom(ioaddr, 1);
+               printk(KERN_DEBUG "Word1:\n");
+               printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
+               printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
+               printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
+               printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
+               printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
+               printk(KERN_DEBUG " AutoPort: %d\n", GetBit(!Word,ee_Jabber));
+               printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));  
+       }
+
+  Word=read_eeprom(ioaddr, 5);
+       printk(KERN_DEBUG "Word5:\n");
+       printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
+       printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
+       printk(KERN_DEBUG " Has ");
+       if (GetBit(Word,ee_PortTPE)) printk("TPE ");
+       if (GetBit(Word,ee_PortBNC)) printk("BNC ");
+       if (GetBit(Word,ee_PortAUI)) printk("AUI ");
+       printk("port(s) \n");
+
+  Word=read_eeprom(ioaddr, 6);
+       printk(KERN_DEBUG "Word6:\n");
+       printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
+       printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
+
+  Word=read_eeprom(ioaddr, 7);
+       printk(KERN_DEBUG "Word7:\n");
+       printk(KERN_DEBUG " INT to IRQ:\n");
+
+       printk(KERN_DEBUG);
+  for (i=0, j=0; i<15; i++)
+     if (GetBit(Word,i)) printk(" INT%d -> IRQ %d;",j++,i);
+
+       printk("\n");
+}
+
 /* This is the real probe routine.  Linux has a history of friendly device
-   probes on the ISA bus.  A good device probes avoids doing writes, and
+   probes on the ISA bus.  A good device probe avoids doing writes, and
    verifies that the correct device exists and functions.  */
 
-__initfunc(int eepro_probe1(struct device *dev, short ioaddr))
+int eepro_probe1(struct device *dev, short ioaddr)
 {
        unsigned short station_addr[6], id, counter;
-       int i;
-       int eepro;      /* a flag, TRUE=1 for the EtherExpress Pro/10,
-                          FALSE = 0 for other 82595-based lan cards. */
+       int i,j, irqMask;
+       int eepro;
        const char *ifmap[] = {"AUI", "10Base2", "10BaseT"};
        enum iftype { AUI=0, BNC=1, TPE=2 };
 
        /* Now, we are going to check for the signature of the
           ID_REG (register 2 of bank 0) */
 
-       if (((id=inb(ioaddr + ID_REG)) & ID_REG_MASK) == ID_REG_SIG) {
+
+ id=inb(ioaddr + ID_REG);
+ printk(KERN_DEBUG " id: %#x ",id);
+ printk(" io: %#x ",ioaddr);
+       if (((id) & ID_REG_MASK) == ID_REG_SIG) {
 
                /* We seem to have the 82595 signature, let's
                   play with its counter (last 2 bits of
                   register 2 of bank 0) to be sure. */
-
-               counter = (id & R_ROBIN_BITS);
-               if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) ==
+       
+               counter = (id & R_ROBIN_BITS);  
+               if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == 
                        (counter + 0x40)) {
 
                        /* Yes, the 82595 has been found */
@@ -366,79 +603,110 @@ __initfunc(int eepro_probe1(struct device *dev, short ioaddr))
                        station_addr[2] = read_eeprom(ioaddr, 4);
 
                        /* Check the station address for the manufacturer's code */
-
-                       if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
-                               eepro = 0;
-                               printk("%s: Intel 82595-based lan card at %#x,",
+                       if (net_debug>3)
+                               printEEPROMInfo(ioaddr);
+                               
+                       if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) { /* int to IRQ Mask */
+                               eepro = 2;
+                               printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
+                                       dev->name, ioaddr);
+                       } else
+                       if (station_addr[2] == 0x00aa)  {
+                               eepro = 1;
+                               printk("%s: Intel EtherExpress Pro/10 ISA at %#x,", 
                                        dev->name, ioaddr);
                        }
                        else {
-                               eepro = 1;
-                               printk("%s: Intel EtherExpress Pro/10 at %#x,",
+                               eepro = 0;
+                               printk("%s: Intel 82595-based lan card at %#x,", 
                                        dev->name, ioaddr);
                        }
 
                        /* Fill in the 'dev' fields. */
                        dev->base_addr = ioaddr;
-
+                       
                        for (i=0; i < 6; i++) {
                                dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
                                printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
                        }
-
+                       
                        if ((dev->mem_end & 0x3f) < 3 ||        /* RX buffer must be more than 3K */
                                (dev->mem_end & 0x3f) > 29)     /* and less than 29K */
                                dev->mem_end = RCV_RAM;         /* or it will be set to 24K */
                        else dev->mem_end = 1024*dev->mem_end;  /* Maybe I should shift << 10 */
 
                        /* From now on, dev->mem_end contains the actual size of rx buffer */
-
+                       
                        if (net_debug > 3)
                                printk(", %dK RCV buffer", (int)(dev->mem_end)/1024);
-
-                       outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
-                       id = inb(ioaddr + REG3);
-                       if (id & TPE_BIT)
-                               dev->if_port = TPE;
-                       else dev->if_port = BNC;
-
-                       if (dev->irq < 2 && eepro) {
+                               
+                               
+//                     outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+//                     id = inb(ioaddr + REG3);
+//                     if (id & TPE_BIT)
+//                             dev->if_port = TPE;
+//                     else dev->if_port = BNC;
+                       
+                       
+                       /* ............... */
+
+                       if (GetBit(  read_eeprom(ioaddr, 5),ee_BNC_TPE))
+                               dev->if_port = BNC;
+                       else dev->if_port = TPE;
+                
+                       
+                       /* ............... */
+
+//                     if (net_debug>3) 
+//                             printk("id: %x\n", id);
+
+
+                       if ((dev->irq < 2) && (eepro!=0)) {
                                i = read_eeprom(ioaddr, 1);
-                               switch (i & 0x07) {
-                                       case 0: dev->irq = 9; break;
-                                       case 1: dev->irq = 3; break;
-                                       case 2: dev->irq = 5; break;
-                                       case 3: dev->irq = 10; break;
-                                       case 4: dev->irq = 11; break;
-                                       default: /* should never get here !!!!! */
-                                               printk(" illegal interrupt vector stored in EEPROM.\n");
+                               irqMask = read_eeprom(ioaddr, 7);
+                               i &= 0x07; /* Mask off INT number */
+                               
+                               for (j=0; ((j<16) && (i>=0)); j++) {
+                                       if ((irqMask & (1<<j))!=0) {
+                                               if (i==0) {
+                                                       dev->irq = j;
+                                                       break; /* found bit corresponding to irq */
+                                               }
+                                               i--; /* count bits set in irqMask */
+                                       }
+                               }
+                               if (dev -> irq<2) {
+                                       printk(" Duh! illegal interrupt vector stored in EEPROM.\n");
                                                return ENODEV;
-                                       }
-                               }
-                       else if (dev->irq == 2)
+                               } else 
+                               
+                               if (dev->irq==2) dev->irq = 9;
+
+                               else if (dev->irq == 2)
                                dev->irq = 9;
+                       }
 
                        if (dev->irq > 2) {
                                printk(", IRQ %d, %s.\n", dev->irq,
                                                ifmap[dev->if_port]);
-                               if (request_irq(dev->irq, &eepro_interrupt, 0, "eepro", dev)) {
+                               /*if (request_irq(dev->irq, &eepro_interrupt, 0, "eepro", dev)) {
                                        printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
                                        return -EAGAIN;
-                               }
+                               }*/
                        }
                        else printk(", %s.\n", ifmap[dev->if_port]);
-
+                       
                        if ((dev->mem_start & 0xf) > 0) /* I don't know if this is */
                                net_debug = dev->mem_start & 7; /* still useful or not */
 
                        if (net_debug > 3) {
                                i = read_eeprom(ioaddr, 5);
                                if (i & 0x2000) /* bit 13 of EEPROM word 5 */
-                                       printk("%s: Concurrent Processing is enabled but not used!\n",
+                                 printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n",
                                                dev->name);
                        }
 
-                       if (net_debug)
+                       if (net_debug) 
                                printk(version);
 
                        /* Grab the region so we can find another board if autoIRQ fails. */
@@ -450,10 +718,10 @@ __initfunc(int eepro_probe1(struct device *dev, short ioaddr))
                                return -ENOMEM;
                        memset(dev->priv, 0, sizeof(struct eepro_local));
 
-                       dev->open = eepro_open;
-                       dev->stop = eepro_close;
-                       dev->hard_start_xmit = eepro_send_packet;
-                       dev->get_stats = eepro_get_stats;
+                       dev->open               = eepro_open;
+                       dev->stop               = eepro_close;
+                       dev->hard_start_xmit    = eepro_send_packet;
+                       dev->get_stats          = eepro_get_stats;
                        dev->set_multicast_list = &set_multicast_list;
 
                        /* Fill in the fields of the device structure with
@@ -481,17 +749,21 @@ __initfunc(int eepro_probe1(struct device *dev, short ioaddr))
    */
 
 static char irqrmap[] = {-1,-1,0,1,-1,2,-1,-1,-1,0,3,4,-1,-1,-1,-1};
+static char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
 static int     eepro_grab_irq(struct device *dev)
 {
-       int irqlist[] = { 5, 9, 10, 11, 4, 3, 0};
+       int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
        int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
 
        outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
+       
+       /* Set the spinlock before activating  IRQ! */
+       ((struct eepro_local *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
        /* Enable the interrupt line. */
        temp_reg = inb(ioaddr + REG1);
        outb(temp_reg | INT_ENABLE, ioaddr + REG1);
-
+       
        outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
 
        /* clear all interrupts */
@@ -507,18 +779,20 @@ static int        eepro_grab_irq(struct device *dev)
 
                outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
 
-               if (request_irq (*irqp, NULL, 0, "bogus", NULL) != EBUSY) {
+               if (request_irq (*irqp, NULL, 0, "bogus", dev) != EBUSY) {
                        /* Twinkle the interrupt, and check if it's seen */
                        autoirq_setup(0);
 
                        outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */
-
-                       if (*irqp == autoirq_report(2) &&  /* It's a good IRQ line */
-                               (request_irq(dev->irq = *irqp, &eepro_interrupt, 0, "eepro", dev) == 0))
+                               
+                       if (*irqp == autoirq_report(2) )//&&  /* It's a good IRQ line */
+                               /* We don't take irqs on detection anymore.
+                                       only when actually turning on the driver (ifconfig) */
+                               /* //(request_irq(dev->irq = *irqp, &eepro_interrupt, 0, "eepro", dev) == 0)) */
                                        break;
 
                        /* clear all interrupts */
-                       outb(ALL_MASK, ioaddr + STATUS_REG);
+                       outb(ALL_MASK, ioaddr + STATUS_REG); 
                }
        } while (*++irqp);
 
@@ -526,40 +800,64 @@ static int        eepro_grab_irq(struct device *dev)
 
        /* Disable the physical interrupt line. */
        temp_reg = inb(ioaddr + REG1);
-       outb(temp_reg & 0x7f, ioaddr + REG1);
+       outb(temp_reg & 0x7f, ioaddr + REG1); 
 
        outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
 
        /* Mask all the interrupts. */
-       outb(ALL_MASK, ioaddr + INT_MASK_REG);
+       outb(ALL_MASK, ioaddr + INT_MASK_REG); 
 
        /* clear all interrupts */
-       outb(ALL_MASK, ioaddr + STATUS_REG);
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
 
        return dev->irq;
 }
 
-static int
-eepro_open(struct device *dev)
+static int eepro_open(struct device *dev)
 {
        unsigned short temp_reg, old8, old9;
+       int irqMask;
        int i, ioaddr = dev->base_addr, rcv_ram = dev->mem_end;
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
 
        if (net_debug > 3)
-               printk("eepro: entering eepro_open routine.\n");
+               printk(KERN_DEBUG "eepro: entering eepro_open routine.\n");
 
-       if (dev->dev_addr[0] == SA_ADDR0 &&
+       if ((irqMask=read_eeprom(ioaddr,7))== ee_FX_INT2IRQ) /* INT to IRQ Mask */
+               {
+                       lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
+                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); 
+               }
+       
+       else if ((dev->dev_addr[0] == SA_ADDR0 &&
                        dev->dev_addr[1] == SA_ADDR1 &&
-                       dev->dev_addr[2] == SA_ADDR2)
-               lp->eepro = 1; /* Yes, an Intel EtherExpress Pro/10 */
+                       dev->dev_addr[2] == SA_ADDR2))
+               { 
+                       lp->eepro = 1;
+                       if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); 
+               }  /* Yes, an Intel EtherExpress Pro/10 */
+
        else lp->eepro = 0; /* No, it is a generic 82585 lan card */
 
-       /* Get the interrupt vector for the 82595 */
+       /* Get the interrupt vector for the 82595 */    
        if (dev->irq < 2 && eepro_grab_irq(dev) == 0) {
                printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
                return -EAGAIN;
        }
+               
+       if (request_irq(dev->irq , &eepro_interrupt, 0, "eepro", dev)) {
+               printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+       
+#ifdef irq2dev_map
+       if  (((irq2dev_map[dev->irq] != 0)
+               || (irq2dev_map[dev->irq] = dev) == 0) && 
+               (irq2dev_map[dev->irq]!=dev)) {
+           /* printk("%s: IRQ map wrong\n", dev->name); */
+               return -EAGAIN;
+       }
+#endif
 
        /* Initialize the 82595. */
 
@@ -567,18 +865,18 @@ eepro_open(struct device *dev)
        temp_reg = inb(ioaddr + EEPROM_REG);
 
        lp->stepping = temp_reg >> 5;   /* Get the stepping number of the 595 */
-
+       
        if (net_debug > 3)
-               printk("The stepping of the 82595 is %d\n", lp->stepping);
+               printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
 
        if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
                outb(temp_reg & 0xef, ioaddr + EEPROM_REG);
-       for (i=0; i < 6; i++)
-               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
-
+       for (i=0; i < 6; i++) 
+               outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); 
+                       
        temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
        outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
-               | RCV_Discard_BadFrame, ioaddr + REG1);
+               | RCV_Discard_BadFrame, ioaddr + REG1);  
 
        temp_reg = inb(ioaddr + REG2); /* Match broadcast */
        outb(temp_reg | 0x14, ioaddr + REG2);
@@ -589,51 +887,70 @@ eepro_open(struct device *dev)
        /* Set the receiving mode */
        outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
 
+       /* Set the interrupt vector */  
        temp_reg = inb(ioaddr + INT_NO_REG);
-       outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+       if (lp->eepro == 2)
+               outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
+       else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); 
+
+
+    temp_reg = inb(ioaddr + INT_NO_REG);
+    if (lp->eepro == 2)
+       outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
+    else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
+
+    if (net_debug > 3)
+       printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg);
+       
+       
 
        /* Initialize the RCV and XMT upper and lower limits */
-       outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG);
-       outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG);
-       outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG);
-       outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG);
+       outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); 
+       outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); 
+       outb(XMT_LOWER_LIMIT, ioaddr + XMT_LOWER_LIMIT_REG); 
+       outb(XMT_UPPER_LIMIT, ioaddr + XMT_UPPER_LIMIT_REG); 
 
        /* Enable the interrupt line. */
        temp_reg = inb(ioaddr + REG1);
-       outb(temp_reg | INT_ENABLE, ioaddr + REG1);
+       outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
 
        outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
 
        /* Let RX and TX events to interrupt */
-       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
        /* clear all interrupts */
-       outb(ALL_MASK, ioaddr + STATUS_REG);
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
 
        /* Initialize RCV */
-       outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR);
+       outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); 
        lp->rx_start = (RCV_LOWER_LIMIT << 8) ;
-       outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP);
+       outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); 
 
        /* Initialize XMT */
-       outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR);
+       outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); 
 
        /* Check for the i82595TX and i82595FX */
        old8 = inb(ioaddr + 8);
        outb(~old8, ioaddr + 8);
        if ((temp_reg = inb(ioaddr + 8)) == old8) {
                if (net_debug > 3)
-                       printk("i82595 detected!\n");
+                       printk(KERN_DEBUG "i82595 detected!\n");
                lp->version = LAN595;
        }
        else {
                lp->version = LAN595TX;
                outb(old8, ioaddr + 8);
                old9 = inb(ioaddr + 9);
-               outb(~old9, ioaddr + 9);
-               if ((temp_reg = inb(ioaddr + 9)) == ~old9) {
+               /*outb(~old9, ioaddr + 9);
+               if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/
+               
+               if (irqMask==ee_FX_INT2IRQ) {
                        enum iftype { AUI=0, BNC=1, TPE=2 };
-                       if (net_debug > 3)
-                               printk("i82595FX detected!\n");
+
+                       if (net_debug > 3) {
+                               printk(KERN_DEBUG "IrqMask: %#x\n",irqMask);
+                               printk(KERN_DEBUG "i82595FX detected!\n");
+                       }
                        lp->version = LAN595FX;
                        outb(old9, ioaddr + 9);
                        if (dev->if_port != TPE) {      /* Hopefully, this will fix the
@@ -647,24 +964,26 @@ eepro_open(struct device *dev)
                                outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
                        }
                }
-               else if (net_debug > 3)
-                       printk("i82595TX detected!\n");
+               else if (net_debug > 3) {
+                       printk(KERN_DEBUG "temp_reg: %#x  ~old9: %#x\n",temp_reg,((~old9)&0xff));
+                       printk(KERN_DEBUG "i82595TX detected!\n");
+               }
        }
-
+       
        outb(SEL_RESET_CMD, ioaddr);
        /* We are supposed to wait for 2 us after a SEL_RESET */
-       
-       udelay(2);
+       SLOW_DOWN;
+       SLOW_DOWN;
 
        lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */
-       lp->tx_last = 0;
-
+       lp->tx_last = 0;  
+       
        dev->tbusy = 0;
        dev->interrupt = 0;
        dev->start = 1;
 
        if (net_debug > 3)
-               printk("eepro: exiting eepro_open routine.\n");
+               printk(KERN_DEBUG "eepro: exiting eepro_open routine.\n");
 
        outb(RCV_ENABLE_CMD, ioaddr);
 
@@ -672,121 +991,168 @@ eepro_open(struct device *dev)
        return 0;
 }
 
-static int
-eepro_send_packet(struct sk_buff *skb, struct device *dev)
+static int eepro_send_packet(struct sk_buff *skb, struct device *dev)
 {
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
        int ioaddr = dev->base_addr;
        int rcv_ram = dev->mem_end;
 
        if (net_debug > 5)
-               printk("eepro: entering eepro_send_packet routine.\n");
-
+         printk(KERN_DEBUG  "eepro: entering eepro_send_packet routine.\n");
+       
        if (dev->tbusy) {
-               /* If we get here, some higher level has decided we are broken.
-                  There should really be a "kick me" function call instead. */
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 40)
-                       return 1;
-               if (net_debug > 1)
-                       printk("%s: transmit timed out, %s?\n", dev->name,
-                                  "network cable problem");
-               lp->stats.tx_errors++;
-
-               /* Try to restart the adaptor. */
-               outb(SEL_RESET_CMD, ioaddr);
-               /* We are supposed to wait for 2 us after a SEL_RESET */
-               udelay(2);
-
-               /* Do I also need to flush the transmit buffers here? YES? */
-               lp->tx_start = lp->tx_end = rcv_ram;
-               lp->tx_last = 0;
-
-               dev->tbusy=0;
-               dev->trans_start = jiffies;
-
-               outb(RCV_ENABLE_CMD, ioaddr);
+         /* If we get here, some higher level has decided we are broken.
+            There should really be a "kick me" function call instead. */
+         int tickssofar = jiffies - dev->trans_start;
+         if (tickssofar < 40)
+           return 1;
+        
+         /* if (net_debug > 1) */
+         printk("%s: transmit timed out, %s?\n", dev->name, 
+                "network cable problem");
+         /* This is not a duplicate. One message for the console, one for the
+            the log file  */
+         printk(KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
+                "network cable problem");
+         lp->stats.tx_errors++;
+
+         /* Try to restart the adaptor. */
+         outb(SEL_RESET_CMD, ioaddr); 
+         /* We are supposed to wait for 2 us after a SEL_RESET */
+         SLOW_DOWN;
+         SLOW_DOWN;
+         
+         /* Do I also need to flush the transmit buffers here? YES? */
+         lp->tx_start = lp->tx_end = rcv_ram; 
+         lp->tx_last = 0;
+       
+         dev->tbusy=0;
+         dev->trans_start = jiffies;
+         
+         outb(RCV_ENABLE_CMD, ioaddr);
+
+       }
 
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20155
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       //      if (skb == NULL) {
+       //      dev_tint(dev);
+       //      return 0;
+       // FIXME : what's this code for ?
        }
+#endif
 
        /* Block a timer-based transmit from overlapping. */
        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-               printk("%s: Transmitter access conflict.\n", dev->name);
+         printk("%s: Transmitter access conflict.\n", dev->name);
        else {
-               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-               unsigned char *buf = skb->data;
+          short length; unsigned char *buf;
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+         unsigned long flags;
+
+         /* Spin on the lock, until we're clear of an IRQ */
+         spin_lock_irqsave(&lp->lock, flags);     
+#endif
+         length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+         buf = skb->data;
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+         lp->stats.tx_bytes+=skb->len;
+#endif
+         hardware_send_packet(dev, buf, length);
+         
+         dev->trans_start = jiffies;
 
-               hardware_send_packet(dev, buf, length);
-               dev->trans_start = jiffies;
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+         spin_unlock_irqrestore(&lp->lock, flags);     
+#endif 
        }
 
-       dev_kfree_skb (skb);
+       compat_dev_kfree_skb (skb, FREE_WRITE);
 
        /* You might need to clean up and record Tx statistics here. */
        /* lp->stats.tx_aborted_errors++; */
 
        if (net_debug > 5)
-               printk("eepro: exiting eepro_send_packet routine.\n");
-
+               printk(KERN_DEBUG "eepro: exiting eepro_send_packet routine.\n");
+       
        return 0;
 }
 
-
 /*     The typical workload of the driver:
        Handle the network interface interrupts. */
 static void
 eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-       struct device *dev = dev_id;
+       struct device *dev =  (struct device *)dev_id;
+                             /* (struct device *)(irq2dev_map[irq]);*/
+#ifdef __SMP__
+       struct eepro_local *lp = (struct eepro_local *)dev->priv;
+#endif 
        int ioaddr, status, boguscount = 20;
 
-       if (net_debug > 5)
-               printk("eepro: entering eepro_interrupt routine.\n");
+       if (test_and_set_bit(0, (void*)&dev->interrupt)) 
+       {
+               printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+                       dev->name);
+               dev->interrupt = 0; /* Avoid halting machine. */
+               return;
+       }
 
+       if (net_debug > 5)
+               printk(KERN_DEBUG "eepro: entering eepro_interrupt routine.\n");
+       
        if (dev == NULL) {
                printk ("eepro_interrupt(): irq %d for unknown device.\n", irq);
                return;
        }
-       dev->interrupt = 1;
-
-       ioaddr = dev->base_addr;
-
-       do {
-               status = inb(ioaddr + STATUS_REG);
-
-               if (status & RX_INT) {
-                       if (net_debug > 4)
-                               printk("eepro: packet received interrupt.\n");
-
-                       /* Acknowledge the RX_INT */
-                       outb(RX_INT, ioaddr + STATUS_REG);
-
-                       /* Get the received packets */
-                       eepro_rx(dev);
-               }
-
-               else if (status & TX_INT) {
-                       if (net_debug > 4)
-                               printk("eepro: packet transmit interrupt.\n");
-
-                       /* Acknowledge the TX_INT */
-                       outb(TX_INT, ioaddr + STATUS_REG);
-
-                       /* Process the status of transmitted packets */
-                       eepro_transmit_interrupt(dev);
-               }
-
+       /* dev->interrupt = 1; */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+       spin_lock(&lp->lock);
+#endif 
+        ioaddr = dev->base_addr;
+
+        do { 
+         status = inb(ioaddr + STATUS_REG);
+               
+         if (status & RX_INT) {
+           if (net_debug > 4)
+             printk(KERN_DEBUG "eepro: packet received interrupt.\n");
+
+           /* Acknowledge the RX_INT */
+           outb(RX_INT, ioaddr + STATUS_REG);   
+           /* Get the received packets */
+           eepro_rx(dev);
+         }
+
+         else if (status & TX_INT) {
+           if (net_debug > 4)
+             printk(KERN_DEBUG "eepro: packet transmit interrupt.\n");
+
+           /* Acknowledge the TX_INT */
+           outb(TX_INT, ioaddr + STATUS_REG); 
+           
+           /* Process the status of transmitted packets */
+           eepro_transmit_interrupt(dev);
+         }
+       
        } while ((boguscount-- > 0) && (status & 0x06));
 
-       dev->interrupt = 0;
+       dev->interrupt = 0; 
+
        if (net_debug > 5)
-               printk("eepro: exiting eepro_interrupt routine.\n");
+               printk(KERN_DEBUG "eepro: exiting eepro_interrupt routine.\n");
 
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+       spin_unlock(&lp->lock);
+#endif
        return;
 }
 
-static int
-eepro_close(struct device *dev)
+static int eepro_close(struct device *dev)
 {
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
        int ioaddr = dev->base_addr;
@@ -800,40 +1166,44 @@ eepro_close(struct device *dev)
 
        /* Disable the physical interrupt line. */
        temp_reg = inb(ioaddr + REG1);
-       outb(temp_reg & 0x7f, ioaddr + REG1);
+       outb(temp_reg & 0x7f, ioaddr + REG1); 
 
        outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
 
        /* Flush the Tx and disable Rx. */
-       outb(STOP_RCV_CMD, ioaddr);
+       outb(STOP_RCV_CMD, ioaddr); 
        lp->tx_start = lp->tx_end = rcv_ram ;
-       lp->tx_last = 0;
+       lp->tx_last = 0;  
 
        /* Mask all the interrupts. */
-       outb(ALL_MASK, ioaddr + INT_MASK_REG);
+       outb(ALL_MASK, ioaddr + INT_MASK_REG); 
 
        /* clear all interrupts */
-       outb(ALL_MASK, ioaddr + STATUS_REG);
+       outb(ALL_MASK, ioaddr + STATUS_REG); 
 
        /* Reset the 82595 */
-       outb(RESET_CMD, ioaddr);
+       outb(RESET_CMD, ioaddr); 
 
        /* release the interrupt */
        free_irq(dev->irq, dev);
 
+#ifdef irq2dev_map
+       irq2dev_map[dev->irq] = 0;
+#endif
+
        /* Update the statistics here. What statistics? */
 
        /* We are supposed to wait for 200 us after a RESET */
+       SLOW_DOWN;
+       SLOW_DOWN; /* May not be enough? */
 
-       udelay(200);
-       
        MOD_DEC_USE_COUNT;
        return 0;
 }
 
 /* Get the current statistics. This may be called with the card open or
    closed. */
-static struct net_device_stats *
+static struct enet_statistics *
 eepro_get_stats(struct device *dev)
 {
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
@@ -851,7 +1221,7 @@ set_multicast_list(struct device *dev)
        unsigned short mode;
        struct dev_mc_list *dmi=dev->mc_list;
 
-       if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63)
+       if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) 
        {
                /*
                 *      We must make the kernel realise we had to move
@@ -859,17 +1229,17 @@ set_multicast_list(struct device *dev)
                 *      the cable. If it was a promisc request the
                 *      flag is already set. If not we assert it.
                 */
-               dev->flags|=IFF_PROMISC;
+               dev->flags|=IFF_PROMISC;                
 
                outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
                mode = inb(ioaddr + REG2);
-               outb(mode | PRMSC_Mode, ioaddr + REG2);
+               outb(mode | PRMSC_Mode, ioaddr + REG2); 
                mode = inb(ioaddr + REG3);
                outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
                outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
                printk("%s: promiscuous mode enabled.\n", dev->name);
-       }
-       else if (dev->mc_count==0 )
+       } 
+       else if (dev->mc_count==0 ) 
        {
                outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
                mode = inb(ioaddr + REG2);
@@ -878,11 +1248,11 @@ set_multicast_list(struct device *dev)
                outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
                outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
        }
-       else
+       else 
        {
                unsigned short status, *eaddrs;
                int i, boguscount = 0;
-
+               
                /* Disable RX and TX interrupts.  Necessary to avoid
                   corruption of the HOST_ADDRESS_REG by interrupt
                   service routines. */
@@ -890,7 +1260,7 @@ set_multicast_list(struct device *dev)
 
                outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
                mode = inb(ioaddr + REG2);
-               outb(mode | Multi_IA, ioaddr + REG2);
+               outb(mode | Multi_IA, ioaddr + REG2);   
                mode = inb(ioaddr + REG3);
                outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
                outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
@@ -899,7 +1269,7 @@ set_multicast_list(struct device *dev)
                outw(0, ioaddr + IO_PORT);
                outw(0, ioaddr + IO_PORT);
                outw(6*(dev->mc_count + 1), ioaddr + IO_PORT);
-               for (i = 0; i < dev->mc_count; i++)
+               for (i = 0; i < dev->mc_count; i++) 
                {
                        eaddrs=(unsigned short *)dmi->dmi_addr;
                        dmi=dmi->next;
@@ -916,9 +1286,9 @@ set_multicast_list(struct device *dev)
 
                /* Update the transmit queue */
                i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1);
-               if (lp->tx_start != lp->tx_end)
-               {
-                       /* update the next address and the chain bit in the
+               if (lp->tx_start != lp->tx_end) 
+               { 
+                       /* update the next address and the chain bit in the 
                           last packet */
                        outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
                        outw(i, ioaddr + IO_PORT);
@@ -933,26 +1303,28 @@ set_multicast_list(struct device *dev)
 
                /* Acknowledge that the MC setup is done */
                do { /* We should be doing this in the eepro_interrupt()! */
-                       udelay(2);
-                       if (inb(ioaddr + STATUS_REG) & 0x08)
+                       SLOW_DOWN;
+                       SLOW_DOWN;
+                       if (inb(ioaddr + STATUS_REG) & 0x08) 
                        {
                                i = inb(ioaddr);
                                outb(0x08, ioaddr + STATUS_REG);
                                if (i & 0x20) { /* command ABORTed */
-                                       printk("%s: multicast setup failed.\n",
+                                       printk("%s: multicast setup failed.\n", 
                                                dev->name);
                                        break;
                                } else if ((i & 0x0f) == 0x03)  { /* MC-Done */
-                                       printk("%s: set Rx mode to %d addresses.\n",
-                                               dev->name, dev->mc_count);
+                                 printk("%s: set Rx mode to %d address%s.\n",
+                                        dev->name, dev->mc_count,
+                                        dev->mc_count > 1 ? "es":"");
                                        break;
                                }
                        }
                } while (++boguscount < 100);
 
                /* Re-enable RX and TX interrupts */
-               outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-
+               outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+       
        }
        outb(RCV_ENABLE_CMD, ioaddr);
 }
@@ -961,7 +1333,7 @@ set_multicast_list(struct device *dev)
 /* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
 
 /* The delay between EEPROM clock transitions. */
-#define eeprom_delay() { udelay(40); }
+#define eeprom_delay() { int _i = 40; while (--_i > 0) { SLOW_DOWN; }}
 #define EE_READ_CMD (6 << 6)
 
 int
@@ -972,10 +1344,10 @@ read_eeprom(int ioaddr, int location)
        short ee_addr = ioaddr + EEPROM_REG;
        int read_cmd = location | EE_READ_CMD;
        short ctrl_val = EECS ;
-
+       
        outb(BANK2_SELECT, ioaddr);
        outb(ctrl_val, ee_addr);
-
+       
        /* Shift the read command bits out. */
        for (i = 8; i >= 0; i--) {
                short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI
@@ -987,7 +1359,7 @@ read_eeprom(int ioaddr, int location)
                eeprom_delay();
        }
        outb(ctrl_val, ee_addr);
-
+       
        for (i = 16; i > 0; i--) {
                outb(ctrl_val | EESK, ee_addr);  eeprom_delay();
                retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
@@ -1013,7 +1385,7 @@ hardware_send_packet(struct device *dev, void *buf, short length)
        unsigned status, tx_available, last, end, boguscount = 100;
 
        if (net_debug > 5)
-               printk("eepro: entering hardware_send_packet routine.\n");
+               printk(KERN_DEBUG "eepro: entering hardware_send_packet routine.\n");
 
        while (boguscount-- > 0) {
 
@@ -1022,9 +1394,9 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                service routines. */
                outb(ALL_MASK, ioaddr + INT_MASK_REG);
 
-               if (dev->interrupt == 1) {
+               if (dev->interrupt == 1) {  
                        /* Enable RX and TX interrupts */
-                       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+                       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
                        continue;
                }
 
@@ -1035,13 +1407,13 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                        tx_available = lp->tx_start - lp->tx_end;
                else tx_available = XMT_RAM;
 
-               if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER)
+               if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) 
                        >= tx_available)   /* No space available ??? */
                        {
                        eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */
 
                        /* Enable RX and TX interrupts */
-                       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+                       outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
                        continue;
                }
 
@@ -1049,17 +1421,17 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
 
                if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */
-                       if ((RAM_SIZE - last) <= XMT_HEADER) {
+                       if ((RAM_SIZE - last) <= XMT_HEADER) {  
                        /* Arrrr!!!, must keep the xmt header together,
                          several days were lost to chase this one down. */
                                last = rcv_ram;
                                end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
-                       }
+                       }       
                        else end = rcv_ram + (end - RAM_SIZE);
                }
 
                outw(last, ioaddr + HOST_ADDRESS_REG);
-               outw(XMT_CMD, ioaddr + IO_PORT);
+               outw(XMT_CMD, ioaddr + IO_PORT); 
                outw(0, ioaddr + IO_PORT);
                outw(end, ioaddr + IO_PORT);
                outw(length, ioaddr + IO_PORT);
@@ -1074,48 +1446,46 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                }
 
                /* A dummy read to flush the DRAM write pipeline */
-               status = inw(ioaddr + IO_PORT);
+               status = inw(ioaddr + IO_PORT); 
 
-               if (lp->tx_start == lp->tx_end) {
+               if (lp->tx_start == lp->tx_end) {       
                        outw(last, ioaddr + XMT_BAR);
                        outb(XMT_CMD, ioaddr);
                        lp->tx_start = last;   /* I don't like to change tx_start here */
                }
                else {
-                       /* update the next address and the chain bit in the
-                       last packet */
-                       if (lp->tx_end != last) {
-                               outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
-                               outw(last, ioaddr + IO_PORT);
-                       }
-                       outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
-                       status = inw(ioaddr + IO_PORT);
-                       outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
-                       /* Continue the transmit command */
-                       outb(RESUME_XMT_CMD, ioaddr);
+                 /* update the next address and the chain bit in the 
+                    last packet */
+                 if (lp->tx_end != last) {
+                   outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
+                   outw(last, ioaddr + IO_PORT); 
+                 }
+                 outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
+                 status = inw(ioaddr + IO_PORT); 
+                 outw(status | CHAIN_BIT, ioaddr + IO_PORT);
+
+                 /* Continue the transmit command */
+                 outb(RESUME_XMT_CMD, ioaddr);
                }
 
                lp->tx_last = last;
                lp->tx_end = end;
 
-               /* Enable RX and TX interrupts */
-               outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-
                if (dev->tbusy) {
                        dev->tbusy = 0;
                }
-
-               lp->stats.tx_bytes += length;
+               
+               /* Enable RX and TX interrupts */
+                outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
 
                if (net_debug > 5)
-                       printk("eepro: exiting hardware_send_packet routine.\n");
+                       printk(KERN_DEBUG "eepro: exiting hardware_send_packet routine.\n");
                return;
        }
 
        dev->tbusy = 1;
        if (net_debug > 5)
-               printk("eepro: exiting hardware_send_packet routine.\n");
+               printk(KERN_DEBUG "eepro: exiting hardware_send_packet routine.\n");
 }
 
 static void
@@ -1128,75 +1498,77 @@ eepro_rx(struct device *dev)
        unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
 
        if (net_debug > 5)
-               printk("eepro: entering eepro_rx routine.\n");
-
+               printk(KERN_DEBUG "eepro: entering eepro_rx routine.\n");
+       
        /* Set the read pointer to the start of the RCV */
        outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
        rcv_event = inw(ioaddr + IO_PORT);
 
        while (rcv_event == RCV_DONE) {
-               rcv_status = inw(ioaddr + IO_PORT);
-               rcv_next_frame = inw(ioaddr + IO_PORT);
-               rcv_size = inw(ioaddr + IO_PORT);
-
-               if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
-                       /* Malloc up new buffer. */
-                       struct sk_buff *skb;
-
-                       rcv_size &= 0x3fff;
-                       skb = dev_alloc_skb(rcv_size+5);
-                       if (skb == NULL) {
-                               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-                               lp->stats.rx_dropped++;
-                               break;
-                       }
-                       skb->dev = dev;
-                       skb_reserve(skb,2);
-
-                       if (lp->version == LAN595)
-                               insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
-                       else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
-                               unsigned short temp = inb(ioaddr + INT_MASK_REG);
-                               outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
-                               insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2);
-                               outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
-                       }
-
-
-                       skb->protocol = eth_type_trans(skb,dev);
-                       netif_rx(skb);
-                       lp->stats.rx_packets++;
-                       lp->stats.rx_bytes += rcv_size;
-               }
-               else { /* Not sure will ever reach here,
-                         I set the 595 to discard bad received frames */
-                       lp->stats.rx_errors++;
-                       if (rcv_status & 0x0100)
-                               lp->stats.rx_over_errors++;
-                       else if (rcv_status & 0x0400)
-                               lp->stats.rx_frame_errors++;
-                       else if (rcv_status & 0x0800)
-                               lp->stats.rx_crc_errors++;
-                       printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
-                               dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
-               }
-               if (rcv_status & 0x1000)
-                       lp->stats.rx_length_errors++;
-               if (--boguscount == 0)
-                       break;
-
-               rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
-               lp->rx_start = rcv_next_frame;
-               outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
-               rcv_event = inw(ioaddr + IO_PORT);
-
-       }
+         rcv_status = inw(ioaddr + IO_PORT); 
+         rcv_next_frame = inw(ioaddr + IO_PORT);
+         rcv_size = inw(ioaddr + IO_PORT); 
+
+         if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) {
+           /* Malloc up new buffer. */
+           struct sk_buff *skb;
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+           lp->stats.rx_bytes+=rcv_size;
+#endif                        
+           rcv_size &= 0x3fff;
+           skb = dev_alloc_skb(rcv_size+5);
+           if (skb == NULL) {
+             printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+             lp->stats.rx_dropped++;
+             break;
+           }
+           skb->dev = dev;
+           skb_reserve(skb,2);
+
+           if (lp->version == LAN595)
+             insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
+           else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+             unsigned short temp = inb(ioaddr + INT_MASK_REG);
+             outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+             insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), 
+                  (rcv_size + 3) >> 2);
+             outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+           }
+       
+           skb->protocol = eth_type_trans(skb,dev);    
+           netif_rx(skb);
+           lp->stats.rx_packets++;
+         }
+         else { /* Not sure will ever reach here, 
+                   I set the 595 to discard bad received frames */
+           lp->stats.rx_errors++;
+           if (rcv_status & 0x0100)
+             lp->stats.rx_over_errors++;
+           else if (rcv_status & 0x0400)
+             lp->stats.rx_frame_errors++;
+           else if (rcv_status & 0x0800)
+             lp->stats.rx_crc_errors++;
+           printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", 
+                  dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
+         }
+         if (rcv_status & 0x1000)
+           lp->stats.rx_length_errors++;
+         if (--boguscount == 0)
+           break;
+         
+         rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
+         lp->rx_start = rcv_next_frame;
+         outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
+         rcv_event = inw(ioaddr + IO_PORT);
+         
+       } 
        if (rcv_car == 0)
-               rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff;
+         rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff;
        outw(rcv_car - 1, ioaddr + RCV_STOP);
 
        if (net_debug > 5)
-               printk("eepro: exiting eepro_rx routine.\n");
+         printk(KERN_DEBUG "eepro: exiting eepro_rx routine.\n");
 }
 
 static void
@@ -1204,80 +1576,118 @@ eepro_transmit_interrupt(struct device *dev)
 {
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
        short ioaddr = dev->base_addr;
-       short boguscount = 20;
+       short boguscount = 20; 
        short xmt_status;
-
-       while (lp->tx_start != lp->tx_end) {
-
-               outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
-               xmt_status = inw(ioaddr+IO_PORT);
-               if ((xmt_status & TX_DONE_BIT) == 0) break;
-
-               xmt_status = inw(ioaddr+IO_PORT);
-               lp->tx_start = inw(ioaddr+IO_PORT);
-
-               dev->tbusy = 0;
-               mark_bh(NET_BH);
-
-               if (xmt_status & 0x2000)
-                       lp->stats.tx_packets++;
-               else {
-                       lp->stats.tx_errors++;
-                       if (xmt_status & 0x0400)
-                               lp->stats.tx_carrier_errors++;
-                       printk("%s: XMT status = %#x\n",
-                               dev->name, xmt_status);
-               }
-               if (xmt_status & 0x000f) {
-                       lp->stats.collisions += (xmt_status & 0x000f);
-               }
-               if ((xmt_status & 0x0040) == 0x0) {
-                       lp->stats.tx_heartbeat_errors++;
-               }
-
-               if (--boguscount == 0)
-                       break;
+       
+       /*
+       if (dev->tbusy == 0) {
+         printk("%s: transmit_interrupt called with tbusy = 0 ??\n",
+                dev->name);
+         printk(KERN_DEBUG "%s: transmit_interrupt called with tbusy = 0 ??\n",
+                dev->name);
+       }
+       */
+       while (lp->tx_start != lp->tx_end) { 
+         outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); 
+         xmt_status = inw(ioaddr+IO_PORT);
+         if ((xmt_status & TX_DONE_BIT) == 0) break;
+
+         xmt_status = inw(ioaddr+IO_PORT); 
+         lp->tx_start = inw(ioaddr+IO_PORT);
+
+         dev->tbusy = 0;
+         mark_bh(NET_BH);
+
+         if (xmt_status & 0x2000)
+           lp->stats.tx_packets++; 
+         else {
+           lp->stats.tx_errors++;
+           if (xmt_status & 0x0400)
+             lp->stats.tx_carrier_errors++;
+           printk("%s: XMT status = %#x\n",
+                  dev->name, xmt_status);
+           printk(KERN_DEBUG "%s: XMT status = %#x\n",
+                  dev->name, xmt_status);
+         }
+         if (xmt_status & 0x000f) {
+           lp->stats.collisions += (xmt_status & 0x000f);
+         }
+         if ((xmt_status & 0x0040) == 0x0) {
+           lp->stats.tx_heartbeat_errors++;
+         }
+         
+         if (--boguscount == 0)
+           break;  
        }
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_eepro = {
-       devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-       0, 0, 0, 0,
-       0, 0,
-       0, 0, 0, NULL, eepro_probe };
+#define MAX_EEPRO 8
+static char devicename[MAX_EEPRO][9];
+static struct device dev_eepro[MAX_EEPRO];
 
-static int io = 0x200;
-static int irq = 0;
-static int mem = (RCV_RAM/1024);       /* Size of the rx buffer in KB */
+static int io[MAX_EEPRO] = {
+#ifdef PnPWakeup
+  0x210,  /*: default for PnP enabled FX chips */
+#else
+  0x200,  /* Why? */
+#endif
+  -1, -1, -1, -1, -1, -1, -1};
+static int irq[MAX_EEPRO] = {0, 0, 0, 0, 0, 0, 0, 0};
+static int mem[MAX_EEPRO] = {  /* Size of the rx buffer in KB */
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024),
+  (RCV_RAM/1024)
+};
 
+static int n_eepro = 0;
+/* For linux 2.1.xx */
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
+MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(mem, "i");
+#endif 
 
-int
-init_module(void)
+int init_module(void)
 {
-       if (io == 0)
+       if (io[0] == 0)
                printk("eepro: You should not use auto-probing with insmod!\n");
-       dev_eepro.base_addr = io;
-       dev_eepro.irq       = irq;
-       dev_eepro.mem_end   = mem;
-
-       if (register_netdev(&dev_eepro) != 0)
-               return -EIO;
-       return 0;
+       while (n_eepro < MAX_EEPRO && io[n_eepro] >= 0) {
+               struct device *d = &dev_eepro[n_eepro];
+               d->name         = devicename[n_eepro]; /* inserted by drivers/net/net_init.c */
+               d->mem_end      = mem[n_eepro];
+               d->base_addr    = io[n_eepro];
+               d->irq          = irq[n_eepro];
+               d->init         = eepro_probe;
+
+               if (register_netdev(d) == 0)
+                       n_eepro++;
+       }
+       
+       return n_eepro ? 0 : -ENODEV;
 }
 
 void
 cleanup_module(void)
 {
-       unregister_netdev(&dev_eepro);
-       kfree_s(dev_eepro.priv,sizeof(struct eepro_local));
-       dev_eepro.priv=NULL;
-
-       /* If we don't do this, we can't re-insmod it later. */
-       release_region(dev_eepro.base_addr, EEPRO_IO_EXTENT);
+       int i;
+       
+       for (i=0; i<n_eepro; i++) {
+               struct device *d = &dev_eepro[i];
+               unregister_netdev(d);
+               kfree_s(d->priv,sizeof(struct eepro_local));
+               d->priv=NULL;
+
+               /* If we don't do this, we can't re-insmod it later. */
+               release_region(d->base_addr, EEPRO_IO_EXTENT);
+               
+       }
 }
 #endif /* MODULE */
index 2aaa087a1919ee284ecca12bdbf48587b62afecf..023a4b1b6ba7cdafffb9b235ab53055c523684d4 100644 (file)
@@ -13,8 +13,8 @@ fi
     
 tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX
 tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX
-tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR
-tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP
+dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_PARPORT
+dep_tristate 'BAYCOM epp driver for AX.25' CONFIG_BAYCOM_EPP $CONFIG_PARPORT
 
 tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
 if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
index 258c5c58c47ff09a071097388602c368268e7508..b2358447d2b3ff4561812a1f6f7385ed2dabdd95 100644 (file)
@@ -41,6 +41,7 @@
 /*****************************************************************************/
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/types.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/hdlcdrv.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 /* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
 
 /* make genksyms happy */
 #include <linux/ip.h>
index 4b415d6cca11f5ebc40c6eae3a69e9769a426483..b504bcd51ef245794be6da773db75e63bb8db694 100644 (file)
@@ -2796,9 +2796,9 @@ static int hp100_down_vg_link( struct device *dev )
   time=jiffies+(HZ/4);
   do{
     if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
-  } while (time>jiffies);
+  } while (time_after(time, jiffies));
 
-  if ( jiffies >= time )       /* no signal->no logout */
+  if ( time_before_eq(jiffies, time) )       /* no signal->no logout */
     return 0;
 
   /* Drop the VG Link by clearing the link up cmd and load addr.*/
@@ -2810,10 +2810,10 @@ static int hp100_down_vg_link( struct device *dev )
   time=jiffies+(HZ/2);
   do{
     if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break;
-  } while(time>jiffies);
+  } while(time_after(time, jiffies));
 
 #ifdef HP100_DEBUG
-  if (jiffies>=time)
+  if (time_before_eq(jiffies, time))
     printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name);
 #endif
 
@@ -2848,7 +2848,7 @@ static int hp100_down_vg_link( struct device *dev )
       time=jiffies+(HZ*5);
       do{
         if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break;
-      } while(time>jiffies);
+      } while(time_after(time, jiffies));
 
       hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */
       hp100_outl(savelan, 10_LAN_CFG_1);
@@ -2857,9 +2857,9 @@ static int hp100_down_vg_link( struct device *dev )
   time=jiffies+(3*HZ); /* Timeout 3s */
   do {
     if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break;
-  } while (time>jiffies);
+  } while (time_after(time, jiffies));
   
-  if(time<=jiffies)
+  if(time_before_eq(time, jiffies))
     {
 #ifdef HP100_DEBUG
       printk( "hp100: %s: down_vg_link: timeout\n", dev->name );
@@ -2868,7 +2868,7 @@ static int hp100_down_vg_link( struct device *dev )
     }
   
   time=jiffies+(2*HZ); /* This seems to take a while.... */
-  do {} while (time>jiffies);
+  do {} while (time_after(time, jiffies));
   
   return 0;
 }
@@ -2918,7 +2918,7 @@ static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
       time = jiffies + (HZ/10); 
       do {
         if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break;
-      } while (time>jiffies);
+      } while (time_after(time, jiffies));
 
       /* Start an addressed training and optionally request promiscuous port */
       if ( (dev->flags) & IFF_PROMISC )
@@ -2955,9 +2955,9 @@ static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
       time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */
       do {
         if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break;
-      } while ( jiffies < time );
+      } while ( time_before(jiffies, time) );
       
-      if ( jiffies >= time )
+      if ( time_after_eq(jiffies, time) )
        {
 #ifdef HP100_DEBUG_TRAINING
          printk( "hp100: %s: Link cable status not ok? Training aborted.\n", dev->name );
@@ -2979,11 +2979,11 @@ static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin )
 #endif
                break;
              }
-         } while ( time > jiffies );
+         } while ( time_after(time, jiffies) );
        }
       
       /* If LINK_UP_ST is set, then we are logged into the hub. */
-      if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) )
+      if ( time_before_eq(jiffies, time) && (val & HP100_LINK_UP_ST) )
         {
 #ifdef HP100_DEBUG_TRAINING
           printk( "hp100: %s: Successfully logged into the HUB.\n", dev->name);
index 91666827e4100228d3e11b99f1f530dd79b9f60d..2f118d32813e8971930862ac41b5ade60aec921d 100644 (file)
  *               - Make sure other end is OK, before sending a packet.
  *               - Fix immediate timer problem.
  *
+ *             Al Viro
+ *               - Changed {enable,disable}_irq handling to make it work
+ *                 with new ("stack") semantics.
+ *
  *             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 the Free Software Foundation; either version
@@ -120,6 +124,9 @@ static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
+#define ENABLE(irq) enable_irq(irq)
+#define DISABLE(irq) disable_irq(irq)
+
 /* In micro second */
 #define PLIP_DELAY_UNIT                   1
 
@@ -333,6 +340,7 @@ static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
 #define OK        0
 #define TIMEOUT   1
 #define ERROR     2
+#define HS_TIMEOUT     3
 
 typedef int (*plip_func)(struct device *dev, struct net_local *nl,
                         struct plip_local *snd, struct plip_local *rcv);
@@ -371,13 +379,22 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
                      int error)
 {
        unsigned char c0;
+       /*
+        * This is tricky. If we got here from the beginning of send (either
+        * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's
+        * already disabled. With the old variant of {enable,disable}_irq()
+        * extra disable_irq() was a no-op. Now it became mortal - it's
+        * unbalanced and thus we'll never re-enable IRQ (until rmmod plip,
+        * that is). So we have to treat HS_TIMEOUT and ERROR from send
+        * in a special way.
+        */
 
        spin_lock_irq(&nl->lock);
        if (nl->connection == PLIP_CN_SEND) {
 
                if (error != ERROR) { /* Timeout */
                        nl->timeout_count++;
-                       if ((snd->state == PLIP_PK_TRIGGER
+                       if ((error == HS_TIMEOUT
                             && nl->timeout_count <= 10)
                            || nl->timeout_count <= 3) {
                                spin_unlock_irq(&nl->lock);
@@ -387,7 +404,8 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
                        c0 = inb(PAR_STATUS(dev));
                        printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",
                               dev->name, snd->state, c0);
-               }
+               } else
+                       error = HS_TIMEOUT;
                nl->enet_stats.tx_errors++;
                nl->enet_stats.tx_aborted_errors++;
        } else if (nl->connection == PLIP_CN_RECEIVE) {
@@ -419,8 +437,10 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
                snd->skb = NULL;
        }
        spin_unlock_irq(&nl->lock);
-       disable_irq(dev->irq);
-       synchronize_irq();
+       if (error == HS_TIMEOUT) {
+               DISABLE(dev->irq);
+               synchronize_irq();
+       }
        outb(PAR_INTR_OFF, PAR_CONTROL(dev));
        dev->tbusy = 1;
        nl->connection = PLIP_CN_ERROR;
@@ -498,7 +518,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
 
        switch (rcv->state) {
        case PLIP_PK_TRIGGER:
-               disable_irq(dev->irq);
+               DISABLE(dev->irq);
                /* Don't need to synchronize irq, as we can safely ignore it */
                outb(PAR_INTR_OFF, PAR_CONTROL(dev));
                dev->interrupt = 0;
@@ -518,7 +538,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
                                nl->connection = PLIP_CN_SEND;
                                queue_task(&nl->deferred, &tq_timer);
                                outb(PAR_INTR_ON, PAR_CONTROL(dev));
-                               enable_irq(dev->irq);
+                               ENABLE(dev->irq);
                                return OK;
                        }
                } else {
@@ -592,13 +612,13 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
                        queue_task(&nl->immediate, &tq_immediate);
                        mark_bh(IMMEDIATE_BH);
                        outb(PAR_INTR_ON, PAR_CONTROL(dev));
-                       enable_irq(dev->irq);
+                       ENABLE(dev->irq);
                        return OK;
                } else {
                        nl->connection = PLIP_CN_NONE;
                        spin_unlock_irq(&nl->lock);
                        outb(PAR_INTR_ON, PAR_CONTROL(dev));
-                       enable_irq(dev->irq);
+                       ENABLE(dev->irq);
                        return OK;
                }
        }
@@ -674,7 +694,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
        switch (snd->state) {
        case PLIP_PK_TRIGGER:
                if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)
-                       return TIMEOUT;
+                       return HS_TIMEOUT;
 
                /* Trigger remote rx interrupt. */
                outb(0x08, data_addr);
@@ -691,12 +711,16 @@ plip_send_packet(struct device *dev, struct net_local *nl,
                        c0 = inb(PAR_STATUS(dev));
                        if (c0 & 0x08) {
                                spin_unlock_irq(&nl->lock);
-                               disable_irq(dev->irq);
+                               DISABLE(dev->irq);
                                synchronize_irq();
                                if (nl->connection == PLIP_CN_RECEIVE) {
                                        /* Interrupted.
                                           We don't need to enable irq,
                                           as it is soon disabled.    */
+                                       /* Yes, we do. New variant of
+                                          {enable,disable}_irq *counts*
+                                          them.  -- AV  */
+                                       ENABLE(dev->irq);
                                        nl->enet_stats.collisions++;
                                        return OK;
                                }
@@ -711,7 +735,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
                        spin_unlock_irq(&nl->lock);
                        if (--cx == 0) {
                                outb(0x00, data_addr);
-                               return TIMEOUT;
+                               return HS_TIMEOUT;
                        }
                }
 
@@ -760,7 +784,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
                nl->is_deferred = 1;
                queue_task(&nl->deferred, &tq_timer);
                outb(PAR_INTR_ON, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
+               ENABLE(dev->irq);
                return OK;
        }
        return OK;
@@ -800,7 +824,7 @@ plip_error(struct device *dev, struct net_local *nl,
                dev->tbusy = 0;
                dev->interrupt = 0;
                outb(PAR_INTR_ON, PAR_CONTROL(dev));
-               enable_irq(dev->irq);
+               ENABLE(dev->irq);
                mark_bh(NET_BH);
        } else {
                nl->is_deferred = 1;
@@ -1000,7 +1024,7 @@ plip_close(struct device *dev)
 
        dev->tbusy = 1;
        dev->start = 0;
-       disable_irq(dev->irq);
+       DISABLE(dev->irq);
        synchronize_irq();
 
 #ifdef NOTDEF
index c8740a8d105b538e2d33413b93c19c79d8eaa124..32f22e14d9f165af4b09d6206ee06cebf302a221 100644 (file)
@@ -248,7 +248,7 @@ int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char
        temp += z80_addr & SDLA_ADDR_MASK;
        
        resp = ~resp1;
-       while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
+       while (time_before(jiffies, done) && (resp != resp1) && (!resp2 || (resp != resp2)))
        {
                if (jiffies != now)
                {
@@ -257,7 +257,7 @@ int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char
                        resp = *temp;
                }
        }
-       return(jiffies < done ? jiffies - start : -1);
+       return(time_before(jiffies, done) ? jiffies - start : -1);
 }
 
 /* constants for Z80 CPU speed */
@@ -444,7 +444,7 @@ static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags,
 
        waiting = 1;
        len = 0;
-       while (waiting && (jiffies <= jiffs))
+       while (waiting && time_before_eq(jiffies, jiffs))
        {
                if (waiting++ % 3) 
                {
index b571dc28c1f6dae9942e8eb4cf45329a16291ee0..c01c31d5ba4f6e7a835e014841098c2c05525284 100644 (file)
@@ -247,10 +247,10 @@ __initfunc(static int seeq8005_probe1(struct device *dev, int ioaddr))
                        outw(0x5a5a, SEEQ_BUFFER);
                }
                j=jiffies+HZ;
-               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && jiffies < j )
+               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
                        mb();
                outw( 0 , SEEQ_DMAAR);
-               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < j+HZ)
+               while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
                        mb();
                if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
                        outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
@@ -707,7 +707,7 @@ static void hardware_send_packet(struct device * dev, char *buf, int length)
        
        /* drain FIFO */
        tmp = jiffies;
-       while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies < tmp + HZ))
+       while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies - tmp < HZ))
                mb();
        
        /* doit ! */
@@ -729,7 +729,7 @@ inline void wait_for_buffer(struct device * dev)
        int status;
        
        tmp = jiffies + HZ;
-       while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < tmp)
+       while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
                mb();
                
        if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
index f86acd1fbef943317775309ef769f10789e80faa..7a4920f9f08b0870807da5660f48f4c91dbf91c3 100644 (file)
@@ -1020,7 +1020,7 @@ static void sktr_timer_chk(unsigned long data)
                return;
 
        sktr_chk_outstanding_cmds(dev);
-       if(tp->LastSendTime + SEND_TIMEOUT < jiffies
+       if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies)
                && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy))
        {
                /* Anything to send, but stalled to long */
@@ -1526,11 +1526,11 @@ static void sktr_wait(unsigned long time)
 {
        long tmp;
 
-       tmp = time/(1000000/HZ);
+       tmp = jiffies + time/(1000000/HZ);
        do {
-               current->state          = TASK_INTERRUPTIBLE;
+               current->state          = TASK_INTERRUPTIBLE;
                tmp = schedule_timeout(tmp);
-       } while(tmp);
+       } while(time_after(tmp, jiffies));
 
        return;
 }
index 04ddcef2000b48607344fdaa651d56354e581f92..fb32f3da5d3211fc9db3a3d0e590a2ecc90f05b3 100644 (file)
@@ -1,13 +1,13 @@
-/* tulip.c: A DEC 21040-family ethernet driver for linux. */
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
 /*
-   NOTICE: THIS IS THE ALPHA TEST VERSION!
-       Written 1994-1997 by Donald Becker.
+       Written 1994-1998 by Donald Becker.
 
        This software may be used and distributed according to the terms
        of the GNU Public License, incorporated herein by reference.
 
-       This driver is for the SMC EtherPower PCI ethernet adapter.
-       It should work with most other DEC 21*40-based ethercards.
+       This driver is for the Digital "Tulip" ethernet adapter interface.
+       It should work with most DEC 21*4*-based chips/ethercards, as well as
+       PNIC and MXIC chips.
 
        The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
        Center of Excellence in Space Data and Information Sciences
        http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
 */
 
-static const char *version = "tulip.c:v0.83 10/19/97 becker@cesdis.gsfc.nasa.gov\n";
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values. */
 
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
 /* Used to pass the full-duplex flag, etc. */
-static int full_duplex[8] = {0, };
-static int options[8] = {0, };
-static int mtu[8] = {0, };                     /* Jumbo MTU for interfaces. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, };                     /* Jumbo MTU for interfaces. */
+
+/*  The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+       "10baseT", "10base2", "AUI", "100baseTx",
+       "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+       "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+       "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
 
 /* Set if the PCI BIOS detects the chips on a multiport board backwards. */
 #ifdef REVERSE_PROBE_ORDER
@@ -38,40 +51,20 @@ static int reverse_probe = 0;
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE   16
-#define RX_RING_SIZE   16
+#define RX_RING_SIZE   32
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #ifdef __alpha__
-static const int rx_copybreak = 1518;
+static int rx_copybreak = 1518;
 #else
-static const int rx_copybreak = 100;
+static int rx_copybreak = 100;
 #endif
 
-/* The following example shows how to always use the 10base2 port. */
-#ifdef notdef
-#define TULIP_DEFAULT_MEDIA 1          /* 1 == 10base2 */
-#define TULIP_NO_MEDIA_SWITCH          /* Don't switch from this port */
-#endif
-
-/* Define to force full-duplex operation on all Tulip interfaces. */
-/* #define  TULIP_FULL_DUPLEX 1 */
-
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((2000*HZ)/1000)
+#define TX_TIMEOUT  (4*HZ)
 
-#include <linux/config.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -82,6 +75,8 @@ static const int rx_copybreak = 100;
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/bios32.h>
+
 #include <asm/processor.h>             /* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -106,28 +101,13 @@ static const int rx_copybreak = 100;
 #define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
 #endif
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
-#ifdef MODULE
-#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
-char kernel_version[] = UTS_RELEASE;
-#endif
-#else
-#undef MOD_INC_USE_COUNT
-#define MOD_INC_USE_COUNT
-#undef MOD_DEC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-#endif /* 1.3.38 */
-
 #if (LINUX_VERSION_CODE >= 0x10344)
 #define NEW_MULTICAST
 #include <linux/delay.h>
 #endif
 #if (LINUX_VERSION_CODE >= 0x20100)
-#ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
 #endif
-#endif
 #ifdef SA_SHIRQ
 #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
 #else
@@ -135,8 +115,8 @@ char kernel_version[] = UTS_RELEASE;
 #endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
+#define hard_smp_processor_id() smp_processor_id()
 #define test_and_set_bit(val, addr) set_bit(val, addr)
-#include <linux/bios32.h>
 #endif
 
 /* This my implementation of shared IRQs, now only used for 1.2.13. */
@@ -167,7 +147,7 @@ I. Board Compatibility
 
 This device driver is designed for the DECchip "Tulip", Digital's
 single-chip ethernet controllers for PCI.  Supported members of the family
-are the 21040, 21041, 21140, 21140A and 21142.  These chips are used on
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  These chips are used on
 many PCI boards including the SMC EtherPower series.
 
 
@@ -268,44 +248,65 @@ register of the set CSR12-15 written.  Hmmm, now how is that possible?  */
 
 #ifndef PCI_VENDOR_ID_LITEON
 #define PCI_VENDOR_ID_LITEON   0x11AD
-#define PCI_DEVICE_ID_PNIC             0x0002
-#define PCI_DEVICE_ID_PNIC_X   0x0168
-#else
-/* Now PCI_VENDOR_ID_LITEON is defined, but device IDs have different names */
-#define PCI_DEVICE_ID_PNIC             PCI_DEVICE_ID_LITEON_LNE100TX
-#define PCI_DEVICE_ID_PNIC_X   0x0168
+#endif
+
+#ifndef PCI_VENDOR_ID_MXIC
+#define        PCI_VENDOR_ID_MXIC              0x10d9
+#define PCI_DEVICE_ID_MX98713  0x0512
+#define PCI_DEVICE_ID_MX98715  0x0531
+#define PCI_DEVICE_ID_MX98725  0x0531
 #endif
 
 /* The rest of these values should never change. */
 
 static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
 
 /* A table describing the chip types. */
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
 static struct tulip_chip_table {
-  int device_id;
-  char *chip_name;
-  int flags;
-  void (*media_timer)(unsigned long data);
+       int vendor_id, device_id;
+       char *chip_name;
+       int io_size;
+       int valid_intrs;                        /* CSR7 interrupt enable settings */
+       int flags;
+       void (*media_timer)(unsigned long data);
 } tulip_tbl[] = {
-  { PCI_DEVICE_ID_DEC_TULIP, "Digital DS21040 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DS21041 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 0, tulip_timer },
-  { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 0, tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
+       "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
+       "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
+       "Digital DS21140 Tulip", 128, 0x0001ebef,
+       HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
+       tulip_timer },
+  { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
+       "Digital DS21142/3 Tulip", 256, 0x0801fbff,
+       HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
+  { PCI_VENDOR_ID_LITEON, 0x0002,
+       "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
+       "Macronix 98713 PMAC", 128, 0x0001ebef,
+       HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
+       "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+  { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
+       "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+  { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+       HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
   {0, 0, 0, 0},
 };
 /* This matches the table above. */
-enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, LC82C168};
-
-static const char * const medianame[] = {
-  "10baseT", "10base2", "AUI", "100baseTx",
-  "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
-  "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
-  "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
-};
-/* A full-duplex map for above. */
-static const char media_fd[] =
-{0,0,0,0,  0xff,0xff,0,0,  0xff,0,0xff,0x01, 0,0,0xff,0 };
+enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+                        LC82C168, MX98713, MX98715, MX98725};
+
+/* A full-duplex map for media types. */
+enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+                 MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
 /* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
 static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
 static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
@@ -325,9 +326,9 @@ enum tulip_offsets {
 /* The bits in the CSR5 status registers, mostly interrupt sources. */
 enum status_bits {
        TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+       NormalIntr=0x10000, AbnormalIntr=0x8000,
        RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
-       TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02,
-       TxIntr=0x01,
+       TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
 };
 
 /* The Tulip Rx and Tx buffer descriptors. */
@@ -352,7 +353,7 @@ struct medialeaf {
 struct mediatable {
        u16 defaultmedia;
        u8 leafcount, csr12dir;                         /* General purpose pin directions. */
-       unsigned has_mii:1;
+       unsigned has_mii:1, has_nonmii:1;
        struct medialeaf mleaf[0];
 };
 
@@ -360,7 +361,6 @@ struct mediainfo {
        struct mediainfo *next;
        int info_type;
        int index;
-       struct non_mii { char media; unsigned char csr12val; char bitnum, flags;}  non_mii;
        unsigned char *info;
 };
 
@@ -384,32 +384,38 @@ struct tulip_private {
        struct enet_statistics stats;
 #endif
        struct timer_list timer;        /* Media selection timer. */
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-       int fc_bit;
+       int interrupt;                          /* In-interrupt flag. */
+#ifdef SMP_CHECK
+       int smp_proc_id;                        /* Which processor in IRQ handler. */
 #endif
        unsigned int cur_rx, cur_tx;            /* The next free ring entry */
        unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
        unsigned int tx_full:1;                         /* The Tx queue is full. */
        unsigned int full_duplex:1;                     /* Full-duplex operation requested. */
        unsigned int full_duplex_lock:1;
+       unsigned int fake_addr:1;                       /* Multiport board faked address. */
        unsigned int default_port:4;            /* Last dev->if_port value. */
        unsigned int media2:4;                          /* Secondary monitored media port. */
        unsigned int medialock:1;                       /* Don't sense media type. */
        unsigned int mediasense:1;                      /* Media sensing in progress. */
        unsigned int csr6;                                      /* Current CSR6 control settings. */
        unsigned char eeprom[128];                      /* Serial EEPROM contents. */
-       signed char phys[4];                            /* MII device addresses. */
+       u16 to_advertise;                                       /* NWay capabilities advertised.  */
+       u16 advertising[4];
+       signed char phys[4], mii_cnt;           /* MII device addresses. */
        struct mediatable *mtable;
        int cur_index;                                          /* Current media index. */
-       unsigned char pci_bus, pci_device_fn;
+       unsigned char pci_bus, pci_dev_fn;
        int pad0, pad1;                                         /* Used for 8-byte alignment */
 };
 
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+                                                                  struct device *dev,
                                                                   int chip_id, int options);
 static void parse_eeprom(struct device *dev);
-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct device *dev, int phy_id, int location);
+static void mdio_write(struct device *dev, int phy_id, int location, int value);
 static void select_media(struct device *dev, int startup);
 static int tulip_open(struct device *dev);
 static void tulip_timer(unsigned long data);
@@ -420,24 +426,19 @@ static int tulip_rx(struct device *dev);
 static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
 static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
 #ifdef NEW_MULTICAST
-static void set_multicast_list(struct device *dev);
+static void set_rx_mode(struct device *dev);
 #else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-#include <linux/if_arp.h>
-#include <net/ip.h>
-
-static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst);
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
 #endif
 
 \f
 
-#ifdef MODULE
 /* A list of all installed Tulip devices, for removing the driver module. */
 static struct device *root_tulip_dev = NULL;
-#endif
 
 /* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
    but now receives directly into full-sized skbuffs that are allocated
@@ -449,121 +450,118 @@ int tulip_probe(struct device *dev)
 {
        int cards_found = 0;
        static int pci_index = 0;       /* Static, for multiple probe calls. */
+       unsigned char pci_bus, pci_device_fn;
 
        /* 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 with the current structure.  So instead we detect just the
           Tulip cards in slot order. */
 
-       if (pci_present()) {
-               unsigned char pci_bus, pci_device_fn;
-
-               for (;pci_index < 0xff; pci_index++) {
-                       unsigned char pci_latency;
 #if LINUX_VERSION_CODE >= 0x20155
-                       unsigned int pci_irq_line;
-                       struct pci_dev *pdev;
+       if (! pci_present())
+               return -ENODEV;
 #else
-                       unsigned char pci_irq_line;
-#endif
-                       unsigned short pci_command, vendor, device;
-                       unsigned int pci_ioaddr, chip_idx = 0;
-
-                       if (pcibios_find_class
-                               (PCI_CLASS_NETWORK_ETHERNET << 8,
-                                reverse_probe ? 0xfe - pci_index : pci_index,
-                                &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
-                               if (reverse_probe)
-                                       continue;
-                               else
-                                       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);
+       if (! pcibios_present())
+               return -ENODEV;
+#endif
+       for (;pci_index < 0xff; pci_index++) {
+               u16 vendor, device, pci_command, new_command;
+               u32 pci_ioaddr;
+               int chip_idx = 0;
+
+               if (pcibios_find_class
+                       (PCI_CLASS_NETWORK_ETHERNET << 8,
+                        reverse_probe ? 0xfe - pci_index : pci_index,
+                        &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+                       if (reverse_probe)
+                               continue;
+                       else
+                               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; tulip_tbl[chip_idx].chip_name; chip_idx++)
+                       if (vendor == tulip_tbl[chip_idx].vendor_id  &&
+                               device == tulip_tbl[chip_idx].device_id)
+                               break;
+               if (tulip_tbl[chip_idx].chip_name == 0) {
+                       if (vendor == PCI_VENDOR_ID_DEC  ||
+                               vendor == PCI_VENDOR_ID_LITEON)
+                               printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
+                                          " %4.4x %4.4x"" detected: not configured.\n",
+                                          vendor, device);
+                       continue;
+               }
 #if LINUX_VERSION_CODE >= 0x20155
-                       pdev = pci_find_slot(pci_bus, pci_device_fn);
-                       pci_irq_line = pdev->irq;
-                       pci_ioaddr = pdev->base_address[0];
+               pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
 #else
-                       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);
+               pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+                                                                 &pci_ioaddr);
 #endif
-                       /* Remove I/O space marker in bit 0. */
-                       pci_ioaddr &= ~3;
+               /* Remove I/O space marker in bit 0. */
+               pci_ioaddr &= ~3;
 
-                       if (vendor != PCI_VENDOR_ID_DEC
-                               && vendor != PCI_VENDOR_ID_LITEON)
-                               continue;
-                       if (vendor == PCI_VENDOR_ID_LITEON)
-                               device = PCI_DEVICE_ID_PNIC_X;
-
-                       for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
-                               if (device == tulip_tbl[chip_idx].device_id)
-                                       break;
-                       if (tulip_tbl[chip_idx].chip_name == 0) {
-                               printk(KERN_INFO "Unknown Digital PCI ethernet chip type"
-                                          " %4.4x"" detected: not configured.\n", device);
-                               continue;
-                       }
-                       if (tulip_debug > 2)
-                               printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n",
-                                          pci_ioaddr, pci_irq_line);
-
-                       if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE))
-                               continue;
+               if (tulip_debug > 2)
+                       printk(KERN_DEBUG "Found %s at I/O %#x.\n",
+                                  tulip_tbl[chip_idx].chip_name, pci_ioaddr);
+
+               if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
+                       continue;
+
+               pcibios_read_config_word(pci_bus, pci_device_fn,
+                                                                PCI_COMMAND, &pci_command);
+               new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+               if (pci_command != new_command) {
+                       printk(KERN_INFO "  The PCI BIOS has not enabled this"
+                                  " device!  Updating PCI command %4.4x->%4.4x.\n",
+                                  pci_command, new_command);
+                       pcibios_write_config_word(pci_bus, pci_device_fn,
+                                                                         PCI_COMMAND, new_command);
+               }
 
-#ifdef MODULE
-                       dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
-                                                cards_found);
-#else
-                       dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1);
-#endif
+               dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);
 
-                       if (dev) {
-                         /* Get and check the bus-master and latency values. */
-                         pcibios_read_config_word(pci_bus, pci_device_fn,
-                                                                          PCI_COMMAND, &pci_command);
-                         if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-                               printk(KERN_INFO "  PCI Master Bit has not been set! Setting...\n");
-                               pci_command |= PCI_COMMAND_MASTER;
-                               pcibios_write_config_word(pci_bus, pci_device_fn,
-                                                                                 PCI_COMMAND, pci_command);
-                         }
-                         pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                                                          PCI_LATENCY_TIMER, &pci_latency);
-                         if (pci_latency < 10) {
-                               printk(KERN_INFO "  PCI latency timer (CFLT) is unreasonably"
-                                          " low at %d.  Setting to 64 clocks.\n", pci_latency);
+               /* Get and check the bus-master and latency values. */
+               if (dev) {
+                       unsigned char pci_latency;
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                                                        PCI_LATENCY_TIMER, &pci_latency);
+                       if (pci_latency < 10) {
+                               printk(KERN_INFO "  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);
-                         } else if (tulip_debug > 1)
-                               printk(KERN_INFO "  PCI latency timer (CFLT) is %#x.\n",
-                                          pci_latency);
-                         /* Bring the 21143 out power-down mode. */
-                         if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+                       } else if (tulip_debug > 1)
+                               printk(KERN_INFO "  PCI latency timer (CFLT) is %#x, "
+                                          " PCI command is %4.4x.\n",
+                                          pci_latency, new_command);
+                       /* Bring the 21143 out power-down mode. */
+                       if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
                                pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                                                                       0x40, 0x40000000);
-                         dev = 0;
-                         cards_found++;
-                       }
+                                                                                  0x40, 0x40000000);
+                       dev = 0;
+                       cards_found++;
                }
        }
 
        return cards_found ? 0 : -ENODEV;
 }
 
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
+                                                                  struct device *dev,
                                                                   int chip_id, int board_idx)
 {
        static int did_version = 0;                     /* Already printed version info. */
        struct tulip_private *tp;
+       long ioaddr;
+       int irq;
        /* See note below on the multiport cards. */
        static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
        static int last_irq = 0;
+       static int multiport_cnt = 0;           /* For four-port boards w/one EEPROM */
        int i;
        unsigned short sum;
 
@@ -572,7 +570,25 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
 
        dev = init_etherdev(dev, 0);
 
-       printk(KERN_INFO "%s: %s at %#3x,",
+#if LINUX_VERSION_CODE >= 0x20155
+       irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
+       ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+#else
+       {
+               u8 pci_irq_line;
+               u32 pci_ioaddr;
+               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);
+               irq = pci_irq_line;
+               ioaddr = pci_ioaddr;
+       }
+#endif
+       /* Remove I/O space marker in bit 0. */
+       ioaddr &= ~3;
+
+       printk(KERN_INFO "%s: %s at %#3lx,",
                   dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
 
        /* Stop the chip's Tx and Rx processes. */
@@ -629,6 +645,10 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                for (i = 0; i < 8; i ++)
                        if (ee_data[i] != ee_data[16+i])
                                sa_offset = 20;
+               if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+                       sa_offset = 2;          /* Grrr, damn Matrox boards. */
+                       multiport_cnt = 4;
+               }
                for (i = 0; i < 6; i ++) {
                        dev->dev_addr[i] = ee_data[i + sa_offset];
                        sum += ee_data[i + sa_offset];
@@ -655,13 +675,15 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                irq = last_irq;
 #endif
        }
+
        for (i = 0; i < 6; i++)
                printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
        printk(", IRQ %d.\n", irq);
        last_irq = irq;
 
        /* We do a request_region() only to register /proc/ioports info. */
-       request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
+       /* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
+       request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
 
        dev->base_addr = ioaddr;
        dev->irq = irq;
@@ -671,11 +693,11 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
        memset(tp, 0, sizeof(*tp));
        dev->priv = tp;
 
-#ifdef MODULE
        tp->next_module = root_tulip_dev;
        root_tulip_dev = dev;
-#endif
 
+       tp->pci_bus = pci_bus;
+       tp->pci_dev_fn = pci_device_fn;
        tp->chip_id = chip_id;
 
 #ifdef TULIP_FULL_DUPLEX
@@ -690,36 +712,64 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
 #endif
 
        /* The lower four bits are the media type. */
-       if (board_idx >= 0) {
-               tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0;
-               if (tp->full_duplex)
-                       tp->full_duplex_lock = 1;
+       if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
                tp->default_port = options[board_idx] & 15;
-               if (tp->default_port)
-                       tp->medialock = 1;
+               if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+                       tp->full_duplex = 1;
                if (mtu[board_idx] > 0)
                        dev->mtu = mtu[board_idx];
        }
+       if (dev->mem_start)
+               tp->default_port = dev->mem_start;
+       if (tp->default_port) {
+               tp->medialock = 1;
+               if (media_cap[tp->default_port] & MediaAlwaysFD)
+                       tp->full_duplex = 1;
+       }
+       if (tp->full_duplex)
+               tp->full_duplex_lock = 1;
 
        /* This is logically part of probe1(), but too complex to write inline. */
-       if (chip_id != DC21040  &&  chip_id != LC82C168)
+       if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
                parse_eeprom(dev);
 
-       if (tp->mtable  &&  tp->mtable->has_mii) {
+       if (media_cap[tp->default_port] & MediaIsMII) {
+               u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+               tp->to_advertise = media2advert[tp->default_port - 9];
+       } else
+               tp->to_advertise = 0x03e1;
+
+       if ((tp->mtable  &&  tp->mtable->has_mii) ||
+               ( ! tp->mtable  &&  (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
                int phy, phy_idx;
                /* Find the connected MII xcvrs.
                   Doing this in open() would allow detecting external xcvrs later,
                   but takes much time. */
                for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
                         phy++) {
-                       int mii_status = mdio_read(ioaddr, phy, 0);
-                       if (mii_status != 0xffff  && mii_status != 0x0000) {
-                               tp->phys[phy_idx++] = phy;
-                               printk(KERN_INFO "%s:  MII transceiver found at MDIO address %d.\n",
-                                          dev->name, phy);
+                       int mii_status = mdio_read(dev, phy, 1);
+                       if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+                               int mii_reg0 = mdio_read(dev, phy, 0);
+                               int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+                               tp->phys[phy_idx] = phy;
+                               tp->advertising[phy_idx++] = reg4;
+                               printk(KERN_INFO "%s:  MII transceiver found at MDIO address "
+                                          "%d, config %4.4x status %4.4x.\n",
+                                          dev->name, phy, mii_reg0, mii_status);
+                               if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
+                                       printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
+                                                  " previously advertising %4.4x.\n",
+                                                  dev->name, reg4, phy, mdio_read(dev, phy, 4));
+                                       mdio_write(dev, phy, 4, reg4);
+                               }
+                               /* Enable autonegotiation: some boards default to off. */
+                               mdio_write(dev, phy, 0, mii_reg0 |
+                                                  (tp->full_duplex ? 0x1100 : 0x1000) |
+                                                  (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
                        }
                }
-               if (phy_idx == 0) {
+               tp->mii_cnt = phy_idx;
+               if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
                        printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
                                   dev->name);
                        tp->phys[0] = 1;
@@ -731,11 +781,11 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
        dev->hard_start_xmit = &tulip_start_xmit;
        dev->stop = &tulip_close;
        dev->get_stats = &tulip_get_stats;
-#ifdef HAVE_MULTICAST
-       dev->set_multicast_list = &set_multicast_list;
+#ifdef HAVE_PRIVATE_IOCTL
+       dev->do_ioctl = &private_ioctl;
 #endif
-#ifdef CONFIG_NET_FASTROUTE
-       dev->accept_fastpath = tulip_accept_fastpath;
+#ifdef HAVE_MULTICAST
+       dev->set_multicast_list = &set_rx_mode;
 #endif
 
        /* Reset the xcvr interface and turn on heartbeat. */
@@ -744,20 +794,37 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
                outl(0x00000000, ioaddr + CSR13);
                outl(0xFFFFFFFF, ioaddr + CSR14);
                outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
-               outl(inl(ioaddr + CSR6) | 0x200, ioaddr + CSR6);
+               outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
                outl(0x0000EF05, ioaddr + CSR13);
                break;
-       case DC21140:  case DC21142:
-               if (tp->mtable)
-                       outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
-               break;
        case DC21040:
                outl(0x00000000, ioaddr + CSR13);
                outl(0x00000004, ioaddr + CSR13);
                break;
+       case DC21140: default:
+               if (tp->mtable)
+                       outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+               break;
+       case DC21142:
+               outl(0x82420200, ioaddr + CSR6);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x0003FFFF, ioaddr + CSR14);
+               outl(0x0008, ioaddr + CSR15);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+               break;
        case LC82C168:
-               outl(0x33, ioaddr + CSR12);
-               outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+               if ( ! tp->mii_cnt) {
+                       outl(0x00420000, ioaddr + CSR6);
+                       outl(0x30, ioaddr + CSR12);
+                       outl(0x0001F078, ioaddr + 0xB8);
+                       outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+               }
+               break;
+       case MX98713: case MX98715: case MX98725:
+               outl(0x00000000, ioaddr + CSR6);
+               outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+               outl(0x00000001, ioaddr + CSR13);
                break;
        }
 
@@ -782,7 +849,9 @@ static struct fixups {
   {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
                                                           0x0000, 0x009E, /* 10baseT */
                                                           0x0903, 0x006D, /* 100baseTx */ }},
-  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x013f,
+  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+                                                                0x0107, 0x8021, /* 100baseFx */
+                                                                0x0108, 0x8021, /* 100baseFx-FD */
                                                                 0x0103, 0x006D, /* 100baseTx */ }},
   {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
                                                           0x1001, 0x009E, /* 10base2, CSR12 0x10*/
@@ -796,9 +865,15 @@ static struct fixups {
   {0, 0, 0, 0, {}}};
 
 static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
- "21142 non-MII PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
 
 #define EEPROM_SIZE 128
+#if defined(__i386__)
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
 static void parse_eeprom(struct device *dev)
 {
        /* The last media info list parsed, for multiport boards.  */
@@ -806,7 +881,7 @@ static void parse_eeprom(struct device *dev)
        static unsigned char *last_ee_data = NULL;
        static int controller_index = 0;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        unsigned char *ee_data = tp->eeprom;
        int i;
 
@@ -870,30 +945,45 @@ static void parse_eeprom(struct device *dev)
        }
 subsequent_board:
 
-       if (tp->chip_id == DC21041) {
+       if (ee_data[27] == 0) {         /* No valid media table. */
+       } else if (tp->chip_id == DC21041) {
                unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
-               short media = *(u16 *)p;
-               int count = p[2];
+               short media;
+               int count;
+
+               media = get_u16(p);
+               p += 2;
+               count = *p++;
 
                printk(KERN_INFO "%s:21041 Media information at %d, default media "
                           "%4.4x (%s).\n", dev->name, ee_data[27], media,
                           media & 0x0800 ? "Autosense" : medianame[media & 15]);
                for (i = 0; i < count; i++) {
-                       unsigned char media_code = p[3 + i*7];
-                       u16 *csrvals = (u16 *)&p[3 + i*7 + 1];
-                       printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
-                                  " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
-                                  dev->name, media_code & 15, medianame[media_code & 15],
-                                  csrvals[0], csrvals[1], csrvals[2]);
+                       unsigned char media_code = *p++;
+                       u16 csrvals[3];
+                       int idx;
+                       for (idx = 0; idx < 3; idx++) {
+                               csrvals[idx] = get_u16(p);
+                               p += 2;
+                       }
+                       if (media_code & 0x40) {
+                               printk(KERN_INFO "%s:  21041 media %2.2x (%s),"
+                                          " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+                                          dev->name, media_code & 15, medianame[media_code & 15],
+                                          csrvals[0], csrvals[1], csrvals[2]);
+                       } else
+                               printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
+                                          dev->name, media_code & 15, medianame[media_code & 15]);
                }
        } else {
                unsigned char *p = (void *)ee_data + ee_data[27];
                unsigned char csr12dir = 0;
                int count;
                struct mediatable *mtable;
-               u16 media = *((u16 *)p)++;
+               u16 media = get_u16(p);
 
-               if (tp->chip_id == DC21140)
+               p += 2;
+               if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
                        csr12dir = *p++;
                count = *p++;
                mtable = (struct mediatable *)
@@ -905,7 +995,7 @@ subsequent_board:
                mtable->defaultmedia = media;
                mtable->leafcount = count;
                mtable->csr12dir = csr12dir;
-               mtable->has_mii = 0;
+               mtable->has_nonmii = mtable->has_mii = 0;
 
                printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
                           media & 0x0800 ? "Autosense" : medianame[media & 15]);
@@ -916,14 +1006,18 @@ subsequent_board:
                                leaf->type = 0;
                                leaf->media = p[0] & 0x3f;
                                leaf->leafdata = p;
+                               if ((p[2] & 0x61) == 0x01)      /* Bogus, but Znyx boards do it. */
+                                       mtable->has_mii = 1;
                                p += 4;
                        } else {
                                leaf->type = p[1];
                                if (p[1] & 1) {
                                        mtable->has_mii = 1;
                                        leaf->media = 11;
-                               } else
+                               } else {
+                                       mtable->has_nonmii = 1;
                                        leaf->media = p[2] & 0x0f;
+                               }
                                leaf->leafdata = p + 2;
                                p += (p[0] & 0x3f) + 1;
                        }
@@ -966,11 +1060,11 @@ subsequent_board:
 #define EE_READ_CMD            (6 << 6)
 #define EE_ERASE_CMD   (7 << 6)
 
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location)
 {
        int i;
        unsigned short retval = 0;
-       int ee_addr = ioaddr + CSR9;
+       long ee_addr = ioaddr + CSR9;
        int read_cmd = location | EE_READ_CMD;
        
        outl(EE_ENB & ~EE_CS, ee_addr);
@@ -1001,6 +1095,16 @@ static int read_eeprom(int ioaddr, int location)
        return retval;
 }
 
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* 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 or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
 /* Read and write the MII registers using software-generated serial
    MDIO protocol.  It is just different enough from the EEPROM protocol
    to not share code.  The maxium data clock rate is 2.5 Mhz. */
@@ -1010,18 +1114,24 @@ static int read_eeprom(int ioaddr, int location)
 #define MDIO_ENB               0x00000         /* Ignore the 0x02000 databook setting. */
 #define MDIO_ENB_IN            0x40000
 #define MDIO_DATA_READ 0x80000
-#ifdef _LINUX_DELAY_H
-#define mdio_delay()   udelay(1)
-#else
-#define mdio_delay()   __SLOW_DOWN_IO
-#endif
 
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(struct device *dev, int phy_id, int location)
 {
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
        int i;
        int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-       unsigned short retval = 0;
-       int mdio_addr = ioaddr + CSR9;
+       int retval = 0;
+       long mdio_addr = dev->base_addr + CSR9;
+
+       if (tp->chip_id == LC82C168) {
+               long ioaddr = dev->base_addr;
+               int i = 1000;
+               outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+               while (--i > 0)
+                       if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+                               return retval & 0xffff;
+               return 0xffff;
+       }
 
        /* Establish sync by sending at least 32 logic ones. */ 
        for (i = 32; i >= 0; i--) {
@@ -1031,60 +1141,78 @@ static int mdio_read(int ioaddr, int phy_id, int location)
                mdio_delay();
        }
        /* Shift the read command bits out. */
-       for (i = 17; i >= 0; i--) {
+       for (i = 15; i >= 0; i--) {
                int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
 
-               outl(dataval, mdio_addr);
-               mdio_delay();
-               outl(dataval | MDIO_SHIFT_CLK, mdio_addr);
+               outl(MDIO_ENB | dataval, mdio_addr);
                mdio_delay();
-               outl(dataval, mdio_addr);
+               outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay();
        }
-       outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-       mdio_delay();
-       outl(MDIO_ENB_IN, mdio_addr);
-
-       for (i = 16; i > 0; i--) {
-               outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-               mdio_delay();
-               retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+       /* Read the two transition, 16 data, and wire-idle bits. */
+       for (i = 19; i > 0; i--) {
                outl(MDIO_ENB_IN, mdio_addr);
                mdio_delay();
-       }
-       /* Clear out extra bits. */
-       for (i = 16; i > 0; i--) {
+               retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
                outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay();
-               outl(MDIO_ENB_IN, mdio_addr);
-               mdio_delay();
        }
-       return retval;
+       return (retval>>1) & 0xffff;
 }
 
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-/* Enable receiver */
-
-void tulip_xon(struct device *dev)
+static void mdio_write(struct device *dev, int phy_id, int location, int value)
 {
-       struct tulip_private *lp = (struct tulip_private *)dev->priv;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int i;
+       int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+       long mdio_addr = dev->base_addr + CSR9;
+
+       if (tp->chip_id == LC82C168) {
+               long ioaddr = dev->base_addr;
+               int i = 1000;
+               outl(cmd, ioaddr + 0xA0);
+               do
+                       if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+                               break;
+               while (--i > 0);
+               return;
+       }
 
-       clear_bit(lp->fc_bit, &netdev_fc_xoff);
-       if (dev->start)
-                               outl(lp->csr6 | 0x2002, dev->base_addr + CSR6);
+       /* Establish sync by sending 32 logic ones. */ 
+       for (i = 32; i >= 0; i--) {
+               outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Shift the command bits out. */
+       for (i = 31; i >= 0; i--) {
+               int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+               outl(MDIO_ENB | dataval, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       /* Clear out extra bits. */
+       for (i = 2; i > 0; i--) {
+               outl(MDIO_ENB_IN, mdio_addr);
+               mdio_delay();
+               outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+               mdio_delay();
+       }
+       return;
 }
-#endif
 
 \f
 static int
 tulip_open(struct device *dev)
 {
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        int i = 0;
 
        /* On some chip revs we must set the MII/SYM port before the reset!? */
-       if (tp->mtable  &&  tp->mtable->has_mii)
+       if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
                outl(0x00040000, ioaddr + CSR6);
 
        /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
@@ -1106,31 +1234,30 @@ tulip_open(struct device *dev)
           Tx and Rx queues and the address filter list. */
 #if defined(__alpha__)
        /* ToDo: Alpha setting could be better. */
-       outl(0x00200000 | 0xE000, ioaddr + CSR0);
+       outl(0x01A00000 | 0xE000, ioaddr + CSR0);
 #elif defined(__powerpc__)
-       outl(0x00200080 | 0x8000, ioaddr + CSR0);
+       outl(0x01A00080 | 0x8000, ioaddr + CSR0);
 #elif defined(__i386__)
 #if defined(MODULE)
        /* When a module we don't have 'x86' to check. */
-       outl(0x00200000 | 0x4800, ioaddr + CSR0);
+       outl(0x01A00000 | 0x4800, ioaddr + CSR0);
 #else
-#ifndef ORIGINAL_TEXT
-#define x86 (boot_cpu_data.x86)
+#if (LINUX_VERSION_CODE > 0x2014c)
+#define x86 boot_cpu_data.x86
 #endif
-       outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
+       outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
        if (x86 <= 4)
          printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
                         "alignment to %x.\n", dev->name,
-                        0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000));
+                        0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
 #endif
 #else
-       outl(0x00200000 | 0x4800, ioaddr + CSR0);
+       outl(0x01A00000 | 0x4800, ioaddr + CSR0);
 #warning Processor architecture undefined!
 #endif
 
 #ifdef SA_SHIRQ
-       if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ,
-                                       tulip_tbl[tp->chip_id].chip_name, dev)) {
+       if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
                return -EAGAIN;
        }
 #else
@@ -1178,7 +1305,7 @@ tulip_open(struct device *dev)
        outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
 
        if (dev->if_port == 0)
-         dev->if_port = tp->default_port;
+               dev->if_port = tp->default_port;
        if (tp->chip_id == DC21041  &&  dev->if_port > 4)
                /* Invalid: Select initial TP, autosense, autonegotiate.  */
                dev->if_port = 4;
@@ -1186,14 +1313,16 @@ tulip_open(struct device *dev)
        /* Allow selecting a default media. */
        if (tp->mtable == NULL)
                goto media_picked;
-       if (dev->if_port)
+       if (dev->if_port) {
+               int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+                       (dev->if_port == 12 ? 0 : dev->if_port);
                for (i = 0; i < tp->mtable->leafcount; i++)
-                 if (tp->mtable->mleaf[i].media ==
-                         (dev->if_port == 12 ? 0 : dev->if_port)) {
-                       printk(KERN_INFO "%s: Using user-specified media %s.\n",
-                                  dev->name, medianame[dev->if_port]);
-                       goto media_picked;
-                 }
+                       if (tp->mtable->mleaf[i].media == looking_for) {
+                               printk(KERN_INFO "%s: Using user-specified media %s.\n",
+                                          dev->name, medianame[dev->if_port]);
+                               goto media_picked;
+                       }
+       }
        if ((tp->mtable->defaultmedia & 0x0800) == 0)
                for (i = 0; i < tp->mtable->leafcount; i++)
                  if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
@@ -1201,55 +1330,61 @@ tulip_open(struct device *dev)
                                   dev->name, medianame[tp->mtable->mleaf[i].media]);
                        goto media_picked;
                  }
+       /* Start sensing first non-full-duplex media. */
        for (i = tp->mtable->leafcount - 1;
-                (media_fd[tp->mtable->mleaf[i].media] & 2) && i > 0; i--)
+                (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
          ;
 media_picked:
 
-       tp->cur_index = i;
        tp->csr6 = 0;
-       select_media(dev, 1);
+       tp->cur_index = i;
+       if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+               tp->csr6 = 0x82420200;
+               outl(0x0003FFFF, ioaddr + CSR14);
+               outl(0x0008, ioaddr + CSR15);
+               outl(0x0001, ioaddr + CSR13);
+               outl(0x1301, ioaddr + CSR12);
+       } else if (tp->chip_id == LC82C168  &&  tp->mii_cnt && ! tp->medialock) {
+               dev->if_port = 11;
+               tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
+               outl(0x0001, ioaddr + CSR15);
+       } else
+               select_media(dev, 1);
 
        /* Start the chip's Tx to process setup frame. */
        outl(tp->csr6, ioaddr + CSR6);
        outl(tp->csr6 | 0x2000, ioaddr + CSR6);
 
        dev->tbusy = 0;
-       dev->interrupt = 0;
+       tp->interrupt = 0;
        dev->start = 1;
 
-
        /* Enable interrupts by setting the interrupt mask. */
-       outl(0x0001ebef, ioaddr + CSR7);
+       outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+       outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
        outl(tp->csr6 | 0x2002, ioaddr + CSR6);
        outl(0, ioaddr + CSR2);         /* Rx poll demand */
 
        if (tulip_debug > 2) {
-               printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n",
+               printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
                           dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
-                          inl(ioaddr + CSR13));
+                          inl(ioaddr + CSR6));
        }
        /* 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.expires = RUN_AT(5*HZ);
        tp->timer.data = (unsigned long)dev;
-       tp->timer.function = &tulip_timer;                              /* timer handler */
+       tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
        add_timer(&tp->timer);
 
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-       tp->fc_bit = netdev_register_fc(dev, tulip_xon);
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-       dev->tx_semaphore = 1;
-#endif
        return 0;
 }
 
 /* Set up the transceiver control registers for the selected media type. */
 static void select_media(struct device *dev, int startup)
 {
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        struct mediatable *mtable = tp->mtable;
        u32 new_csr6;
@@ -1261,8 +1396,8 @@ static void select_media(struct device *dev, int startup)
                switch (mleaf->type) {
                case 0:                                 /* 21140 non-MII xcvr. */
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control"
-                                          " setting %2.2x.\n",
+                               printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+                                          " with control setting %2.2x.\n",
                                           dev->name, p[1]);
                        dev->if_port = p[0];
                        if (startup)
@@ -1270,26 +1405,11 @@ static void select_media(struct device *dev, int startup)
                        outl(p[1], ioaddr + CSR12);
                        new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
                        break;
-               case 1:
-                       if (startup) {
-                               outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
-                               dev->if_port = 11;
-                               if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s:  Doing a reset sequence of length %d.\n",
-                                                  dev->name, p[2 + p[1]]);
-                               for (i = 0; i < p[2 + p[1]]; i++)
-                                       outl(p[3 + p[1] + i], ioaddr + CSR12);
-                               if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s  Doing a transceiver setup sequence of length %d.\n",
-                                                  dev->name, p[1]);
-                               for (i = 0; i < p[1]; i++)
-                                       outl(p[2 + i], ioaddr + CSR12);
-                       }
-                       check_mii = 1;
-                       new_csr6 = 0x020C0000;
-                       break;
                case 2: case 4: {
-                       u16 *setup = (u16*)&p[1];
+                       u16 setup[3];
+                       for (i = 0; i < 3; i++)
+                               setup[i] = get_u16(&p[i*2 + 1]);
+
                        dev->if_port = p[0] & 15;
                        if (tulip_debug > 1)
                                printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
@@ -1299,59 +1419,74 @@ static void select_media(struct device *dev, int startup)
                                outl(setup[1], ioaddr + CSR14);
                                outl(setup[2], ioaddr + CSR15);
                                outl(setup[0], ioaddr + CSR13);
-                               setup += 3;
-                       } else {
+                               for (i = 0; i < 3; i++)                 /* Re-fill setup[]  */
+                                       setup[i] = get_u16(&p[i*2 + 7]);
+                       } else if (dev->if_port <= 4) {
                                outl(0, ioaddr + CSR13);
                                outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
                                outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
                                outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+                       } else {
+                               outl(0, ioaddr + CSR14);
+                               outl(8, ioaddr + CSR15);
+                               outl(0, ioaddr + CSR13);
                        }
                        outl(setup[0]<<16, ioaddr + CSR15);     /* Direction */
                        outl(setup[1]<<16, ioaddr + CSR15);     /* Data */
                        if (mleaf->type == 4)
-                               new_csr6 = 0x02000000 | ((setup[2] & 0x71) << 18);
+                               new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
                        else
                                new_csr6 = 0x82420000;
                        break;
                }
-               case 3: {
+               case 1: case 3: {
+                       int phy_num = p[0];
                        int init_length = p[1];
-                       u16 * init_sequence = (u16*)(p + 2);
-                       int reset_length = p[2 + init_length*2];
-                       u16 * reset_sequence = (u16*)&p[3 + init_length*2];
+                       u16 *misc_info;
+                       u16 to_advertise;
 
                        dev->if_port = 11;
-                       if (startup) {
-                               if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s:  Doing a 21142 reset sequence of length %d.\n",
-                                                  dev->name, reset_length);
-                               for (i = 0; i < reset_length; i++)
-                                       outl(reset_sequence[i] << 16, ioaddr + CSR15);
-                       }
-                       if (tulip_debug > 2)
-                               printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n",
-                                          dev->name, init_length);
-                       for (i = 0; i < init_length; i++)
-                               outl(init_sequence[i] << 16, ioaddr + CSR15);
                        check_mii = 1;
-                       new_csr6 = 0x020C0000;
+                       new_csr6 = 0x020E0000;
+                       if (mleaf->type == 3) { /* 21142 */
+                               u16 *init_sequence = (u16*)(p+2);
+                               u16 *reset_sequence = &((u16*)(p+3))[init_length];
+                               int reset_length = p[2 + init_length*2];
+                               misc_info = reset_sequence + reset_length;
+                               if (startup)
+                                       for (i = 0; i < reset_length; i++)
+                                               outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+                               for (i = 0; i < init_length; i++)
+                                       outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+                       } else {
+                               u8 *init_sequence = p + 2;
+                               u8 *reset_sequence = p + 3 + init_length;
+                               int reset_length = p[2 + init_length];
+                               misc_info = (u16*)(reset_sequence + reset_length);
+                               if (startup) {
+                                       outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+                                       for (i = 0; i < reset_length; i++)
+                                               outl(reset_sequence[i], ioaddr + CSR12);
+                               }
+                               for (i = 0; i < init_length; i++)
+                                       outl(init_sequence[i], ioaddr + CSR12);
+                       }
+                       to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+                       tp->advertising[phy_num] = to_advertise;
+                       if (tulip_debug > 1 || 1)
+                               printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d (%d).\n",
+                                          dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+                       /* Bogus: put in by a committee?  */
+                       mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
                        break;
                }
                default:
-                 new_csr6 = 0x020C0000;
+                 new_csr6 = 0x020E0000;
                }
                if (tulip_debug > 1)
                        printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
                                   dev->name, medianame[dev->if_port],
                                   inl(ioaddr + CSR12) & 0xff);
-       } else if (tp->chip_id == DC21140) {
-               /* Set media type to MII @ 100mbps: 0x020C0000 */
-               new_csr6 = 0x020C0000;
-               dev->if_port = 11;
-               if (tulip_debug > 1) {
-                       printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n",
-                                  dev->name, inl(ioaddr + CSR12) & 0xff);
-               }
        } else if (tp->chip_id == DC21041) {
                if (tulip_debug > 1)
                        printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
@@ -1363,14 +1498,24 @@ static void select_media(struct device *dev, int startup)
                outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
                new_csr6 = 0x80020000;
        } else if (tp->chip_id == LC82C168) {
-               if (startup)
-                       dev->if_port = 3;
+               if (startup && ! tp->medialock)
+                       dev->if_port = tp->mii_cnt ? 11 : 0;
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: LiteOn PHY status is %3.3x, CSR12 %4.4x,"
+                       printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
                                   " media %s.\n",
                                   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
                                   medianame[dev->if_port]);
-               if (dev->if_port == 3  ||  dev->if_port == 5) {
+               if (tp->mii_cnt) {
+                       new_csr6 = 0x812C0000;
+                       outl(0x0001, ioaddr + CSR15);
+                       outl(0x0201B07A, ioaddr + 0xB8);
+               } else if (startup) {
+                       /* Start with 10mbps to do autonegotiation. */
+                       outl(0x32, ioaddr + CSR12);
+                       new_csr6 = 0x00420000;
+                       outl(0x0001B078, ioaddr + 0xB8);
+                       outl(0x0201B078, ioaddr + 0xB8);
+               } else if (dev->if_port == 3  ||  dev->if_port == 5) {
                        outl(0x33, ioaddr + CSR12);
                        new_csr6 = 0x01860000;
                        if (startup)
@@ -1382,7 +1527,7 @@ static void select_media(struct device *dev, int startup)
                        new_csr6 = 0x00420000;
                        outl(0x1F078, ioaddr + 0xB8);
                }
-       } else {                                        /* 21040 */
+       } else if (tp->chip_id == DC21040) {                                    /* 21040 */
                /* Turn on the xcvr interface. */
                int csr12 = inl(ioaddr + CSR12);
                if (tulip_debug > 1)
@@ -1393,6 +1538,23 @@ static void select_media(struct device *dev, int startup)
                outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
                outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
                outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+       } else {                                        /* Unknown chip type with no media table. */
+               if (tp->default_port == 0)
+                       if (tp->mii_cnt) {
+                               dev->if_port = 11;
+                       } else
+                               dev->if_port = 3;
+               if (media_cap[dev->if_port] & MediaIsMII) {
+                       new_csr6 = 0x020E0000;
+               } else if (media_cap[dev->if_port] & MediaIsFx) {
+                       new_csr6 = 0x028600000;
+               } else
+                       new_csr6 = 0x038600000;
+               if (tulip_debug > 1)
+                       printk(KERN_DEBUG "%s: No media description table, assuming "
+                                  "%s transceiver, CSR12 %2.2x.\n",
+                                  dev->name, medianame[dev->if_port],
+                                  inl(ioaddr + CSR12));
        }
 
        tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -1403,7 +1565,7 @@ static void tulip_timer(unsigned long data)
 {
        struct device *dev = (struct device *)data;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        u32 csr12 = inl(ioaddr + CSR12);
        int next_tick = 0;
 
@@ -1467,167 +1629,366 @@ static void tulip_timer(unsigned long data)
                  break;
                }
                break;
-       case LC82C168: {
+       case DC21140:  case DC21142: case MX98713: default: {
+               struct medialeaf *mleaf;
+               unsigned char *p;
+               if (tp->mtable == NULL) {       /* No EEPROM info, use generic code. */
+                       /* Not much that can be done.
+                          Assume this a generic MII or SYM transceiver. */
+                       next_tick = 60*HZ;
+                       if (tulip_debug > 2)
+                               printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+                                          "CSR12 0x%2.2x.\n",
+                                          dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+                       break;
+               }
+               mleaf = &tp->mtable->mleaf[tp->cur_index];
+               p = mleaf->leafdata;
+               switch (mleaf->type) {
+               case 0: case 4: {
+                       /* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
+                       int offset = mleaf->type == 4 ? 5 : 2;
+                       s8 bitnum = p[offset];
+                       if (p[offset+1] & 0x80) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_DEBUG"%s: Transceiver monitor tick "
+                                                  "CSR12=%#2.2x, no media sense.\n",
+                                                  dev->name, csr12);
+                               if (mleaf->type == 4) {
+                                       if (mleaf->media == 3 && (csr12 & 0x02))
+                                               goto select_next_media;
+                               }
+                               break;
+                       }
+                       if (tulip_debug > 2)
+                               printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+                                          " bit %d is %d, expecting %d.\n",
+                                          dev->name, csr12, (bitnum >> 1) & 7,
+                                          (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+                                          (bitnum >= 0));
+                       /* Check that the specified bit has the proper value. */
+                       if ((bitnum < 0) !=
+                               ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+                                                  medianame[mleaf->media]);
+                               if ((p[2] & 0x61) == 0x01)      /* Bogus Znyx board. */
+                                       goto actually_mii;
+                               break;
+                       }
+                       if (tp->medialock)
+                               break;
+         select_next_media:
+                       if (--tp->cur_index < 0) {
+                               /* We start again, but should instead look for default. */
+                               tp->cur_index = tp->mtable->leafcount - 1;
+                       }
+                       dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+                       if (media_cap[dev->if_port] & MediaIsFD)
+                               goto select_next_media; /* Skip FD entries. */
+                       if (tulip_debug > 1)
+                               printk(KERN_DEBUG "%s: No link beat on media %s,"
+                                          " trying transceiver type %s.\n",
+                                          dev->name, medianame[mleaf->media & 15],
+                                          medianame[tp->mtable->mleaf[tp->cur_index].media]);
+                       select_media(dev, 0);
+                       /* Restart the transmit process. */
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+                       next_tick = (24*HZ)/10;
+                       break;
+               }
+               case 1:  case 3: {              /* 21140, 21142 MII */
+                       int mii_reg1, mii_reg5;
+               actually_mii:
+                       mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+                       mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+                       if (tulip_debug > 1)
+                               printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+                                          "%4.4x, CSR12 %2.2x, %cD.\n",
+                                          dev->name, mii_reg1, mii_reg5, csr12,
+                                          tp->full_duplex ? 'F' : 'H');
+                       if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0) {
+                               int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+                               if ((new_reg1 & 0x0004) == 0) {
+                                       printk(KERN_INFO "%s: No link beat on the MII interface,"
+                                                  " status then %4.4x now %4.4x.\n",
+                                                  dev->name, mii_reg1, new_reg1);
+                                       if (tp->mtable  &&  tp->mtable->has_nonmii)
+                                               goto select_next_media;
+                               }
+                       }
+                       if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+                               ;                               /* No MII device or no link partner report */
+                       else if (tp->full_duplex_lock)
+                               ;
+                       else {
+                               int negotiated = mii_reg5 & tp->advertising[0];
+                               int duplex = ((negotiated & 0x0100) != 0
+                                                         || (negotiated & 0x00C0) == 0x0040);
+                               /* 100baseTx-FD  or  10T-FD, but not 100-HD */
+                               if (tp->full_duplex != duplex) {
+                                       tp->full_duplex = duplex;
+                                       if (tp->full_duplex)
+                                               tp->csr6 |= 0x0200;
+                                       else
+                                               tp->csr6 &= ~0x0200;
+                                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+                                       if (tulip_debug > 0) /* Gurppp, should be >1 */
+                                               printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+                                                          " Xcvr #%d parter capability of %4.4x.\n",
+                                                          dev->name, tp->full_duplex ? "full" : "half",
+                                                          tp->phys[0], mii_reg5);
+                               }
+                       }
+                       next_tick = 60*HZ;
+                       break;
+               }
+               case 2:                                 /* 21142 serial block has no link beat. */
+               default:
+                       break;
+               }
+       }
+       break;
+       }
+       if (next_tick) {
+               tp->timer.expires = RUN_AT(next_tick);
+               add_timer(&tp->timer);
+       }
+}
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+   of available transceivers.  */
+static void t21142_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+       int next_tick = 60*HZ;
+       int new_csr6 = 0;
+
+       if (tulip_debug > 1)
+               printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+                          dev->name, csr12, medianame[dev->if_port]);
+       if (dev->if_port == 3) {
+               if (csr12 & 2) {                /* No 100mbps link beat, revert to 10mbps. */
+                       new_csr6 = 0x82420200;
+                       outl(new_csr6, ioaddr + CSR6);
+                       outl(0x0000, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(0x0008, ioaddr + CSR15);
+                       outl(0x0001, ioaddr + CSR13);
+                       outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+               }
+       } else if ((csr12 & 0x7000) != 0x5000) {
+               /* Negotiation failed.  Search media types. */
+               if (tulip_debug > 1)
+                       printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+                                  dev->name, csr12);
+               if (!(csr12 & 4)) {             /* 10mbps link beat good. */
+                       new_csr6 = 0x82420000;
+                       dev->if_port = 0;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+                       outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+               } else if (csr12 & 0x100) {
+                       new_csr6 = 0x82420200;
+                       dev->if_port = 2;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FFFF, ioaddr + CSR14);
+                       outl(0x0008, ioaddr + CSR15);
+                       outl(0x0001, ioaddr + CSR13);
+               } else {
+                       /* Select 100mbps port to check for link beat. */
+                       new_csr6 = 0x83860000;
+                       dev->if_port = 3;
+                       outl(0, ioaddr + CSR13);
+                       outl(0x0003FF7F, ioaddr + CSR14);
+                       outl(8, ioaddr + CSR15);
+                       outl(1, ioaddr + CSR13);
+               }
+               if (tulip_debug > 1)
+                       printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+                                  dev->name, medianame[dev->if_port]);
+               if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+                       tp->csr6 &= 0x00D5;
+                       tp->csr6 |= new_csr6;
+                       outl(0x0301, ioaddr + CSR12);
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               }
+       }
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
+}
+
+static void t21142_lnk_change( struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+
+       if (tulip_debug > 1)
+               printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+                          dev->name, csr12, inl(ioaddr + CSR5));
+
+       if ((csr12 & 0x7000) == 0x5000) {
+               if (csr12 & 0x01800000) {
+                       /* Switch to 100mbps mode. */
+                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                       if (csr12 & 0x01000000) {
+                               dev->if_port = 5;
+                               tp->csr6 = 0x83860200;
+                       } else {
+                               dev->if_port = 3;
+                               tp->csr6 = 0x83860000;
+                       }
+                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               } /* Else 10baseT-FD is handled automatically. */
+       } else if (dev->if_port == 3) {
+               if (!(csr12 & 2))
+                       printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+                                  dev->name);
+               else
+                       dev->if_port = 0;
+       } else if (dev->if_port == 0) {
+               if (!(csr12 & 4))
+                       printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+                                  dev->name);
+       } else if (!(csr12 & 4)) {              /* 10mbps link beat good. */
+                       printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+                                  dev->name);
+                       dev->if_port = 0;
+       } else  {               /* 100mbps link beat good. */
+               printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+                          dev->name);
+               dev->if_port = 3;
+               tp->csr6 = 0x83860000;
+               outl(0x0003FF7F, ioaddr + CSR14);
+               outl(0x0301, ioaddr + CSR12);
+               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+       }
+}
+       
+
+static void mxic_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       int next_tick = 60*HZ;
+
+       if (tulip_debug > 3) {
+               printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+                          inl(ioaddr + CSR12));
+       }
+       if (next_tick) {
+               tp->timer.expires = RUN_AT(next_tick);
+               add_timer(&tp->timer);
+       }
+}
+
+static void pnic_timer(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       int csr12 = inl(ioaddr + CSR12);
+       int next_tick = 60*HZ;
+       int new_csr6 = tp->csr6 & ~0x40C40200;
+
+       if (media_cap[dev->if_port] & MediaIsMII) {
+               int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
+
+               if (tulip_debug > 1)
+                       printk(KERN_DEBUG "%s: LC82C168 negotiated capability %8.8x, "
+                                  "CSR5 %8.8x.\n",
+                                  dev->name, negotiated, inl(ioaddr + CSR5));
+
+               if (negotiated & 0x0380)                                /* 10 vs 100mbps */
+                       new_csr6 |= 0x812E0000;
+               else
+                       new_csr6 |= 0x816E0000;
+               if (((negotiated & 0x0300) == 0x0100)                   /* Duplex */
+                       || (negotiated & 0x00C0) == 0x0040
+                       || tp->full_duplex_lock) {
+                       tp->full_duplex = 1;
+                       new_csr6 |= 0x0200;
+               }
+               if (tulip_debug > 1)
+                       printk(KERN_DEBUG "%s: LC82C168 MII PHY status %4.4x, Link "
+                                  "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
+                          dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
+                                  tp->csr6, inl(ioaddr + CSR6));
+       } else {
                int phy_reg = inl(ioaddr + 0xB8);
+               int csr5 = inl(ioaddr + CSR5);
+
                if (tulip_debug > 1)
                        printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
-                                  dev->name, phy_reg, inl(ioaddr + CSR5));
+                                  dev->name, phy_reg, csr5);
+
                if (phy_reg & 0x04000000) {     /* Remote link fault */
-                       outl(0x0201F078, ioaddr + 0xB8);
-                       next_tick = (24*HZ)/10;
-               } else
-                       next_tick = 10*HZ;
+                       /*outl(0x0201F078, ioaddr + 0xB8);*/
+                       next_tick = 3*HZ;
+               }
                if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
                        if (tulip_debug > 1)
                                printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
                                           "CSR5 %8.8x, PHY %3.3x.\n",
                                           dev->name, medianame[dev->if_port], csr12,
                                           inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
-                       if (dev->if_port == 0) {
+                       if (tp->medialock) {
+                       } else if (dev->if_port == 0) {
                                dev->if_port = 3;
-                       } else
-                               dev->if_port = 0;
-                       next_tick = (24*HZ)/10;
-                       select_media(dev, 0);
-                       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                       dev->trans_start = jiffies;
-               }
-               break;
-       }
-       case DC21140:  case DC21142: {
-               struct medialeaf *mleaf;
-               unsigned char *p;
-               if (tp->mtable == NULL) {       /* No EEPROM info, use generic code. */
-                       /* Assume this is like a SMC card, and check its link beat bit. */
-                       if ((dev->if_port == 0 && (csr12 & 0x0080)) ||
-                               (dev->if_port == 1 && (csr12 & 0x0040) == 0)) {
-                               dev->if_port ^= 1;
-                               /* Stop the transmit process. */
-                               tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000);
-                               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                               printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to"
-                                          " %s media.\n", dev->name,
-                                          csr12 & 0xff,
-                                          dev->if_port ? "100baseTx" : "10baseT");
-                               outl(tp->csr6 | 0xA002, ioaddr + CSR6);
-                               dev->trans_start = jiffies;
-                               next_tick = (24*HZ)/10;
+                               outl(0x33, ioaddr + CSR12);
+                               new_csr6 = 0x01860000;
+                               outl(0x1F868, ioaddr + 0xB8);
                        } else {
-                               next_tick = 10*HZ;
-                               if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link"
-                                                  " beat detected as %s.\n", dev->name,
-                                                  csr12 & 0xff,
-                                                  dev->if_port ? "100baseTx" : "10baseT");
+                               dev->if_port = 0;
+                               outl(0x32, ioaddr + CSR12);
+                               new_csr6 = 0x00420000;
+                               outl(0x1F078, ioaddr + 0xB8);
                        }
-                       break;
+                       new_csr6 |= (tp->csr6 & 0xfdff);
+                       next_tick = 3*HZ;
+               } else
+                       new_csr6 = tp->csr6;
+               if (tp->full_duplex_lock  ||  (phy_reg & 0x30000000) != 0) {
+                       tp->full_duplex = 1;
+                       new_csr6 |= 0x00000200;
                }
-         mleaf = &tp->mtable->mleaf[tp->cur_index];
-         p = mleaf->leafdata;
-         switch (mleaf->type) {
-         case 0: case 4: {
-               /* Type 0 non-MII or #4 SYM transceiver.  Check the link beat bit. */
-                 s8 bitnum = p[mleaf->type == 4 ? 5 : 2];
-                 if (tulip_debug > 2)
-                         printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is"
-                                        " %d, expecting %d.\n",
-                                        dev->name, csr12, (bitnum >> 1) & 7,
-                                        (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
-                                        (bitnum >= 0));
-                 /* Check that the specified bit has the proper value. */
-                 if ((bitnum < 0) !=
-                         ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
-                         if (tulip_debug > 1)
-                                 printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
-                                                medianame[mleaf->media]);
-                         break;
-                 }
-                 if (tp->medialock)
-                         break;
-         select_next_media:
-                 if (--tp->cur_index < 0) {
-                       /* We start again, but should instead look for default. */
-                       tp->cur_index = tp->mtable->leafcount - 1;
-                 }
-                 dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
-                 if (media_fd[dev->if_port])
-                       goto select_next_media; /* Skip FD entries. */
-                 if (tulip_debug > 1)
-                         printk(KERN_DEBUG "%s: No link beat on media %s,"
-                                        " trying transceiver type %s.\n",
-                                        dev->name, medianame[mleaf->media & 15],
-                                        medianame[tp->mtable->mleaf[tp->cur_index].media]);
-                 select_media(dev, 0);
-                 /* Restart the transmit process. */
-                 outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                 outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                 next_tick = (24*HZ)/10;
-                 break;
-         }
-         case 1:  case 3:              /* 21140, 21142 MII */
-                 {
-                         int mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
-                         int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
-                         printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, "
-                                        "MII status %4.4x, Link partner report %4.4x.\n",
-                                        dev->name, csr12, mii_reg1, mii_reg5);
-#ifdef notdef
-                         if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0)
-                                 goto select_next_media;
-#else
-                         if (mii_reg1 != 0xffff  &&  (mii_reg1 & 0x0004) == 0)
-                                 printk(KERN_INFO "%s: No link beat on the MII interface, "
-                                                "status then %4.4x now %4.4x.\n",
-                                                dev->name, mii_reg1,
-                                                mdio_read(ioaddr, tp->phys[0], 1));
-#endif
-                         if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
-                                 ;                             /* No MII device or no link partner report */
-                         else if (tp->full_duplex_lock)
-                                 ;
-                         else if ((mii_reg5 & 0x0100) != 0
-                                          || (mii_reg5 & 0x00C0) == 0x0040) {
-                                 /* 100baseTx-FD  or  10T-FD, but not 100-HD */
-                                 if (tp->full_duplex == 0) {
-                                         tp->full_duplex = 1;
-                                         tp->csr6 |= 0x0200;
-                                         outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-                                         outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-                                 }
-                                 if (tulip_debug > 0) /* Gurppp, should be >1 */
-                                         printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-                                                        " Xcvr #%d parter capability of %4.4x.\n",
-                                                        dev->name, full_duplex ? "full" : "half",
-                                                        tp->phys[0], mii_reg5);
-                         }
-                 }
-                 break;
-         case 2:                                       /* 21142 serial block has no link beat. */
-         default:
-                 break;
-         }
-       }
-       break;
-       default:                                        /* Invalid chip type. */
-         break;
        }
-       if (next_tick) {
-               tp->timer.expires = RUN_AT(next_tick);
-               add_timer(&tp->timer);
+       if (tp->csr6 != new_csr6) {
+               tp->csr6 = new_csr6;
+               outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
+               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+               dev->trans_start = jiffies;
+               if (tulip_debug > 0) /* Gurppp, should be >1 */
+                       printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
+                                  "CSR6 %8.8x.\n",
+                                  dev->name, tp->full_duplex ? "full" : "half", new_csr6);
        }
+       tp->timer.expires = RUN_AT(next_tick);
+       add_timer(&tp->timer);
 }
 
 static void tulip_tx_timeout(struct device *dev)
 {
   struct tulip_private *tp = (struct tulip_private *)dev->priv;
-  int ioaddr = dev->base_addr;
+  long ioaddr = dev->base_addr;
 
-  if (tp->mtable && tp->mtable->has_mii) {
-       /* Do nothing -- the media monitor should handle this. */
-       if (tulip_debug > 1)
-         printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
-                        dev->name);
+  if (media_cap[dev->if_port] & MediaIsMII) {
+         /* Do nothing -- the media monitor should handle this. */
+         if (tulip_debug > 1)
+                 printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+                                dev->name);
+         dev->trans_start = jiffies;
+         return;
   } else if (tp->chip_id == DC21040) {
          if (inl(ioaddr + CSR12) & 0x0002) {
                  printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
@@ -1637,20 +1998,6 @@ static void tulip_tx_timeout(struct device *dev)
          }
          dev->trans_start = jiffies;
          return;
-  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142) {
-       /* Stop the transmit process. */
-       outl(tp->csr6 | 0x0002, ioaddr + CSR6);
-       dev->if_port ^= 1;
-       printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
-                  "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
-                  dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
-                  inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
-       printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
-                  dev->name, dev->if_port ? "100baseTx" : "10baseT");
-       outl(tp->csr6 | 0x2002, ioaddr + CSR6);
-       tp->stats.tx_errors++;
-       dev->trans_start = jiffies;
-       return;
   } else if (tp->chip_id == DC21041) {
        u32 csr12 = inl(ioaddr + CSR12);
 
@@ -1659,19 +2006,38 @@ static void tulip_tx_timeout(struct device *dev)
                   dev->name, inl(ioaddr + CSR5), csr12,
                   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
        tp->mediasense = 1;
-
-       if (dev->if_port == 1 || dev->if_port == 2) {
+       if (dev->if_port == 1 || dev->if_port == 2)
                if (csr12 & 0x0004) {
                        dev->if_port = 2 - dev->if_port;
                } else
                        dev->if_port = 0;
-       else
+       else
                dev->if_port = 1;
-
        select_media(dev, 0);
        tp->stats.tx_errors++;
        dev->trans_start = jiffies;
        return;
+  } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+                        || tp->chip_id == MX98713) {
+         /* Stop the transmit process. */
+         outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+         printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+                        "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+                        dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+                        inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+         if (tp->mtable) {
+                 if (--tp->cur_index < 0) {
+                         /* We start again, but should instead look for default. */
+                         tp->cur_index = tp->mtable->leafcount - 1;
+                 }
+                 select_media(dev, 0);
+                 printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
+                                dev->name, dev->if_port ? "100baseTx" : "10baseT");
+         }
+         outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+         tp->stats.tx_errors++;
+         dev->trans_start = jiffies;
+         return;
   } else
        printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
                   " resetting...\n",
@@ -1753,40 +2119,12 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
        int entry;
        u32 flag;
 
-#ifdef ORIGINAL_TEXT
-#ifndef final_version
-       if (skb == NULL || skb->len <= 0) {
-               printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
-                          dev->name);
-               dev_tint(dev);
-               return 0;
-       }
-#endif
-#endif
-
-#ifdef CONFIG_NET_FASTROUTE
-       cli();
-       if (xchg(&dev->tx_semaphore,0) == 0) {
-               sti();
-               /* With new queueing algorithm returning 1 when dev->tbusy == 0
-                  should not result in lockups, but I am still not sure. --ANK
-                */
-               if (net_ratelimit())
-                               printk(KERN_CRIT "Please check: are you still alive?\n");
-               return 1;
-       }
-#endif
        /* Block a timer-based transmit from overlapping.  This could better be
           done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
        if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-#ifdef CONFIG_NET_FASTROUTE
-               sti();
-#endif
-               if (jiffies - dev->trans_start >= TX_TIMEOUT)
-                               tulip_tx_timeout(dev);
-#ifdef CONFIG_NET_FASTROUTE
-               dev->tx_semaphore = 1;
-#endif
+               if (jiffies - dev->trans_start < TX_TIMEOUT)
+                       return 1;
+               tulip_tx_timeout(dev);
                return 1;
        }
 
@@ -1816,7 +2154,6 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
        if (entry == TX_RING_SIZE-1)
                flag |= 0xe2000000;
 
-       tp->stats.tx_bytes += skb->len;
        tp->tx_ring[entry].length = skb->len | flag;
        tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
        tp->cur_tx++;
@@ -1824,10 +2161,6 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
        outl(0, dev->base_addr + CSR1);
 
        dev->trans_start = jiffies;
-#ifdef CONFIG_NET_FASTROUTE
-       dev->tx_semaphore = 1;
-       sti();
-#endif
 
        return 0;
 }
@@ -1842,8 +2175,9 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
        struct device *dev = (struct device *)(irq2dev_map[irq]);
 #endif
 
-       struct tulip_private *lp;
-       int csr5, ioaddr, boguscnt = 12;
+       struct tulip_private *tp;
+       long ioaddr;
+       int csr5, work_budget = max_interrupt_work;
 
        if (dev == NULL) {
                printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
@@ -1852,11 +2186,21 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
        }
 
        ioaddr = dev->base_addr;
-       lp = (struct tulip_private *)dev->priv;
-       if (dev->interrupt)
+       tp = (struct tulip_private *)dev->priv;
+       if (test_and_set_bit(0, (void*)&tp->interrupt)) {
+#ifdef SMP_CHECK
+               printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
+                          " proc %d already handling.\n", dev->name,
+                          tp->smp_proc_id, hard_smp_processor_id());
+#else
                printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-
+#endif
+               return;
+       }
        dev->interrupt = 1;
+#ifdef SMP_CHECK
+       tp->smp_proc_id = hard_smp_processor_id();
+#endif
 
        do {
                csr5 = inl(ioaddr + CSR5);
@@ -1867,23 +2211,24 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
                        printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
                                   dev->name, csr5, inl(dev->base_addr + CSR5));
 
-               if ((csr5 & 0x00018000) == 0)
+               if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
                        break;
 
-               if (csr5 & RxIntr)
-                       tulip_rx(dev);
+               if (csr5 & (RxIntr | RxNoBuf))
+                       work_budget -= tulip_rx(dev);
 
                if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
-                       int dirty_tx;
+                       unsigned int dirty_tx;
 
-                       for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+                       for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+                                dirty_tx++) {
                                int entry = dirty_tx % TX_RING_SIZE;
-                               int status = lp->tx_ring[entry].status;
+                               int status = tp->tx_ring[entry].status;
 
                                if (status < 0)
                                        break;                  /* It still hasn't been Txed */
                                /* Check for Rx filter setup frames. */
-                               if (lp->tx_skbuff[entry] == NULL)
+                               if (tp->tx_skbuff[entry] == NULL)
                                  continue;
 
                                if (status & 0x8000) {
@@ -1893,74 +2238,104 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
                                                printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
                                                           dev->name, status);
 #endif
-                                       lp->stats.tx_errors++;
-                                       if (status & 0x4104) lp->stats.tx_aborted_errors++;
-                                       if (status & 0x0C00) lp->stats.tx_carrier_errors++;
-                                       if (status & 0x0200) lp->stats.tx_window_errors++;
-                                       if (status & 0x0002) lp->stats.tx_fifo_errors++;
-                                       if ((status & 0x0080) && lp->full_duplex == 0)
-                                               lp->stats.tx_heartbeat_errors++;
+                                       tp->stats.tx_errors++;
+                                       if (status & 0x4104) tp->stats.tx_aborted_errors++;
+                                       if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+                                       if (status & 0x0200) tp->stats.tx_window_errors++;
+                                       if (status & 0x0002) tp->stats.tx_fifo_errors++;
+                                       if ((status & 0x0080) && tp->full_duplex == 0)
+                                               tp->stats.tx_heartbeat_errors++;
 #ifdef ETHER_STATS
-                                       if (status & 0x0100) lp->stats.collisions16++;
+                                       if (status & 0x0100) tp->stats.collisions16++;
 #endif
                                } else {
 #ifdef ETHER_STATS
-                                       if (status & 0x0001) lp->stats.tx_deferred++;
+                                       if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+#if LINUX_VERSION_CODE > 0x20127
+                                       tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
 #endif
-                                       lp->stats.collisions += (status >> 3) & 15;
-                                       lp->stats.tx_packets++;
+                                       tp->stats.collisions += (status >> 3) & 15;
+                                       tp->stats.tx_packets++;
                                }
 
                                /* Free the original skb. */
-                               dev_kfree_skb(lp->tx_skbuff[entry]);
-                               lp->tx_skbuff[entry] = 0;
+#if (LINUX_VERSION_CODE > 0x20155)
+                               dev_kfree_skb(tp->tx_skbuff[entry]);
+#else
+                               dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+#endif
+                               tp->tx_skbuff[entry] = 0;
                        }
 
 #ifndef final_version
-                       if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+                       if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
                                printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-                                          dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+                                          dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
                                dirty_tx += TX_RING_SIZE;
                        }
 #endif
 
-                       if (lp->tx_full && dev->tbusy
-                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+                       if (tp->tx_full && dev->tbusy
+                               && tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
                                /* The ring is no longer full, clear tbusy. */
-                               lp->tx_full = 0;
+                               tp->tx_full = 0;
                                dev->tbusy = 0;
                                mark_bh(NET_BH);
                        }
 
-                       lp->dirty_tx = dirty_tx;
+                       tp->dirty_tx = dirty_tx;
+                       if (csr5 & TxDied) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_WARNING "%s: The transmitter stopped!"
+                                                  "  CSR5 is %x, CSR6 %x.\n",
+                                                  dev->name, csr5, inl(ioaddr + CSR6));
+                               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+                       }
                }
 
                /* Log errors. */
-               if (csr5 & 0x8000) {    /* Abnormal error summary bit. */
-                       if (csr5 & TxJabber) lp->stats.tx_errors++;
+               if (csr5 & AbnormalIntr) {      /* Abnormal error summary bit. */
+                       if (csr5 & TxJabber) tp->stats.tx_errors++;
                        if (csr5 & TxFIFOUnderflow) {
-                         lp->csr6 |= 0x00200000;  /* Reconfigure to store-n-forward. */
-                         /* Restart the transmit process. */
-                         outl(lp->csr6 | 0x0002, ioaddr + CSR6);
-                         outl(lp->csr6 | 0x2002, ioaddr + CSR6);
+                               if ((tp->csr6 & 0xC000) != 0xC000)
+                                       tp->csr6 += 0x4000;     /* Bump up the Tx threshold */
+                               else
+                                       tp->csr6 |= 0x00200000;  /* Store-n-forward. */
+                               /* Restart the transmit process. */
+                               outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+                               outl(tp->csr6 | 0x2002, ioaddr + CSR6);
                        }
                        if (csr5 & RxDied) {            /* Missed a Rx frame. */
-                               lp->stats.rx_errors++;
-                               lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+                               tp->stats.rx_errors++;
+                               tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
                        }
                        if (csr5 & TimerInt) {
                                printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
                                           dev->name, csr5);
                                /* Hmmmmm, it's not clear what to do here. */
                        }
+                       if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
+                               && tp->chip_id == DC21142) {
+                               if (tulip_debug > 1)
+                                       printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+                                                  dev->name, csr5);
+                               t21142_lnk_change(dev);
+                       }
                        /* Clear all error sources, included undocumented ones! */
-                       outl(0x000f7ba, ioaddr + CSR5);
+                       outl(0x0800f7ba, ioaddr + CSR5);
                }
-               if (--boguscnt < 0) {
-                       printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n",
-                                  dev->name, csr5);
-                       /* Clear all interrupt sources. */
-                       outl(0x0001ffff, ioaddr + CSR5);
+               if (--work_budget < 0) {
+                       if (tulip_debug > 1)
+                               printk(KERN_WARNING "%s: Too much work at interrupt, "
+                                          "csr5=0x%8.8x.\n", dev->name, csr5);
+                       /* Acknowledge all interrupt sources. */
+                       outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+                       /* Clear all but standard interrupt sources. */
+                       outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
                        break;
                }
        } while (1);
@@ -1969,271 +2344,83 @@ static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *reg
                printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
                           dev->name, inl(ioaddr + CSR5));
 
-       /* Code that should never be run!  Perhaps remove after testing.. */
-       {
-               static int stopit = 10;
-               if (dev->start == 0  &&  --stopit < 0) {
-                       printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n"
-                                  KERN_ERR "%s: Disabling interrupt handler %d to avoid "
-                                  "locking up the machine.\n",
-                                  dev->name, dev->name, dev->irq);
-#ifdef SA_SHIRQ
-                       free_irq(irq, dev);
-#else
-                       free_irq(irq);
-#endif
-               }
-       }
-
        dev->interrupt = 0;
+       clear_bit(0, (void*)&tp->interrupt);
        return;
 }
 
-#ifdef CONFIG_NET_FASTROUTE
-/* DMAing cards are the most easy in this respect,
-   they are able to make fast route to any device.
-
-   Now we allow to make it only to another ethernet card.
- */
-static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst)
-{
-       struct device *odev = dst->dev;
-
-       if (dst->ops->protocol != __constant_htons(ETH_P_IP))
-                       return -1;
-       if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL)
-                       return -1;
-
-       return 0;
-}
-
-/*
-   Return values:
-
-   0 - packet has gone by fast path.
-   1 - fast path is OK, but device deferred xmit. (semifast path)
-
-   2 - fast path is hit, but packet is a bit strange. (NI)
-   3 - oom
-
-   4 - fast path miss.
- */
-
-static int tulip_fast_forward(struct device *dev, int entry, int len)
-{
-       struct tulip_private *lp = (struct tulip_private *)dev->priv;
-       struct sk_buff *skb = lp->rx_skbuff[entry];
-       struct ethhdr *eth = (void*)skb->data;
-
-       if (eth->h_proto == __constant_htons(ETH_P_IP)) {
-               struct rtable *rt;
-               struct iphdr *iph;
-               unsigned h;
-
-               iph = (struct iphdr*)(skb->data + ETH_HLEN);
-               h = (*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK;
-               rt = (struct rtable*)(dev->fastpath[h]);
-               if (rt &&
-                       ((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] &&
-                       ((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] &&
-                       ((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] &&
-                       ((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] &&
-                       rt->u.dst.obsolete == 0) {
-                       struct device *odev = rt->u.dst.dev;
-
-                       dev_fastroute_stat.hits++;
-
-                       if (*(u8*)iph != 0x45 ||
-                               (eth->h_dest[0]&1) ||
-                               !neigh_is_valid(rt->u.dst.neighbour) ||
-                               iph->ttl <= 1)
-                                       goto alas2;
-
-                       ip_decrease_ttl(iph);
-
-                       if (1) {
-                               struct sk_buff *skb2 = DEV_ALLOC_SKB(PKT_BUF_SZ);
-                               if (skb2 == NULL)
-                                               goto oom;
-                               lp->rx_ring[entry].buffer1 = virt_to_bus(skb2->tail);
-                               skb2->dev = dev;
-                               lp->rx_skbuff[entry] = skb2;
-                       }
-
-                       skb_put(skb, len);
-
-                       ip_statistics.IpInReceives++;
-                       ip_statistics.IpForwDatagrams++;
-
-                       /* Could use hh cache */
-                       memcpy(eth->h_source, odev->dev_addr, 6);
-                       memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
-                       skb->dev = odev;
-
-#ifdef FAST_SKB_RECYCLE /* DO NOT DEFINE IT! READ COMMENT */
-                       /* We could use fast buffer recycling here if odev
-                          is not DMAing.
-
-                          The only problem is that we must allocate skb2
-                          BEFORE we lose skb, otherwise we would make hole in
-                          tulip rx array. Hence, to implement FAST_SKB_RECYCLE
-                          we need always keep at least one skb in a safe place.
-                        */
-                       atomic_inc(&skb->users);
-#endif
-
-                       if (odev->tx_semaphore &&
-                               odev->tbusy == 0 &&
-                               odev->interrupt == 0 &&
-                               odev->hard_start_xmit(skb, odev) == 0) {
-#ifdef FAST_SKB_RECYCLE
-                               if (atomic_read(&skb->users) == 1) {
-                                       skb->tail = skb->data;
-                                       skb->len = 0;
-                               }
-#endif
-                               dev_fastroute_stat.succeed++;
-                               return 0;
-                       }
-#ifdef FAST_SKB_RECYCLE
-                       atomic_dec(&skb->users);
-#endif
-
-                       /* Otherwise... */
-                       skb->pkt_type = PACKET_FASTROUTE;
-                       skb->nh.raw = skb->data + ETH_HLEN;
-                       skb->protocol = __constant_htons(ETH_P_IP);
-                       dev_fastroute_stat.deferred++;
-                       return 1;
-               }
-       }
-       return 4;
-
-oom:
-       return 3;
-
-alas2:
-#ifdef not_yet
-       skb->dst = dst_clone(&rt->u.dst);
-       return 2;
-#else
-       return 4;
-#endif
-}
-#endif
-
 static int
 tulip_rx(struct device *dev)
 {
-       struct tulip_private *lp = (struct tulip_private *)dev->priv;
-       int entry = lp->cur_rx % RX_RING_SIZE;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int entry = tp->cur_rx % RX_RING_SIZE;
+       int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+       int work_done = 0;
 
        if (tulip_debug > 4)
                printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
-                          lp->rx_ring[entry].status);
+                          tp->rx_ring[entry].status);
        /* If we own the next entry, it's a new packet. Send it up. */
-       while (lp->rx_ring[entry].status >= 0) {
-               int status = lp->rx_ring[entry].status;
+       while (tp->rx_ring[entry].status >= 0) {
+               s32 status = tp->rx_ring[entry].status;
 
+               if (--rx_work_limit < 0)
+                       break;
                if ((status & 0x0300) != 0x0300) {
                        if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
-                         printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-                                        "multiple buffers, status %8.8x!\n", dev->name, status);
-                         lp->stats.rx_length_errors++;
+                               if (tulip_debug > 1)
+                                       printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+                                                  "multiple buffers, status %8.8x!\n",
+                                                  dev->name, status);
+                         tp->stats.rx_length_errors++;
                        }
                } else if (status & 0x8000) {
                        /* There was a fatal error. */
-                       lp->stats.rx_errors++; /* end of a packet.*/
-                       if (status & 0x0890) lp->stats.rx_length_errors++;
-                       if (status & 0x0004) lp->stats.rx_frame_errors++;
-                       if (status & 0x0002) lp->stats.rx_crc_errors++;
-                       if (status & 0x0001) lp->stats.rx_fifo_errors++;
+                       if (tulip_debug > 2)
+                               printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+                                          dev->name, status);
+                       tp->stats.rx_errors++; /* end of a packet.*/
+                       if (status & 0x0890) tp->stats.rx_length_errors++;
+                       if (status & 0x0004) tp->stats.rx_frame_errors++;
+                       if (status & 0x0002) tp->stats.rx_crc_errors++;
+                       if (status & 0x0001) tp->stats.rx_fifo_errors++;
                } else {
-                       /* Malloc up new buffer, compatible with net-2e. */
                        /* Omit the four octet CRC from the length. */
-                       short pkt_len = (lp->rx_ring[entry].status >> 16) - 4;
+                       short pkt_len = (status >> 16) - 4;
                        struct sk_buff *skb;
-                       int rx_in_place = 0;
-
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-                       if (netdev_dropping)
-                                       goto throttle;
-#endif
-
-                       skb = lp->rx_skbuff[entry];
 
-#ifdef CONFIG_NET_FASTROUTE
-                       switch (tulip_fast_forward(dev, entry, pkt_len)) {
-                       case 0: 
-                                       goto gone;
-                       case 1:
-                                       goto semi_gone;
-                       case 2:
-                                       break;
-                       case 3:
-                                       skb = NULL;
-                                       goto memory_squeeze;
-                       }
-#endif
                        /* Check if the packet is long enough to just accept without
                           copying to a properly sized skbuff. */
-                       if (pkt_len > rx_copybreak) {
-                               struct sk_buff *newskb;
-                               char *temp;
-
-                               /* Get a fresh skbuff to replace the filled one. */
-                               newskb = DEV_ALLOC_SKB(PKT_BUF_SZ);
-                               if (newskb == NULL) {
-                                       skb = NULL;             /* No memory, drop the packet. */
-                                       goto memory_squeeze;
-                               }
-                               /* Pass up the skb already on the Rx ring. */
-                               temp = skb_put(skb, pkt_len);
-                               if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp)
-                                       printk(KERN_ERR "%s: Internal consistency error -- the "
-                                                  "skbuff addresses do not match"
-                                                  " in tulip_rx: %p vs. %p / %p.\n", dev->name,
-                                                  bus_to_virt(lp->rx_ring[entry].buffer1),
-                                                  skb->head, temp);
-                               rx_in_place = 1;
-                               lp->rx_skbuff[entry] = newskb;
-                               newskb->dev = dev;
-                               /* Longword alignment required: do not skb_reserve(2)! */
-                               lp->rx_ring[entry].buffer1 = virt_to_bus(newskb->tail);
-                       } else
-                               skb = DEV_ALLOC_SKB(pkt_len + 2);
-memory_squeeze:
-                       if (skb == NULL) {
-                               int i;
-                               printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n",
-                                          dev->name);
-                               /* Check that at least two ring entries are free.
-                                  If not, free one and mark stats->rx_dropped++. */
-                               for (i = 0; i < RX_RING_SIZE; i++)
-                                       if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
-                                               break;
-
-                               if (i > RX_RING_SIZE -2) {
-                                       lp->stats.rx_dropped++;
-                                       lp->rx_ring[entry].status = 0x80000000;
-                                       lp->cur_rx++;
-                               }
-                               break;
-                       }
-                       skb->dev = dev;
-                       if (! rx_in_place) {
-                               skb_reserve(skb, 2);    /* 16 byte align the data fields */
-#if LINUX_VERSION_CODE < 0x20200  || defined(__alpha__)
+                       if (pkt_len < rx_copybreak
+                               && (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+                               skb->dev = dev;
+                               skb_reserve(skb, 2);    /* 16 byte align the IP header */
+#if LINUX_VERSION_CODE < 0x10300
+                               memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
+#elif LINUX_VERSION_CODE < 0x20200  || defined(__alpha__)
                                memcpy(skb_put(skb, pkt_len),
-                                          bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len);
+                                          bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
 #else
-#ifdef ORIGINAL_TEXT
 #warning Code untested
-#else
-#error Code is wrong, and it has nothing to do with 2.2 :-)
+                               eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+                                                                pkt_len, 0);
+                               skb_put(skb, pkt_len);
 #endif
-                               eth_copy_and_sum(skb, bus_to_virt(lp->rx_ring[entry].buffer1),
-                                                                       pkt_len, 0);
+                               work_done++;
+                       } else {        /* Pass up the skb already on the Rx ring. */
+                               skb = tp->rx_skbuff[entry];
+                               tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+                               {
+                                       void *temp = skb_put(skb, pkt_len);
+                                       if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+                                               printk(KERN_ERR "%s: Internal consistency error! The "
+                                                  "skbuff addresses do not match in tulip_rx:"
+                                                          " %p vs. %p / %p.\n", dev->name,
+                                                          bus_to_virt(tp->rx_ring[entry].buffer1),
+                                                          skb->head, temp);
+                               }
+#else
                                skb_put(skb, pkt_len);
 #endif
                        }
@@ -2241,57 +2428,49 @@ memory_squeeze:
                        skb->protocol = eth_type_trans(skb, dev);
 #else
                        skb->len = pkt_len;
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-semi_gone:
 #endif
                        netif_rx(skb);
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-                       if (netdev_dropping) {
-throttle:
-                               if (lp->fc_bit) {
-                                       outl(lp->csr6 | 0x2000, dev->base_addr + CSR6);
-                                       set_bit(lp->fc_bit, &netdev_fc_xoff);
-                               }
-                       }
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-gone:
-#endif
-                       lp->stats.rx_packets++;
-#ifndef ORIGINAL_TEXT
-                       lp->stats.rx_bytes += pkt_len;
+                       dev->last_rx = jiffies;
+                       tp->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+                       tp->stats.rx_bytes += pkt_len;
 #endif
                }
+               entry = (++tp->cur_rx) % RX_RING_SIZE;
+       }
 
-               lp->rx_ring[entry].status = 0x80000000;
-               entry = (++lp->cur_rx) % RX_RING_SIZE;
+       /* Refill the Rx ring buffers. */
+       for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+               entry = tp->dirty_rx % RX_RING_SIZE;
+               if (tp->rx_skbuff[entry] == NULL) {
+                       struct sk_buff *skb;
+                       skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
+                       if (skb == NULL)
+                               break;
+                       skb->dev = dev;                 /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+                       tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+#else
+                       tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
+#endif
+                       work_done++;
+               }
+               tp->rx_ring[entry].status = 0x80000000;
        }
 
-       return 0;
+       return work_done;
 }
 
 static int
 tulip_close(struct device *dev)
 {
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
        int i;
 
-#ifdef CONFIG_NET_FASTROUTE
-       dev->tx_semaphore = 0;
-#endif
        dev->start = 0;
        dev->tbusy = 1;
 
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-       if (tp->fc_bit) {
-               int bit = tp->fc_bit;
-               tp->fc_bit = 0;
-               netdev_unregister_fc(bit);
-       }
-#endif
-
        if (tulip_debug > 1)
                printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
                           dev->name, inl(ioaddr + CSR5));
@@ -2326,12 +2505,20 @@ tulip_close(struct device *dev)
 #if LINUX_VERSION_CODE < 0x20100
                        skb->free = 1;
 #endif
+#if (LINUX_VERSION_CODE > 0x20155)
                        dev_kfree_skb(skb);
+#else
+                       dev_kfree_skb(skb, FREE_WRITE);
+#endif
                }
        }
        for (i = 0; i < TX_RING_SIZE; i++) {
                if (tp->tx_skbuff[i])
+#if (LINUX_VERSION_CODE > 0x20155)
                        dev_kfree_skb(tp->tx_skbuff[i]);
+#else
+                       dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+#endif
                tp->tx_skbuff[i] = 0;
        }
 
@@ -2345,7 +2532,7 @@ static struct enet_statistics *
 tulip_get_stats(struct device *dev)
 {
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
 
        if (dev->start)
                tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
@@ -2353,6 +2540,71 @@ tulip_get_stats(struct device *dev)
        return &tp->stats;
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       long ioaddr = dev->base_addr;
+       u16 *data = (u16 *)&rq->ifr_data;
+       int phy = tp->phys[0] & 0x1f;
+       long flags;
+
+       switch(cmd) {
+       case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+               if (tp->mtable  &&  tp->mtable->has_mii)
+                       data[0] = phy;
+               else if (tp->chip_id == DC21142)
+                       data[0] = 32;
+               else
+                       return -ENODEV;
+               return 0;
+       case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+               if (data[0] == 32) {  /* 21142 pseudo-MII */
+                       int csr12 = inl(ioaddr + CSR12);
+                       int csr14 = inl(ioaddr + CSR14);
+                       switch (data[1]) {
+                       case 0: {
+                               data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+                               break; }
+                       case 1:
+                               data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+                                       + (csr12&0x06 ? 0x04 : 0);
+                               break;
+                       case 4: {
+                               int csr14 = inl(ioaddr + CSR14);
+                               data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+                               break;
+                       }
+                       case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+                       default: data[3] = 0; break;
+                       }
+               } else {
+                       save_flags(flags);
+                       cli();
+                       data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+                       restore_flags(flags);
+               }
+               return 0;
+       case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+               if (!suser())
+                       return -EPERM;
+               if (data[0] == 32) {  /* 21142 pseudo-MII */
+               } else {
+                       save_flags(flags);
+                       cli();
+                       mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+                       restore_flags(flags);
+               }
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
    new frame, not around filling tp->setup_frame.  This is non-deterministic
@@ -2380,12 +2632,12 @@ static inline unsigned ether_crc_le(int length, unsigned char *data)
 }
 
 #ifdef NEW_MULTICAST
-static void set_multicast_list(struct device *dev)
+static void set_rx_mode(struct device *dev)
 #else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
 #endif
 {
-       int ioaddr = dev->base_addr;
+       long ioaddr = dev->base_addr;
        int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
        struct tulip_private *tp = (struct tulip_private *)dev->priv;
 
@@ -2442,9 +2694,9 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
                }
                eaddrs = (u16 *)dev->dev_addr;
                do {
-                 *setup_frm++ = eaddrs[0];
-                 *setup_frm++ = eaddrs[1];
-                 *setup_frm++ = eaddrs[2];
+                       *setup_frm++ = eaddrs[0];
+                       *setup_frm++ = eaddrs[1];
+                       *setup_frm++ = eaddrs[2];
                } while (++i < 15);
                /* Now add this frame to the Tx list. */
                if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
@@ -2457,19 +2709,19 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
                        entry = tp->cur_tx++ % TX_RING_SIZE;
 
                        if (entry != 0) {
-                         /* Avoid a chip errata by prefixing a dummy entry. */
-                         tp->tx_skbuff[entry] = 0;
-                         tp->tx_ring[entry].length =
-                               (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
-                         tp->tx_ring[entry].buffer1 = 0;
-                         tp->tx_ring[entry].status = 0x80000000;
-                         entry = tp->cur_tx++ % TX_RING_SIZE;
+                               /* Avoid a chip errata by prefixing a dummy entry. */
+                               tp->tx_skbuff[entry] = 0;
+                               tp->tx_ring[entry].length =
+                                       (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+                               tp->tx_ring[entry].buffer1 = 0;
+                               tp->tx_ring[entry].status = 0x80000000;
+                               entry = tp->cur_tx++ % TX_RING_SIZE;
                        }
 
                        tp->tx_skbuff[entry] = 0;
                        /* Put the setup frame on the Tx list. */
                        if (entry == TX_RING_SIZE-1)
-                         tx_flags |= 0x02000000;               /* Wrap ring. */
+                               tx_flags |= 0x02000000;         /* Wrap ring. */
                        tp->tx_ring[entry].length = tx_flags;
                        tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
                        tp->tx_ring[entry].status = 0x80000000;
@@ -2484,16 +2736,70 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
                outl(csr6 | 0x0000, ioaddr + CSR6);
        }
 }
+\f
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+       u16 dev_id;
+       u32 io;
+       u8 bus, devfn;
+       struct device *dev;
+
+       if (loc->bus != LOC_PCI) return NULL;
+       bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+       printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
+       pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+       pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+       io &= ~3;
+       dev = tulip_probe1(bus, devfn, NULL, DC21142, -1);
+       if (dev) {
+               dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+               strcpy(node->dev_name, dev->name);
+               node->major = node->minor = 0;
+               node->next = NULL;
+               MOD_INC_USE_COUNT;
+               return node;
+       }
+       return NULL;
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+       struct device **devp, **next;
+       printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
+       for (devp = &root_tulip_dev; *devp; devp = next) {
+               next = &((struct tulip_private *)(*devp)->priv)->next_module;
+               if (strcmp((*devp)->name, node->dev_name) == 0) break;
+       }
+       if (*devp) {
+               unregister_netdev(*devp);
+               kfree(*devp);
+               *devp = *next;
+               kfree(node);
+               MOD_DEC_USE_COUNT;
+       }
+}
+
+struct driver_operations tulip_ops = {
+       "tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+};
+
+#endif  /* Cardbus support */
+
 \f
 #ifdef MODULE
 #if LINUX_VERSION_CODE > 0x20118
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
 MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(reverse_probe, "i");
 MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 #endif
 
 /* An additional parameter that may be passed in... */
@@ -2505,8 +2811,12 @@ init_module(void)
        if (debug >= 0)
                tulip_debug = debug;
 
-       root_tulip_dev = NULL;
+#ifdef CARDBUS
+       register_driver(&tulip_ops);
+       return 0;
+#else
        return tulip_probe(NULL);
+#endif
 }
 
 void
@@ -2514,6 +2824,10 @@ cleanup_module(void)
 {
        struct device *next_dev;
 
+#ifdef CARDBUS
+       unregister_driver(&tulip_ops);
+#endif
+
        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
        while (root_tulip_dev) {
                next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
@@ -2528,7 +2842,8 @@ cleanup_module(void)
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
index 84bfe986355938378314203073081182f3b6f0f7..483d2f8968b600852f71052ed5fe0166e74877e3 100644 (file)
@@ -632,7 +632,9 @@ void nubus_init(void)
        nubus_init_via();
        printk("Scanning nubus slots.\n");
        nubus_probe_bus();
+#ifdef CONFIG_PROC_FS
        proc_register(&proc_root, &proc_nubus);
+#endif
 }
 
        
\ No newline at end of file
index 2ecc6c85b70816cc5a8cef33ba2324f0f23c8e7c..afbb68c75953a3e533d3f8007afcbf318c852749 100644 (file)
@@ -338,6 +338,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( VIA,            VIA_86C100A,    "VT 86C100A"),
        DEVICE( VIA,            VIA_82C597_1,   "VT 82C597 Apollo VP3 AGP"),
        DEVICE( VIA,            VIA_82C598_1,   "VT 82C598 Apollo MVP3 AGP"),
+       DEVICE( SMC2,           SMC2_1211TX,    "1211 TX"),
        DEVICE( VORTEX,         VORTEX_GDT60x0, "GDT 60x0"),
        DEVICE( VORTEX,         VORTEX_GDT6000B,"GDT 6000b"),
        DEVICE( VORTEX,         VORTEX_GDT6x10, "GDT 6110/6510"),
@@ -482,6 +483,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( S3,             S3_ViRGE_MXP,   "ViRGE/MX+"),
        DEVICE( S3,             S3_ViRGE_MXPMV, "ViRGE/MX+MV"),
        DEVICE( S3,             S3_SONICVIBES,  "SonicVibes"),
+       DEVICE( DCI,            DCI_PCCOM4,     "PC COM PCI Bus 4 port serial Adapter"),
        DEVICE( INTEL,          INTEL_82375,    "82375EB"),
        DEVICE( INTEL,          INTEL_82424,    "82424ZX Saturn"),
        DEVICE( INTEL,          INTEL_82378,    "82378IB"),
@@ -739,6 +741,7 @@ static const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_INIT:          return "Initio Corp";
              case PCI_VENDOR_ID_TTI:           return "Triones Technologies, Inc.";
              case PCI_VENDOR_ID_VIA:           return "VIA Technologies";
+             case PCI_VENDOR_ID_SMC2:          return "SMC";
              case PCI_VENDOR_ID_VORTEX:        return "VORTEX";
              case PCI_VENDOR_ID_EF:            return "Efficient Networks";
              case PCI_VENDOR_ID_FORE:          return "Fore Systems";
@@ -787,6 +790,7 @@ static const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_AVANCE:        return "Avance";
              case PCI_VENDOR_ID_NETVIN:        return "NetVin";
              case PCI_VENDOR_ID_S3:            return "S3 Inc.";
+             case PCI_VENDOR_ID_DCI:           return "Decision Computer Int.";
              case PCI_VENDOR_ID_INTEL:         return "Intel";
              case PCI_VENDOR_ID_KTI:           return "KTI";
              case PCI_VENDOR_ID_ADAPTEC:       return "Adaptec";
index 0f3daef14b570f53097fe4fd104dd4c56f3f2aee..30ddde6a34c45ff5620d19bb9b7e1910b78a1289 100644 (file)
@@ -50,7 +50,7 @@ dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) supp
   fi
 dep_tristate 'EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
-dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
+dep_tristate 'Future Domain 16xx SCSI/AHA-2920A support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 if [ "$CONFIG_MCA" = "y" ]; then
   if [ "$CONFIG_SCSI" = "y" ]; then
     bool 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS
@@ -116,7 +116,7 @@ dep_tristate 'PSI240i support' CONFIG_SCSI_PSI240I $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
-  dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
+# dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
index c5c7337390155ec9a3497ca1a3179f03ab49b157..dc46aa27e9b02b5934ef1f31722b59e70be6134e 100644 (file)
@@ -3941,6 +3941,8 @@ int
 advansys_proc_info(char *buffer, char **start, off_t offset, int length, 
                    int hostno, int inout)
 {
+#ifdef CONFIG_PROC_FS
+
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
     int                 i;
@@ -4147,9 +4149,12 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
     ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
 
     return totcnt;
+#else /* CONFIG_PROC_FS */
+    return 0;
+#endif /* CONFIG_PROC_FS */
+
 }
 #endif /* version >= v1.3.0 */
-
 /*
  * advansys_detect()
  *
index 189b7a5e6091dd7f32f6981687f7104c3e1e3740..4ec4c06c88127f69fdc0b0a7bdca74c2b20f0e5c 100644 (file)
@@ -962,7 +962,7 @@ char * get_board_data(u32 base, u32 irq, u32 id)
     eata_send_command((u32) cp, (u32) base, EATA_CMD_DMA_SEND_CP);
     
     i = jiffies + (3 * HZ);
-    while (fake_int_happened == FALSE && jiffies <= i
+    while (fake_int_happened == FALSE && time_before_eq(jiffies, i)
        barrier();
     
     DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x "
@@ -973,7 +973,7 @@ char * get_board_data(u32 base, u32 irq, u32 id)
     scsi_init_free((void *)cp, sizeof(struct eata_ccb));
     scsi_init_free((void *)sp, sizeof(struct eata_sp));
     
-    if ((fake_int_result & HA_SERROR) || jiffies > i){
+    if ((fake_int_result & HA_SERROR) || time_after(jiffies, i)){
        printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear "
               "possible blink state\n", base); 
        /* hard reset the HBA  */
index 267d8bf82a545bef62bdec765ecc5afb1978a39d..d9eda89f1e2b9ca111b4032b06df299e6e48b1eb 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 
 void swap_statistics(u8 *p)
 {
@@ -68,6 +69,8 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
                   int hostno, int inout)
 {
 
+#ifdef CONFIG_PROC_FS
+
     Scsi_Device *scd, SDev;
     struct Scsi_Host *HBA_ptr;
     Scsi_Cmnd scmd;
@@ -466,6 +469,9 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
     DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
     return (len);     
+#else /* CONFIG_PROC_FS */
+    return 0;
+#endif        
 }
 
 /*
index d35c32d07ea4b43c131029542c3334ac22c05443..a706a8e7f2f19470dd0876321845b090f90d78e8 100644 (file)
@@ -500,7 +500,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy)
     HD(cmd)->state = RESET;
     
     time = jiffies;
-    while (jiffies < (time + (3 * HZ)) && limit++ < 10000000);
+    while (time_before(jiffies, time + 3 * HZ) && limit++ < 10000000);
     
     DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "
                            "loops %d.\n", limit));
index 8290533156660ce50288d985fca15b6f5884b455..4ccc65182233b12cc2a3dc667931ef6555e94645 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/config.h>
+
 /*
  * eata_set_info
  * buffer : pointer to the data that has been written to the hostfile
@@ -24,7 +26,7 @@ int eata_pio_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
 int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length, 
                       int hostno, int inout)
 {
-
+#ifdef CONFIG_PROC_FS
     Scsi_Device *scd;
     struct Scsi_Host *HBA_ptr;
     static u8 buff[512];
@@ -108,6 +110,9 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
     DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
     return (len);     
+#else
+    return 0;
+#endif        
 }
 
 /*
index 3c26b45571cb6bdd3a32dca0c4e46083acea47ef..760b3fbc5617389c2df5ef16b2ba88ceb9da3de5 100644 (file)
@@ -1,10 +1,8 @@
 /* fdomain.c -- Future Domain TMC-16x0 SCSI driver
  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Wed Oct  2 11:10:55 1996 by faith@acm.org
+ * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org
  * Author: Rickard E. Faith, faith@cs.unc.edu
- * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
- *
- * Version 5.46 (23-04-1998)
+ * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org)
 
  * 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 the
     Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
     Future Domain TMC-3260 (PCI)
     Quantum ISA-200S, ISA-250MG
-    Adaptec AHA-2920 (PCI)
+    Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
     IBM ?
- LILO command-line options:
+ LILO/INSMOD command-line options:
     fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]
 
 
+    
+ NOTE:
+
+ The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
+ Use the aic7xxx driver for this board.
+       
+ The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
+ driver for that card.  Unfortunately, the boxes will probably just say
+ "2920", so you'll have to look on the card for a Future Domain logo, or a
+ letter after the 2920.
+
+ THANKS:
+
+ Thanks to Adaptec for providing PCI boards for testing.  This finally
+ enabled me to test the PCI detection and correct it for PCI boards that do
+ not have a BIOS at a standard ISA location.  For PCI boards, LILO/INSMOD
+ command-line options should no longer be needed.  --RF 18Nov98
+
 
  DESCRIPTION:
  
  This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
@@ -70,7 +89,7 @@
  your board.  Please refer to the Seagate driver for more information and
  possible support.
 
-
  
  HISTORY:
 
  2.1.1       5.45         2 Oct 1996  Update ROM accesses for 2.1.x
  2.1.97      5.46       23 Apr 1998  Rewritten PCI detection routines [mj]
  2.1.11x     5.47        9 Aug 1998  Touched for 8 SCSI disk majors support
-
+             5.48        18 Nov 1998  BIOS no longer needed for PCI detection
+ 2.2.0       5.50        28 Dec 1998  Support insmod parameters
  
 
  REFERENCES USED:
  patches.
 
  New PCI detection code written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+
+ Insmod parameter code based on patches from Daniel Graham
+ <graham@balance.uoregon.edu>. 
  
  All of the alpha testers deserve much thanks.
 
@@ -282,7 +305,7 @@ struct proc_dir_entry proc_scsi_fdomain = {
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
   
-#define VERSION          "$Revision: 5.45 $"
+#define VERSION          "$Revision: 5.50 $"
 
 /* START OF USER DEFINABLE OPTIONS */
 
@@ -406,6 +429,15 @@ static int               FIFO_Size = 0x2000; /* 8k FIFO for
 extern void              do_fdomain_16x0_intr( int irq, void *dev_id,
                                            struct pt_regs * regs );
 
+#ifdef MODULE
+                               /* Allow insmod parameters to be like LILO
+                                   parameters.  For example:
+                                  insmod fdomain fdomain=0x140,11
+                               */
+static int               fdomain[]={ 0, 0, 0 };
+MODULE_PARM(fdomain, "2-3i");
+#endif
+
 static unsigned long addresses[] = {
    0xc8000,
    0xca000,
@@ -504,10 +536,10 @@ static void print_banner( struct Scsi_Host *shpnt )
    if (!shpnt) return;         /* This won't ever happen */
 
    if (bios_major < 0 && bios_minor < 0) {
-      printk( "scsi%d <fdomain>: No BIOS; using scsi id %d\n",
+      printk( "scsi%d: <fdomain> No BIOS; using scsi id %d\n",
              shpnt->host_no, shpnt->this_id );
    } else {
-      printk( "scsi%d <fdomain>: BIOS version ", shpnt->host_no );
+      printk( "scsi%d: <fdomain> BIOS version ", shpnt->host_no );
 
       if (bios_major >= 0) printk( "%d.", bios_major );
       else                 printk( "?." );
@@ -523,7 +555,7 @@ static void print_banner( struct Scsi_Host *shpnt )
                                   boards, we will have to modify banner
                                   for additional PCI cards, but for now if
                                   it's PCI it's a TMC-3260 - JTM */
-   printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
+   printk( "scsi%d: <fdomain> %s chip at 0x%x irq ",
           shpnt->host_no,
           chip == tmc1800 ? "TMC-1800"
           : (chip == tmc18c50 ? "TMC-18C50"
@@ -541,8 +573,9 @@ static void print_banner( struct Scsi_Host *shpnt )
 void fdomain_setup( char *str, int *ints )
 {
    if (setup_called++ || ints[0] < 2 || ints[0] > 3) {
-      printk( "fdomain: usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n" );
-      printk( "fdomain: bad LILO parameters?\n" );
+      printk( "scsi: <fdomain>"
+             " Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n" );
+      printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
    }
 
    port_base       = ints[0] >= 1 ? ints[1] : 0;
@@ -591,8 +624,6 @@ static int fdomain_is_valid_port( int port )
       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
       chip = tmc18c50;
 
-#if 1
-
                                /* Try to toggle 32-bit mode.  This only
                                   works on an 18c30 chip.  (User reports
                                   say this works, so we should switch to
@@ -606,17 +637,6 @@ static int fdomain_is_valid_port( int port )
            FIFO_Size = 0x800;  /* 2k FIFO */
         }
       }
-#else
-
-                               /* That should have worked, but appears to
-                                  have problems.  Let's assume it is an
-                                  18c30 if the RAM is disabled. */
-
-      if (inb( port + Configuration2 ) & 0x02) {
-        chip      = tmc18c30;
-        FIFO_Size = 0x800;     /* 2k FIFO */
-      }
-#endif
                                /* If that failed, we are an 18c50. */
    }
 
@@ -656,7 +676,7 @@ static int fdomain_get_irq( int base )
    int options = inb( base + Configuration1 );
 
 #if DEBUG_DETECT
-   printk( " Options = %x\n", options );
+   printk( "scsi: <fdomain> Options = %x\n", options );
 #endif
    
                                /* Check for board with lowest bios_base --
@@ -673,10 +693,31 @@ static int fdomain_get_irq( int base )
 
 static int fdomain_isa_detect( int *irq, int *iobase )
 {
-   int i;
+   int i, j;
    int base;
    int flag = 0;
 
+#if DEBUG_DETECT
+   printk( "scsi: <fdomain> fdomain_isa_detect:" );
+#endif
+
+   for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
+#if DEBUG_DETECT
+      printk( " %lx(%lx),", addresses[i], bios_base );
+#endif
+      for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
+        if (check_signature(addresses[i] + signatures[j].sig_offset,
+                            signatures[j].signature,
+                            signatures[j].sig_length )) {
+           bios_major = signatures[j].major_bios_version;
+           bios_minor = signatures[j].minor_bios_version;
+           PCI_bus    = (signatures[j].flag == 1);
+           Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
+           bios_base  = addresses[i];
+        }
+      }
+   }
+   
    if (bios_major == 2) {
       /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
         Assuming the ROM is enabled (otherwise we wouldn't have been
@@ -746,6 +787,11 @@ static int fdomain_isa_detect( int *irq, int *iobase )
       if ((flag = fdomain_is_valid_port( base ))) break;
    }
 
+#if DEBUG_DETECT
+   if (flag) printk( " SUCCESS\n" );
+   else      printk( " FAILURE\n" );
+#endif
+
    if (!flag) return 0;                /* iobase not found */
 
    *irq    = fdomain_get_irq( base );
@@ -771,18 +817,21 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
    /* Tell how to print a list of the known PCI devices from bios32 and
       list vendor and device IDs being used if in debug mode.  */
       
-   printk( "\nINFO: use lspci -v to see list of PCI devices\n" );
-   printk( "\nTMC-3260 detect:"
-          " Using PCI Vendor ID: 0x%x, PCI Device ID: 0x%x\n",
+   printk( "scsi: <fdomain> INFO: use lspci -v to see list of PCI devices\n" );
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+          " Using Vendor ID: 0x%x and Device ID: 0x%x\n",
           PCI_VENDOR_ID_FD, 
           PCI_DEVICE_ID_FD_36C70 );
 #endif 
 
-   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD,
+                              PCI_DEVICE_ID_FD_36C70,
+                              pdev)) == NULL)
      return 0;
        
 #if DEBUG_DETECT
-   printk( "Future Domain 36C70 : at PCI bus %u, device %u, function %u\n",
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+          " PCI bus %u, device %u, function %u\n",
           pdev->bus->number,
           PCI_SLOT(pdev->devfn),
           PCI_FUNC(pdev->devfn));
@@ -793,10 +842,6 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
 
    pci_base = pdev->base_address[0];
    pci_irq = pdev->irq;
-#if DEBUG_DETECT
-      printk( "TMC-3260 PCI: IRQ = %u, I/O base = 0x%lx\n", 
-             pci_irq, pci_base );
-#endif
 
    /* Now we have the I/O base address and interrupt from the PCI
       configuration registers. */
@@ -805,18 +850,28 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase )
    *iobase = (pci_base & PCI_BASE_ADDRESS_IO_MASK);
 
 #if DEBUG_DETECT
-   printk( "TMC-3260 fix: Masking I/O base address with 0xff00.\n" ); 
-   printk( "TMC-3260: IRQ = %d, I/O base = 0x%x\n", *irq, *iobase );
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+          " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base );
 #endif
 
-   if (!fdomain_is_valid_port( *iobase )) return 0;
+   if (!fdomain_is_valid_port( *iobase )) {
+      printk( "scsi: <fdomain>"
+             " PCI card detected, but driver not loaded (invalid port)\n" );
+      return 0;
+   }
+
+                               /* Fill in a few global variables.  Ugh. */
+   bios_major = bios_minor = -1;
+   PCI_bus    = 1;
+   Quantum    = 0;
+   bios_base  = 0;
+   
    return 1;
 }
 #endif
 
 int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
 {
-   int              i, j;
    int              retcode;
    struct Scsi_Host *shpnt;
 #if DO_DETECT
@@ -829,68 +884,44 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
    unsigned char    buf[buflen];
 #endif
 
-#if DEBUG_DETECT
-   printk( "fdomain_16x0_detect()," );
-#endif
    tpnt->proc_dir = &proc_scsi_fdomain;
 
+#ifdef MODULE
+   if (fdomain[0] || fdomain[1] || fdomain[2]) {
+      port_base       = fdomain[0];
+      interrupt_level = fdomain[1];
+      this_id         = fdomain[2];
+      bios_major = bios_minor = -1;
+      ++setup_called;
+   }
+#endif
+   
    if (setup_called) {
 #if DEBUG_DETECT
-      printk( "no BIOS, using port_base = 0x%x, irq = %d\n",
+      printk( "scsi: <fdomain> No BIOS, using port_base = 0x%x, irq = %d\n",
              port_base, interrupt_level );
 #endif
       if (!fdomain_is_valid_port( port_base )) {
-        printk( "fdomain: cannot locate chip at port base 0x%x\n",
+        printk( "scsi: <fdomain> Cannot locate chip at port base 0x%x\n",
                 port_base );
-        printk( "fdomain: bad LILO parameters?\n" );
+        printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
         return 0;
       }
    } else {
       int flag = 0;
-      
-      for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
-#if DEBUG_DETECT
-        printk( " %lx(%lx),", addresses[i], bios_base );
-#endif
-        for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
-           if (check_signature(addresses[i] + signatures[j].sig_offset,
-                               signatures[j].signature,
-                               signatures[j].sig_length )) {
-              bios_major = signatures[j].major_bios_version;
-              bios_minor = signatures[j].minor_bios_version;
-              PCI_bus    = (signatures[j].flag == 1);
-              Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
-              bios_base  = addresses[i];
-           }
-        }
-      }
-
-      if (!bios_base) {
-#if DEBUG_DETECT
-        printk( " FAILED: NO BIOS\n" );
-#endif
-        return 0;
-      }
 
-      if (!PCI_bus) {
-        flag = fdomain_isa_detect( &interrupt_level, &port_base );
-      } else {
 #ifdef CONFIG_PCI
-        flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );
-#else
-        printk(KERN_ERR "No PCI support in this kernel, giving up.\n");
-        flag = 0;
+                               /* Try PCI detection first */
+      flag = fdomain_pci_bios_detect( &interrupt_level, &port_base );
 #endif
-      }
-        
       if (!flag) {
-#if DEBUG_DETECT
-        printk( " FAILED: NO PORT\n" );
-#endif
-#ifdef CONFIG_PCI
-        printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" );
-#endif
-        return 0;              /* Cannot find valid set of ports */
+                               /* Then try ISA bus detection */
+        flag = fdomain_isa_detect( &interrupt_level, &port_base );
+
+        if (!flag) {
+           printk( "scsi: <fdomain> Detection failed (no card)\n" );
+           return 0;
+        }
       }
    }
 
@@ -911,13 +942,10 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
    fdomain_16x0_reset( NULL, 0 );
 
    if (fdomain_test_loopback()) {
-#if DEBUG_DETECT
-      printk( "fdomain: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
-#endif
+      printk( "scsi: <fdomain> Detection failed"
+             " (loopback test failed at port base 0x%x)\n", port_base );
       if (setup_called) {
-        printk( "fdomain: loopback test failed at port base 0x%x\n",
-                port_base );
-        printk( "fdomain: bad LILO parameters?\n" );
+        printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
       }
       return 0;
    }
@@ -946,7 +974,9 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
 
                                /* Log IRQ with kernel */   
    if (!interrupt_level) {
-      panic( "fdomain: *NO* interrupt level selected!\n" );
+      printk( "scsi: <fdomain>"
+             " Card Detected, but driver not loaded (no IRQ)\n" );
+      return 0;
    } else {
       /* Register the IRQ with the kernel */
 
@@ -955,18 +985,21 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
 
       if (retcode < 0) {
         if (retcode == -EINVAL) {
-           printk( "fdomain: IRQ %d is bad!\n", interrupt_level );
-           printk( "         This shouldn't happen!\n" );
-           printk( "         Send mail to faith@acm.org\n" );
+           printk( "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level );
+           printk( "                This shouldn't happen!\n" );
+           printk( "                Send mail to faith@acm.org\n" );
         } else if (retcode == -EBUSY) {
-           printk( "fdomain: IRQ %d is already in use!\n", interrupt_level );
-           printk( "         Please use another IRQ!\n" );
+           printk( "scsi: <fdomain> IRQ %d is already in use!\n",
+                   interrupt_level );
+           printk( "                Please use another IRQ!\n" );
         } else {
-           printk( "fdomain: Error getting IRQ %d\n", interrupt_level );
-           printk( "         This shouldn't happen!\n" );
-           printk( "         Send mail to faith@acm.org\n" );
+           printk( "scsi: <fdomain> Error getting IRQ %d\n",
+                   interrupt_level );
+           printk( "                This shouldn't happen!\n" );
+           printk( "                Send mail to faith@acm.org\n" );
         }
-        panic( "fdomain: Driver requires interruptions\n" );
+        printk( "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
+        return 0;
       }
    }
 
@@ -987,7 +1020,7 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
    SCinit.use_sg          = 0;
    SCinit.lun             = 0;
 
-   printk( "fdomain: detection routine scanning for devices:\n" );
+   printk( "scsi: <fdomain> detection routine scanning for devices:\n" );
    for (i = 0; i < 8; i++) {
       SCinit.target = i;
       if (i == tpnt->this_id)  /* Skip host adapter */
@@ -1031,10 +1064,10 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
 
 const char *fdomain_16x0_info( struct Scsi_Host *ignore )
 {
-   static char buffer[80];
+   static char buffer[128];
    char        *pt;
    
-   strcpy( buffer, "Future Domain TMC-16x0 SCSI driver, version" );
+   strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" );
    if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */
       strcat( buffer, strchr( VERSION, ':' ) + 1 );
       pt = strrchr( buffer, '$') - 1;
@@ -1118,7 +1151,7 @@ static int fdomain_arbitrate( void )
    printk( "Arbitration failed, status = %x\n", status );
 #endif
 #if ERRORS_ONLY
-   printk( "fdomain: Arbitration failed, status = %x\n", status );
+   printk( "scsi: <fdomain> Arbitration failed, status = %x\n", status );
 #endif
    return 1;
 }
@@ -1158,7 +1191,7 @@ static int fdomain_select( int target )
       if (!flag) /* Skip first failure for all chips. */
            ++flag;
       else
-           printk( "fdomain: Selection failed\n" );
+           printk( "scsi: <fdomain> Selection failed\n" );
    }
 #endif
    return 1;
@@ -1173,9 +1206,9 @@ void my_done( int error )
       current_SC->result = error;
       if (current_SC->scsi_done)
            current_SC->scsi_done( current_SC );
-      else panic( "fdomain: current_SC->scsi_done() == NULL" );
+      else panic( "scsi: <fdomain> current_SC->scsi_done() == NULL" );
    } else {
-      panic( "fdomain: my_done() called outside of command\n" );
+      panic( "scsi: <fdomain> my_done() called outside of command\n" );
    }
 #if DEBUG_RACE
    in_interrupt_flag = 0;
@@ -1211,7 +1244,7 @@ void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
    /* Abort calls my_done, so we do nothing here. */
    if (current_SC->SCp.phase & aborted) {
 #if DEBUG_ABORT
-      printk( "Interrupt after abort, ignoring\n" );
+      printk( "scsi: <fdomain> Interrupt after abort, ignoring\n" );
 #endif
       /*
       return; */
@@ -1311,7 +1344,7 @@ void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
         if (current_SC->SCp.Status
             && current_SC->SCp.Status != 2
             && current_SC->SCp.Status != 8) {
-           printk( "fdomain: target = %d, command = %x, status = %x\n",
+           printk( "scsi: <fdomain> target = %d, command = %x, status = %x\n",
                    current_SC->target,
                    current_SC->cmnd[0],
                    current_SC->SCp.Status );
@@ -1329,7 +1362,8 @@ void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
         if (!current_SC->SCp.Message) ++done;
 #if DEBUG_MESSAGES || EVERY_ACCESS
         if (current_SC->SCp.Message) {
-           printk( "fdomain: message = %x\n", current_SC->SCp.Message );
+           printk( "scsi: <fdomain> message = %x\n",
+                   current_SC->SCp.Message );
         }
 #endif
         break;
@@ -1590,8 +1624,8 @@ void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
                                                || code == 0x24
                                                || !code)))
                  
-                 printk( "fdomain: REQUEST SENSE "
-                         "Key = %x, Code = %x, Qualifier = %x\n",
+                 printk( "scsi: <fdomain> REQUEST SENSE"
+                         " Key = %x, Code = %x, Qualifier = %x\n",
                          key, code, qualifier );
         }
       }
@@ -1624,7 +1658,7 @@ void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
 int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
    if (in_command) {
-      panic( "fdomain: fdomain_16x0_queue() NOT REENTRANT!\n" );
+      panic( "scsi: <fdomain> fdomain_16x0_queue() NOT REENTRANT!\n" );
    }
 #if EVERY_ACCESS
    printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
@@ -1704,7 +1738,8 @@ void print_info( Scsi_Cmnd *SCpnt )
    unsigned int isr;
 
    if (!SCpnt || !SCpnt->host) {
-      printk( "fdomain: cannot provide detailed information\n" );
+      printk( "scsi: <fdomain> Cannot provide detailed information\n" );
+      return;
    }
    
    printk( "%s\n", fdomain_16x0_info( SCpnt->host ) );
@@ -1770,7 +1805,7 @@ int fdomain_16x0_abort( Scsi_Cmnd *SCpnt)
 {
    unsigned long flags;
 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
-   printk( "fdomain: abort " );
+   printk( "scsi: <fdomain> abort " );
 #endif
 
    save_flags( flags );
@@ -1808,7 +1843,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt, unsigned int ignored )
 #endif
 
 #if ERRORS_ONLY
-   if (SCpnt) printk( "fdomain: SCSI Bus Reset\n" );
+   if (SCpnt) printk( "scsi: <fdomain> SCSI Bus Reset\n" );
 #endif
 
 #if DEBUG_RESET
@@ -1893,7 +1928,7 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array )
     */
 
    if (MAJOR(dev) != SCSI_DISK0_MAJOR) {
-      printk("fdomain_16x0_biosparam: too many disks");
+      printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
       return 0;
    }
    drive = MINOR(dev) >> 4;
index 0b1337581d2f99bfcf361f4a75853997510a58b3..bd65b5e8487591dda9d6122c48532b16bc793ce1 100644 (file)
@@ -1567,7 +1567,7 @@ ibmmca_detect (Scsi_Host_Template * template)
 
   /* first look for the SCSI integrated on the motherboard */
   pos2 = mca_read_stored_pos(MCA_INTEGSCSI, 2);
-  if (pos2 != 0xff) {
+//  if (pos2 != 0xff) {
     if ((pos2 & 1) == 0) {
       port = IM_IO_PORT + ((pos2 & 0x0e) << 2);
     } else {
@@ -1584,7 +1584,7 @@ ibmmca_detect (Scsi_Host_Template * template)
           mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
                                  shpnt);
         }
-    }
+//    }
 
   /* now look for other adapters */
   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
index c08589b58836757ed44533564ba0592f356879a9..316d661b5c82d99be412142eafb000a17b392a20 100644 (file)
@@ -1346,11 +1346,11 @@ handle_reset(struct mesh_state *ms)
 static void
 do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
-       /*unsigned long flags;*/
+       unsigned long flags;
 
-       /*spin_lock_irqsave(&io_request_lock, flags);*/
+       spin_lock_irqsave(&io_request_lock, flags);
        mesh_interrupt(irq, dev_id, ptregs);
-       /*spin_unlock_irqrestore(&io_request_lock, flags);*/
+       spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 static void handle_error(struct mesh_state *ms)
@@ -1643,6 +1643,7 @@ mesh_done(struct mesh_state *ms, int start_next)
 static void
 mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
 {
+#if 0
        if (ms->completed_q == NULL)
                ms->completed_q = cmd;
        else
@@ -1651,6 +1652,9 @@ mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
        cmd->host_scribble = NULL;
        queue_task(&ms->tqueue, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
+#else
+       (*cmd->scsi_done)(cmd);
+#endif
 }
 
 /*
index 2539774c667df1c8aaf74bec235dfeb1558bd975..13e80b23d3487dff569bc849567e3a4201e175f1 100644 (file)
@@ -319,7 +319,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #define ASKED_FOR_SENSE 0x20
 
 
-#ifdef __mc68000__
+#if defined(__mc68000__) || defined(CONFIG_APUS)
 #include <asm/pgtable.h>
 #define CONTIGUOUS_BUFFERS(X,Y) \
        (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data))
index 703fb42aa9129afb9a997eab67e21edd54d72c7f..ebfd9dda9698d6af49c96e595e289a8f6fbb6ba2 100644 (file)
@@ -379,8 +379,8 @@ static void __init borken_init (void)
 {
   register int count = 0, start = jiffies + 1, stop = start + 25;
 
-  while (jiffies < start) ;
-  for (; jiffies < stop; ++count) ;
+  while (time_before(jiffies, start)) ;
+  for (; time_before(jiffies, stop); ++count) ;
 
 /*
  * Ok, we now have a count for .25 seconds.  Convert to a
@@ -903,9 +903,9 @@ static int internal_command (unsigned char target, unsigned char lun,
 
       while (((STATUS | STATUS | STATUS) &
               (STAT_BSY | STAT_SEL)) &&
-             (!st0x_aborted) && (jiffies < clock));
+             (!st0x_aborted) && time_before(jiffies, clock));
 
-      if (jiffies > clock)
+      if (time_after(jiffies, clock))
         return retcode (DID_BUS_BUSY);
       else if (st0x_aborted)
         return retcode (st0x_aborted);
index 3ce29e72bb7b7d995915e035c9d7fc68637d8f43..0488cb353a26c79839a63dfff8405dd2afcabefc 100644 (file)
@@ -791,7 +791,7 @@ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned
     register unsigned WAITbits;
     register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
 
-    while (jiffies <= WAITtimeout) {
+    while (time_before_eq(jiffies, WAITtimeout)) {
        WAITbits = inb (port) & mask;
 
        if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
@@ -806,7 +806,7 @@ static inline void delay (unsigned how_long)
 {
     register unsigned long time = jiffies + how_long;
 
-    while (jiffies < time);
+    while (time_before(jiffies, time));
 }
 
 
@@ -868,7 +868,7 @@ static inline Scb *alloc_scbs (int needed)
            spin_unlock_irq(&io_request_lock);
            for (now = jiffies; now == jiffies; );      /* wait a jiffy */
            spin_lock_irq(&io_request_lock);
-       } while (freescbs < needed && jiffies <= timeout);
+       } while (freescbs < needed && time_before_eq(jiffies, timeout));
        /*
         *  If we get here with enough free Scbs, we can take them.
         *  Otherwise, we timed out and didn't get enough.
@@ -1247,7 +1247,7 @@ int wd7000_diagnostics (Adapter *host, int code)
      */
     mail_out (host, (struct scb *) &icb);
     timeout = jiffies + WAITnexttimeout;       /* wait up to 2 seconds */
-    while (icb.phase && jiffies < timeout)
+    while (icb.phase && time_before(jiffies, timeout))
        barrier ();             /* wait for completion */
 
     if (icb.phase) {
index 5fa5910dedbe6e766ff4f98b2cae88a9d1854f3f..77963cfe01879fac1ccd55106fc867731f9b07ee 100644 (file)
@@ -2084,8 +2084,7 @@ static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
        int utotal, ftotal;
 
        frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
+       userCount >>= (stereo? 2: 1);
        ftotal = frameLeft;
        utotal = userCount;
        while (frameLeft) {
@@ -2130,8 +2129,7 @@ static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
        int utotal, ftotal;
 
        frameLeft >>= 2;
-       if (stereo)
-               userCount >>= 1;
+       userCount >>= (stereo? 2: 1);
        ftotal = frameLeft;
        utotal = userCount;
        while (frameLeft) {
index 4b29613e58c602eaa067b71e55e14bed2fcbc3b6..ba950b0838906ed251872f7eea2c82a872af8c6c 100644 (file)
@@ -56,7 +56,9 @@ if [ "$CONFIG_INET" = "y" ]; then
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
   fi
-  tristate 'NFS server support' CONFIG_NFSD
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    tristate 'NFS server support' CONFIG_NFSD
+  fi
   if [ "$CONFIG_NFSD" != "n" ]; then
     bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
   fi
index db2ecc42d76780bcabf58a19222cf5ce12219fa4..bac1e059f1b32853bf36aafeb462ecf346faec5e 100644 (file)
@@ -424,10 +424,14 @@ void invalidate_buffers(kdev_t dev)
 
 static inline void remove_from_hash_queue(struct buffer_head * bh)
 {
-       if (bh->b_pprev) {
-               if(bh->b_next)
-                       bh->b_next->b_pprev = bh->b_pprev;
-               *bh->b_pprev = bh->b_next;
+       struct buffer_head **pprev = bh->b_pprev;
+       if (pprev) {
+               struct buffer_head * next = bh->b_next;
+               if (next) {
+                       next->b_pprev = pprev;
+                       bh->b_next = NULL;
+               }
+               *pprev = next;
                bh->b_pprev = NULL;
        }
 }
@@ -551,14 +555,19 @@ static inline void insert_into_queues(struct buffer_head * bh)
                nr_buffers_type[bh->b_list]++;
 
                /* Put the buffer in new hash-queue if it has a device. */
+               bh->b_next = NULL;
+               bh->b_pprev = NULL;
                if (bh->b_dev) {
                        struct buffer_head **bhp = &hash(bh->b_dev, bh->b_blocknr);
-                       if((bh->b_next = *bhp) != NULL)
-                               (*bhp)->b_pprev = &bh->b_next;
+                       struct buffer_head *next = *bhp;
+
+                       if (next) {
+                               bh->b_next = next;
+                               next->b_pprev = &bh->b_next;
+                       }
                        *bhp = bh;
-                       bh->b_pprev = bhp;      /* Exists in bh hashes. */
-               } else
-                       bh->b_pprev = NULL;     /* Not in bh hashes. */
+                       bh->b_pprev = bhp;
+               }
        }
 }
 
index 0bf373cf82dc0022b75c8459f42e5defa30a6594..89140d928757b94eb455246fad24105c5ca2e2b0 100644 (file)
@@ -475,7 +475,7 @@ void shrink_dcache_parent(struct dentry * parent)
  * too much.
  *
  * Priority:
- *   0 - very urgent: schrink everything
+ *   0 - very urgent: shrink everything
  *  ...
  *   6 - base-level: try to shrink a bit.
  */
index 9c45967c049317cea86f29b85707f811864e9da4..cd38e954281fc33385da262efa37e9a6a9c72120 100644 (file)
@@ -366,7 +366,9 @@ fat_read_super(struct super_block *sb, void *data, int silent)
                        CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
                fsinfo = (struct fat_boot_fsinfo *)
                        &bh->b_data[MSDOS_SB(sb)->fsinfo_offset];
-               if (CF_LE_L(fsinfo->signature) != 0x61417272) {
+               if ((MSDOS_SB(sb)->fsinfo_offset - sizeof(MSDOS_SB(sb)->fsinfo_offset) + 1)> bh->b_size) 
+                       printk("fat_read_super: Bad fsinfo_offset\n");
+               else if (CF_LE_L(fsinfo->signature) != 0x61417272) {
                        printk("fat_read_super: Did not find valid FSINFO "
                                "signature. Found 0x%x\n",
                                CF_LE_L(fsinfo->signature));
index 26c72dab9e689eb061c633e87247e106e22735ba..049a0cc15ac9ab9661103af6b672d04173fcada1 100644 (file)
@@ -409,11 +409,13 @@ static unsigned int isofs_get_last_session(kdev_t dev)
   struct cdrom_multisession ms_info;
   unsigned int vol_desc_start;
   struct inode inode_fake;
+  struct file_operations *fops;
   extern struct file_operations * get_blkfops(unsigned int);
   int i;
 
   vol_desc_start=0;
-  if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+  fops = get_blkfops(MAJOR(dev));
+  if (fops && fops->ioctl)
     {
       /* Whoops.  We must save the old FS, since otherwise
        * we would destroy the kernels idea about FS on root
@@ -536,17 +538,10 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
            vdp = (struct iso_volume_descriptor *)bh->b_data;
            hdp = (struct hs_volume_descriptor *)bh->b_data;
            
-           if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
-               if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
-                   goto out_freebh;
-               
-               s->u.isofs_sb.s_high_sierra = 1;
-               high_sierra = 1;
-               opt.rock = 'n';
-               h_pri = (struct hs_primary_descriptor *)vdp;
-               goto root_found;
-           }
-
+           /* Due to the overlapping physical location of the descriptors, 
+            * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 
+            * proper identification in this case, we first check for ISO.
+            */
            if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
                if (isonum_711 (vdp->type) == ISO_VD_END)
                    break;
@@ -580,9 +575,21 @@ struct super_block *isofs_read_super(struct super_block *s, void *data,
                    }
                }
 #endif
-               /* Just skip any volume descriptors we don't recognize */
+           } else {
+               if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+                   if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
+                       goto out_freebh;
+               
+                   s->u.isofs_sb.s_high_sierra = 1;
+                   high_sierra = 1;
+                   opt.rock = 'n';
+                   h_pri = (struct hs_primary_descriptor *)vdp;
+                   goto root_found;
+               }
            }
 
+            /* Just skip any volume descriptors we don't recognize */
+
            brelse(bh);
            bh = NULL;
        }
@@ -1105,8 +1112,9 @@ void isofs_read_inode(struct inode * inode)
        }
 
        /* There are defective discs out there - we do this to protect
-          ourselves.  A cdrom will never contain more than 800Mb */
-       if((inode->i_size < 0 || inode->i_size > 800000000) &&
+          ourselves.  A cdrom will never contain more than 800Mb 
+          .. but a DVD may be up to 1Gig (Ulrich Habel) */
+       if((inode->i_size < 0 || inode->i_size > 1073741824) &&
            inode->i_sb->u.isofs_sb.s_cruft == 'n') {
          printk("Warning: defective cdrom.  Enabling \"cruft\" mount option.\n");
          inode->i_sb->u.isofs_sb.s_cruft = 'y';
index 5f07b1c66dd6e9e0f522d4d5a420c10211184978..d50df7eacd4bbbe68037b4719a5c31dc5a728230 100644 (file)
@@ -125,7 +125,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
 
        /* If we're cleaning up locks because the process is exiting,
         * perform the RPC call asynchronously. */
-       if (cmd == F_SETLK && fl->fl_type == F_UNLCK
+       if ((cmd == F_SETLK || cmd == F_SETLKW)
+           && fl->fl_type == F_UNLCK
            && (current->flags & PF_EXITING)) {
                sigfillset(&current->blocked);  /* Mask all signals */
                recalc_sigpending(current);
@@ -144,7 +145,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
 
        if (cmd == F_GETLK) {
                status = nlmclnt_test(call, fl);
-       } else if (cmd == F_SETLK && fl->fl_type == F_UNLCK) {
+       } else if ((cmd == F_SETLK || cmd == F_SETLKW)
+                  && fl->fl_type == F_UNLCK) {
                status = nlmclnt_unlock(call, fl);
        } else if (cmd == F_SETLK || cmd == F_SETLKW) {
                call->a_args.block = (cmd == F_SETLKW)? 1 : 0;
index d4ab7fcc1b2c5a8f1ce6d1a85200e0d33ee2fe52..2bbc005cee0e584972accc3c36e690334d99338f 100644 (file)
@@ -92,7 +92,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
        /* Lock hash table */
        down(&nlm_host_sema);
 
-       if (time_after(jiffies, next_gc))
+       if (time_after_eq(jiffies, next_gc))
                nlm_gc_hosts();
 
        for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
@@ -173,19 +173,22 @@ nlm_bind_host(struct nlm_host *host)
        /* If we've already created an RPC client, check whether
         * RPC rebind is required */
        if ((clnt = host->h_rpcclnt) != NULL) {
-               if (time_after(jiffies, host->h_nextrebind)) {
+               if (time_after_eq(jiffies, host->h_nextrebind)) {
                        clnt->cl_port = 0;
                        host->h_nextrebind = jiffies + NLM_HOST_REBIND;
                        dprintk("lockd: next rebind in %ld jiffies\n",
                                        host->h_nextrebind - jiffies);
                }
        } else {
-               uid_t           saved_euid = current->euid;
+               uid_t saved_fsuid = current->fsuid;
+               kernel_cap_t saved_cap = current->cap_effective;
 
                /* Create RPC socket as root user so we get a priv port */
-               current->euid = 0;
+               current->fsuid = 0;
+               cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE);
                xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
-               current->euid = saved_euid;
+               current->fsuid = saved_fsuid;
+               current->cap_effective = saved_cap;
                if (xprt == NULL)
                        goto forgetit;
 
@@ -219,7 +222,7 @@ void
 nlm_rebind_host(struct nlm_host *host)
 {
        dprintk("lockd: rebind host %s\n", host->h_name);
-       if (host->h_rpcclnt && time_after(jiffies, host->h_nextrebind)) {
+       if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
                host->h_rpcclnt->cl_port = 0;
                host->h_nextrebind = jiffies + NLM_HOST_REBIND;
        }
@@ -298,7 +301,7 @@ nlm_gc_hosts(void)
                q = &nlm_hosts[i];
                while ((host = *q) != NULL) {
                        if (host->h_count || host->h_inuse
-                        || time_before_eq(jiffies, host->h_expires)) {
+                        || time_before(jiffies, host->h_expires)) {
                                q = &host->h_next;
                                continue;
                        }
index 2eac8d0253170af4a52f5e96153497b0d1d8f3d1..be9e0a5f35e626b7a4a51b79606166365b225aad 100644 (file)
@@ -136,7 +136,7 @@ lockd(struct svc_rqst *rqstp)
                 */
                if (!nlmsvc_grace_period) {
                        timeout = nlmsvc_retry_blocked();
-               } else if (time_after(jiffies, nlmsvc_grace_period))
+               } else if (time_before(nlmsvc_grace_period, jiffies))
                        nlmsvc_grace_period = 0;
 
                /*
index 585e2957fea5f78788088a90725f3c31f483ce35..2077752f4295f79677ce7a6deaa17bc74ea23f2f 100644 (file)
@@ -499,15 +499,22 @@ nlmsvc_callback_exit(struct rpc_task *task)
 /*
  * NLM Server procedures.
  */
-#define nlmsvc_proc_none       NULL
-#define nlmsvc_encode_norep    NULL
-#define nlmsvc_decode_norep    NULL
-#define nlmsvc_decode_testres  NULL
-#define nlmsvc_proc_test_res   NULL
-#define nlmsvc_proc_lock_res   NULL
-#define nlmsvc_proc_cancel_res NULL
-#define nlmsvc_proc_unlock_res NULL
-#define nlmsvc_proc_granted_res        NULL
+
+#define nlmsvc_encode_norep    nlmsvc_encode_void
+#define nlmsvc_decode_norep    nlmsvc_decode_void
+#define nlmsvc_decode_testres  nlmsvc_decode_void
+#define nlmsvc_decode_lockres  nlmsvc_decode_void
+#define nlmsvc_decode_unlockres        nlmsvc_decode_void
+#define nlmsvc_decode_cancelres        nlmsvc_decode_void
+#define nlmsvc_decode_grantedres       nlmsvc_decode_void
+
+#define nlmsvc_proc_none       nlmsvc_proc_null
+#define nlmsvc_proc_test_res   nlmsvc_proc_null
+#define nlmsvc_proc_lock_res   nlmsvc_proc_null
+#define nlmsvc_proc_cancel_res nlmsvc_proc_null
+#define nlmsvc_proc_unlock_res nlmsvc_proc_null
+#define nlmsvc_proc_granted_res        nlmsvc_proc_null
+
 struct nlm_void                        { int dummy; };
 
 #define PROC(name, xargt, xrest, argt, rest)   \
@@ -533,10 +540,10 @@ struct svc_procedure              nlmsvc_procedures[] = {
   PROC(unlock_msg,     unlockargs,     norep,          args,   void),
   PROC(granted_msg,    testargs,       norep,          args,   void),
   PROC(test_res,       testres,        norep,          res,    void),
-  PROC(lock_res,       res,            norep,          res,    void),
-  PROC(cancel_res,     res,            norep,          res,    void),
-  PROC(unlock_res,     res,            norep,          res,    void),
-  PROC(granted_res,    res,            norep,          res,    void),
+  PROC(lock_res,       lockres,        norep,          res,    void),
+  PROC(cancel_res,     cancelres,      norep,          res,    void),
+  PROC(unlock_res,     unlockres,      norep,          res,    void),
+  PROC(granted_res,    grantedres,     norep,          res,    void),
   PROC(none,           void,           void,           void,   void),
   PROC(none,           void,           void,           void,   void),
   PROC(none,           void,           void,           void,   void),
index 3bc3b5ea090dc7032fce4ee538d50aa01cb5764a..0c3306d43a669320b6dd987bf6aa4c0a4b8e13a6 100644 (file)
@@ -52,6 +52,8 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
        struct nlm_file *file;
        unsigned int    hash;
        u32             nfserr;
+       uid_t           saved_cr_uid;
+       struct svc_cred *cred;
 
        dprintk("lockd: nlm_file_lookup(%s/%u)\n",
                kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
@@ -80,11 +82,19 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
 
        /* Open the file. Note that this must not sleep for too long, else
         * we would lock up lockd:-) So no NFS re-exports, folks.
+        *
+        * We have to make sure we have the right credential to open
+        * the file.
         */
+       cred = &rqstp->rq_cred;
+       saved_cr_uid = cred->cr_uid;
+       cred->cr_uid = 0;
        if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
                dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr));
+               cred->cr_uid = saved_cr_uid;
                goto out_free;
        }
+       cred->cr_uid = saved_cr_uid;
 
        file->f_next = nlm_files[hash];
        nlm_files[hash] = file;
index a8d65fc7a39c12940876e85f486e86da0149b6de..4d8025650cc1bdaecca50999d9e90274d577393b 100644 (file)
@@ -9,11 +9,8 @@
 
 O_TARGET := nfsd.o
 O_OBJS   := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
-           export.o auth.o lockd.o nfscache.o nfsxdr.o
-
-ifdef CONFIG_PROC_FS
-  O_OBJS += stats.o
-endif
+           export.o auth.o lockd.o nfscache.o nfsxdr.o \
+           stats.o
 
 M_OBJS   := $(O_TARGET)
 
index a2f80bea7d0b0cd63e044a33b7e483af7c3bec6a..74f174d63c396d1d17b8b245337851da449f1519 100644 (file)
@@ -50,11 +50,10 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        current->ngroups = i;
 
        if ((cred->cr_uid)) {
-               cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
-               cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH);
+               cap_t(current->cap_effective) &= ~CAP_FS_MASK;
        } else {
-               cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
-               cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+               cap_t(current->cap_effective) |= (CAP_FS_MASK &
+                                                 current->cap_permitted);
        }
 
        rqstp->rq_userset = 1;
index 81bd84bcfb7aa301c22e3acd7750c5a511a09744..eb644935c7e8e295c7937a3d90f6b0ae33c6c47b 100644 (file)
@@ -615,6 +615,112 @@ exp_getclientbyname(char *ident)
        return NULL;
 }
 
+struct flags {
+       int flag;
+       char *name[2];
+} expflags[] = {
+       { NFSEXP_READONLY, {"ro", "rw"}},
+       { NFSEXP_INSECURE_PORT, {"insecure", ""}},
+       { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
+       { NFSEXP_ALLSQUASH, {"all_squash", ""}},
+       { NFSEXP_ASYNC, {"async", ""}},
+       { NFSEXP_GATHERED_WRITES, {"wdelay", ""}},
+       { NFSEXP_UIDMAP, {"uidmap", ""}},
+       { NFSEXP_KERBEROS, { "kerberos", ""}},
+       { NFSEXP_SUNSECURE, { "sunsecure", ""}},
+       { NFSEXP_CROSSMNT, {"crossmnt", ""}},
+       { 0, {"", ""}}
+};
+
+static int
+exp_flags(char *buffer, int flag)
+{
+    int len = 0, first = 0;
+    struct flags *flg = expflags;
+
+    for (;flg->flag;flg++) {
+        int state = (flg->flag & flag)?0:1;
+        if (!flg->flag)
+               break;
+        if (*flg->name[state]) {
+               len += sprintf(buffer + len, "%s%s",
+                               first++?",":"", flg->name[state]);
+        }
+    }
+    return len;
+}
+
+int
+exp_procfs_exports(char *buffer, char **start, off_t offset,
+                             int length, int *eof, void *data)
+{
+       struct svc_clnthash     **hp, **head, *tmp;
+       struct svc_client       *clp;
+       svc_export *exp;
+       off_t   pos = 0;
+        off_t  begin = 0;
+        int    len = 0;
+       int     i,j;
+
+        len += sprintf(buffer, "# Version 1.0\n");
+        len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n");
+
+       for (clp = clients; clp; clp = clp->cl_next) {
+               for (i = 0; i < NFSCLNT_EXPMAX; i++) {
+                       exp = clp->cl_export[i];
+                       while (exp) {
+                               int first = 0;
+                               len += sprintf(buffer+len, "%s\t", exp->ex_path);
+                               len += sprintf(buffer+len, "%s", clp->cl_ident);
+                               len += sprintf(buffer+len, "(");
+
+                               len += exp_flags(buffer+len, exp->ex_flags);
+                               len += sprintf(buffer+len, ") # ");
+                               for (j = 0; j < clp->cl_naddr; j++) {
+                                       struct in_addr  addr = clp->cl_addr[j]; 
+
+                                       head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
+                                       for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
+                                               if (tmp->h_addr.s_addr == addr.s_addr) {
+                                                       if (first++) len += sprintf(buffer+len, "%s", " ");
+                                                       if (tmp->h_client != clp)
+                                                               len += sprintf(buffer+len, "(");
+                                                       len += sprintf(buffer+len, "%ld.%ld.%ld.%ld",
+                                                                       htonl(addr.s_addr) >> 24 & 0xff,
+                                                                       htonl(addr.s_addr) >> 16 & 0xff,
+                                                                       htonl(addr.s_addr) >>  8 & 0xff,
+                                                                       htonl(addr.s_addr) >>  0 & 0xff);
+                                                       if (tmp->h_client != clp)
+                                                         len += sprintf(buffer+len, ")");
+                                                       break;
+                                               }
+                                       }
+                               }
+                               exp = exp->ex_next;
+
+                               buffer[len++]='\n';
+
+                               pos=begin+len;
+                               if(pos<offset) {
+                                       len=0;
+                                       begin=pos;
+                               }
+                               if (pos > offset + length)
+                                       goto done;
+                       }
+               }
+       }
+
+       *eof = 1;
+
+done:
+       *start = buffer + (offset - begin);
+       len -= (offset - begin);
+       if ( len > length )
+               len = length;
+       return len;
+}
+
 /*
  * Add or modify a client.
  * Change requests may involve the list of host addresses. The list of
index e671472321434b11da5780bb61a5349e531f5fb4..88d7cd1cda2c65d3c2c6c837a400b264a4dabfeb 100644 (file)
@@ -314,8 +314,8 @@ nfsd_cache_append(struct svc_rqst *rqstp, struct svc_buf *data)
                                data->len);
                return 0;
        }
-       memcpy(resp->buf, data->buf, data->len);
-       resp->buf += ((data->len + 3) >> 2);
+       memcpy(resp->buf, data->buf, data->len << 2);
+       resp->buf += data->len;
        resp->len += data->len;
        return 1;
 }
index 5a8add24d6b998ed57abfb055f596ae27cedeeac..80f718eea167af4dbb1a5aa1eea3c5dbfdbd57a0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/version.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
+#include <linux/proc_fs.h>
 
 #include <linux/nfs.h>
 #include <linux/sunrpc/svc.h>
@@ -53,6 +54,24 @@ static int   nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
 
 static int     initialized = 0;
 
+#ifdef CONFIG_PROC_FS
+
+int exp_procfs_exports(char *buffer, char **start, off_t offset,
+                             int length, int *eof, void *data);
+
+void proc_export_init(void)
+{
+       struct proc_dir_entry *nfs_export_ent = NULL;
+
+       if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
+               return;
+       if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+               return;
+       nfs_export_ent->read_proc = exp_procfs_exports;
+}
+
+#endif
+
 /*
  * Initialize nfsd
  */
@@ -66,8 +85,10 @@ nfsd_init(void)
        nfsd_cache_init();      /* RPC reply cache */
        nfsd_export_init();     /* Exports table */
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
-       nfsd_racache_init();    /* Readahead param cache */
        nfsd_fh_init();         /* FH table */
+#ifdef CONFIG_PROC_FS
+       proc_export_init();
+#endif
        initialized = 1;
 }
 
@@ -290,6 +311,8 @@ cleanup_module(void)
        nfsd_cache_shutdown();
        nfsd_fh_free();
 #ifdef CONFIG_PROC_FS
+       remove_proc_entry("fs/nfs/exports", NULL);
+       remove_proc_entry("fs/nfs", NULL);
        nfsd_stat_shutdown();
 #endif
        nfsd_lockd_shutdown();
index a8bf3a3a59c1dba2de3fd9b08e6008bfb2ad4c9c..e8c97b63af010301fe1f6234fabb4bd864e30d68 100644 (file)
@@ -1093,32 +1093,33 @@ check_type:
        /*
         * Security: Check that the export is valid for dentry <gam3@acm.org>
         */
+       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);
-               goto out;
+               error = nfserr_stale;
        } else if (exp->ex_dentry != dentry) {
                struct dentry *tdentry = dentry;
-               int err2 = 0;
 
-               error = nfserr_stale;
                do {
                        tdentry = tdentry->d_parent;
-                       if (exp->ex_dentry == tdentry) {
-                               error = 0;
+                       if (exp->ex_dentry == tdentry)
                                break;
-                       }
-                       if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) {
-                               error = err2;
-#ifdef NFSD_PARANOIA
-                               goto out1;
-#else
-                               goto out;
-#endif
+                       /* 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)) {
+                               error = nfserr_stale;
+dprintk("fh_verify: no root_squashed access.\n");
                        }
                } while ((tdentry != tdentry->d_parent));
-               if (error) {
-                       printk("fh_verify: Security: %s/%s bad export.\n",
+               if (exp->ex_dentry != tdentry) {
+                       error = nfserr_stale;
+                       printk("nfsd Security: %s/%s bad export.\n",
                               dentry->d_parent->d_name.name,
                               dentry->d_name.name);
                        goto out;
@@ -1126,14 +1127,14 @@ check_type:
        }
 
        /* Finally, check access permissions. */
-       error = nfsd_permission(exp, dentry, access);
+       if (!error) {
+               error = nfsd_permission(exp, dentry, access);
+       }
 #ifdef NFSD_PARANOIA
-out1:
 if (error)
 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
 #endif
-
 out:
        return error;
 }
index 455d0f2091f671d4e00ad1e92b8d3e34fefd67b8..ff1608a8259c4da55e42bd797540fdf00018b827 100644 (file)
@@ -44,6 +44,11 @@ static void                  nfsd(struct svc_rqst *rqstp);
 struct timeval                 nfssvc_boot = { 0, 0 };
 static int                     nfsd_active = 0;
 
+/*
+ * Maximum number of nfsd processes
+ */
+#define        NFSD_MAXSERVS           128
+
 int
 nfsd_svc(unsigned short port, int nrservs)
 {
@@ -52,20 +57,31 @@ nfsd_svc(unsigned short port, int nrservs)
 
        dprintk("nfsd: creating service\n");
        error = -EINVAL;
-       if (nrservs < 0)
+       if (nrservs <= 0)
                goto out;
        if (nrservs > NFSD_MAXSERVS)
                nrservs = NFSD_MAXSERVS;
+       nfsd_nservers = nrservs;
 
        error = -ENOMEM;
+       nfsd_racache_init();     /* Readahead param cache */
+       if (nfsd_nservers == 0)
+               goto out;
+         
        serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
-       if (serv == NULL) 
+       if (serv == NULL)
                goto out;
 
-       if ((error = svc_makesock(serv, IPPROTO_UDP, port)) < 0
-        || (error = svc_makesock(serv, IPPROTO_TCP, port)) < 0)
+       error = svc_makesock(serv, IPPROTO_UDP, port);
+       if (error < 0)
                goto failure;
 
+#if 0  /* Don't even pretend that TCP works. It doesn't. */
+       error = svc_makesock(serv, IPPROTO_TCP, port);
+       if (error < 0)
+               goto failure;
+#endif
+
        while (nrservs--) {
                error = svc_create_thread(nfsd, serv);
                if (error < 0)
@@ -93,6 +109,8 @@ nfsd(struct svc_rqst *rqstp)
        exit_mm(current);
        current->session = 1;
        current->pgrp = 1;
+       /* Let svc_process check client's authentication. */
+       rqstp->rq_auth = 1;
        sprintf(current->comm, "nfsd");
 
        oldumask = current->fs->umask;          /* Set umask to 0.  */
@@ -127,22 +145,13 @@ nfsd(struct svc_rqst *rqstp)
                 * port probes on port 2049 by unauthorized clients.
                 */
                rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
-               if (!rqstp->rq_client) {
-                       printk(KERN_WARNING "nfsd: unauthenticated request "
-                               "from (%08lx:%d)\n",
-                               ntohl(rqstp->rq_addr.sin_addr.s_addr),
-                               ntohs(rqstp->rq_addr.sin_port));
-                       svc_drop(rqstp);
-                       serv->sv_stats->rpcbadclnt++;
-               } else {
-                       /* Process request with signals blocked.  */
-                       spin_lock_irq(&current->sigmask_lock);
-                       siginitsetinv(&current->blocked, ALLOWED_SIGS);
-                       recalc_sigpending(current);
-                       spin_unlock_irq(&current->sigmask_lock);
-                       
-                       svc_process(serv, rqstp);
-               }
+               /* Process request with signals blocked.  */
+               spin_lock_irq(&current->sigmask_lock);
+               siginitsetinv(&current->blocked, ALLOWED_SIGS);
+               recalc_sigpending(current);
+               spin_unlock_irq(&current->sigmask_lock);
+
+               svc_process(serv, rqstp);
 
                /* Unlock export hash tables */
                exp_unlock();
@@ -166,6 +175,8 @@ nfsd(struct svc_rqst *rqstp)
                printk("nfsd: last server exiting\n");
                /* revoke all exports */
                nfsd_export_shutdown();
+               /* release read-ahead cache */
+               nfsd_racache_shutdown();
        }
 
        /* Destroy the thread */
index accd0aadc3dfc3a3ed27fa698f0418c60bc5a69c..e05cd271d0424609902063d0ce2b84cc9cc4f583 100644 (file)
@@ -13,6 +13,7 @@
  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -26,6 +27,7 @@
 struct nfsd_stats      nfsdstats;
 struct svc_stat                nfsd_svcstats = { &nfsd_program, };
 
+#ifdef CONFIG_PROC_FS
 static int
 nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
                                int *eof, void *data)
@@ -88,3 +90,4 @@ nfsd_stat_shutdown(void)
 {
        svc_proc_unregister("nfsd");
 }
+#endif /* CONFIG_PROC_FS */
index 9798050c520533c6862ef18b108380a514b6b26a..a213e21e39b171454d0a4f4d4bca63cfb705b75d 100644 (file)
@@ -73,9 +73,10 @@ struct raparms {
                                p_rawin;
 };
 
-#define FILECACHE_MAX          (2 * NFSD_MAXSERVS)
-static struct raparms          raparms[FILECACHE_MAX];
-static struct raparms *                raparm_cache = 0;
+int nfsd_nservers = 0;
+#define FILECACHE_MAX          (2 * nfsd_nservers) 
+static struct raparms *                raparml = NULL;
+static struct raparms *                raparm_cache = NULL;
 
 /*
  * Lock a parent directory following the VFS locking protocol.
@@ -148,16 +149,18 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
        dprintk("nfsd: nfsd_lookup(fh %p, %s)\n", SVCFH_DENTRY(fhp), name);
 
        /* Obtain dentry and export. */
-       err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP);
+       err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
        if (err)
                goto out;
 
        dparent = fhp->fh_dentry;
        exp  = fhp->fh_export;
 
+#if 0
        err = nfsd_permission(exp, dparent, MAY_EXEC);
        if (err)
                goto out;
+#endif
        err = nfserr_noent;
        if (fs_off_limits(dparent->d_sb))
                goto out;
@@ -232,13 +235,17 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
 
+       err = inode_change_ok(inode, iap);
+       if (err)
+               goto out_nfserr;
+
        /* The size case is special... */
        if (iap->ia_valid & ATTR_SIZE) {
 if (!S_ISREG(inode->i_mode))
 printk("nfsd_setattr: size change??\n");
                if (iap->ia_size < inode->i_size) {
                        err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
-                       if (err != 0)
+                       if (err)
                                goto out;
                }
                err = get_write_access(inode);
@@ -275,9 +282,17 @@ printk("nfsd_setattr: size change??\n");
 
        /* Change the attributes. */
        if (iap->ia_valid) {
+               kernel_cap_t    saved_cap;
+
                iap->ia_valid |= ATTR_CTIME;
                iap->ia_ctime = CURRENT_TIME;
+               if (current->fsuid != 0) {
+                       saved_cap = current->cap_effective;
+                       cap_clear(current->cap_effective);
+               }
                err = notify_change(dentry, iap);
+               if (current->fsuid != 0)
+                       current->cap_effective = saved_cap;
                if (err)
                        goto out_nfserr;
                if (EX_ISSYNC(fhp->fh_export))
@@ -493,6 +508,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
        struct inode            *inode;
        mm_segment_t            oldfs;
        int                     err = 0;
+#ifdef CONFIG_QUOTA
+       uid_t                   saved_euid;
+#endif
 
        if (!cnt)
                goto out;
@@ -522,16 +540,31 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
 
        /* Write the data. */
        oldfs = get_fs(); set_fs(KERNEL_DS);
+#ifdef CONFIG_QUOTA
+       /* This is for disk quota. */
+       saved_euid = current->euid;
+       current->euid = current->fsuid;
        err = file.f_op->write(&file, buf, cnt, &file.f_pos);
+       current->euid = saved_euid;
+#else
+       err = file.f_op->write(&file, buf, cnt, &file.f_pos);
+#endif
        set_fs(oldfs);
 
        /* clear setuid/setgid flag after write */
        if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
                struct iattr    ia;
+               kernel_cap_t    saved_cap;
 
                ia.ia_valid = ATTR_MODE;
                ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
+               if (current->fsuid != 0) {
+                       saved_cap = current->cap_effective;
+                       cap_clear(current->cap_effective);
+               }
                notify_change(dentry, &ia);
+               if (current->fsuid != 0)
+                       current->cap_effective = saved_cap;
        }
 
        fh_unlock(fhp);                 /* unlock inode */
@@ -661,7 +694,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                break;
        case S_IFCHR:
        case S_IFBLK:
+               /* The client is _NOT_ required to do security enforcement */
+               if(!capable(CAP_SYS_ADMIN))
+               {
+                       err = -EPERM;
+                       goto out;
+               }
        case S_IFIFO:
+       case S_IFSOCK:
                opfunc = dirp->i_op->mknod;
                break;
        }
@@ -719,6 +759,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;
 
        err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
        if (err)
@@ -736,7 +777,13 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
        DQUOT_INIT(inode);
        newattrs.ia_size = size;
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+       if (current->fsuid != 0) {
+               saved_cap = current->cap_effective;
+               cap_clear(current->cap_effective);
+       }
        err = notify_change(dentry, &newattrs);
+       if (current->fsuid != 0)
+               current->cap_effective = saved_cap;
        if (!err) {
                vmtruncate(inode, size);
                if (inode->i_op && inode->i_op->truncate)
@@ -1235,11 +1282,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
 {
        struct inode    *inode = dentry->d_inode;
        int             err;
+       kernel_cap_t    saved_cap;
 
        if (acc == MAY_NOP)
                return 0;
-
-       /*
+#if 0
        dprintk("nfsd: permission 0x%x%s%s%s%s%s mode 0%o%s%s%s\n",
                acc,
                (acc & MAY_READ)?       " read"  : "",
@@ -1253,8 +1300,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
                IS_RDONLY(inode)?       " ro" : "");
        dprintk("      owner %d/%d user %d/%d\n",
                inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
-        */
-
+#endif
 #ifndef CONFIG_NFSD_SUN
         if (dentry->d_mounts != dentry) {
                return nfserr_perm;
@@ -1284,15 +1330,33 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
        if (inode->i_uid == current->fsuid /* && !(acc & MAY_TRUNC) */)
                return 0;
 
+       if (current->fsuid != 0) {
+               saved_cap = current->cap_effective;
+               cap_clear(current->cap_effective);
+       }
+
        err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
 
        /* Allow read access to binaries even when mode 111 */
-       if (err == -EPERM && S_ISREG(inode->i_mode) && acc == MAY_READ)
+       if (err == -EACCES && S_ISREG(inode->i_mode) && acc == MAY_READ)
                err = permission(inode, MAY_EXEC);
 
+       if (current->fsuid != 0)
+               current->cap_effective = saved_cap;
+
        return err? nfserrno(-err) : 0;
 }
 
+void
+nfsd_racache_shutdown(void)
+{
+       if (!raparm_cache)
+               return;
+       dprintk("nfsd: freeing %d readahead buffers.\n", FILECACHE_MAX);
+       kfree(raparml);
+       nfsd_nservers = 0;
+       raparm_cache = raparml = NULL;
+}
 /*
  * Initialize readahead param cache
  */
@@ -1303,9 +1367,19 @@ nfsd_racache_init(void)
 
        if (raparm_cache)
                return;
-       memset(raparms, 0, sizeof(raparms));
-       for (i = 0; i < FILECACHE_MAX - 1; i++) {
-               raparms[i].p_next = raparms + i + 1;
+       raparml = kmalloc(sizeof(struct raparms) * FILECACHE_MAX, GFP_KERNEL);
+
+       if (raparml != NULL) {
+               dprintk("nfsd: allocating %d readahead buffers.\n",
+                       FILECACHE_MAX);
+               memset(raparml, 0, sizeof(struct raparms) * FILECACHE_MAX);
+               for (i = 0; i < FILECACHE_MAX - 1; i++) {
+                       raparml[i].p_next = raparml + i + 1;
+               }
+               raparm_cache = raparml;
+       } else {
+               printk(KERN_WARNING
+                      "nfsd: Could not allocate memory read-ahead cache.\n");
+               nfsd_nservers = 0;
        }
-       raparm_cache = raparms;
 }
index e6564f15e6fdac299ec4c570e44a2e3de721352e..137eb4d5fe9ad7a273a8ea786ca4b165bf4e21cf 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -523,19 +523,27 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
        newattrs.ia_gid = group;
        newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
        /*
-        * If the owner has been changed, remove the setuid bit
+        * If the user or group of a non-directory has been changed by a
+        * non-root user, remove the setuid bit.
+        * 19981026     David C Niemi <niemi@tux.org>
+        *
         */
-       if (inode->i_mode & S_ISUID) {
+       if ((inode->i_mode & S_ISUID) == S_ISUID &&
+               !S_ISDIR(inode->i_mode)
+               && current->fsuid) 
+       {
                newattrs.ia_mode &= ~S_ISUID;
                newattrs.ia_valid |= ATTR_MODE;
        }
        /*
-        * If the group has been changed, remove the setgid bit
-        *
-        * Don't remove the setgid bit if no group execute bit.
-        * This is a file marked for mandatory locking.
+        * Likewise, if the user or group of a non-directory has been changed
+        * by a non-root user, remove the setgid bit UNLESS there is no group
+        * execute bit (this would be a file marked for mandatory locking).
+        * 19981026     David C Niemi <niemi@tux.org>
         */
-       if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
+       if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 
+               && !S_ISDIR(inode->i_mode) && current->fsuid) 
+       {
                newattrs.ia_mode &= ~S_ISGID;
                newattrs.ia_valid |= ATTR_MODE;
        }
index 77c0a20bd3a2c2c180e7eecb7cebe2b2ccdfbc18..4dbff5b565052c5d572fee289da09a15a946d053 100644 (file)
@@ -38,3 +38,8 @@ Thu Dec 10 1998   AV
                        Removed dead code - mknod is never asked to
                        create a symlink or directory. Incidentially,
                        it wouldn't do it right if it would be called.
+
+Sat Dec 26 1998   KGB
+       *    inode.c (detect_sysv4):
+                       Added detection of expanded s_type field (0x10,
+                       0x20 and 0x30).  Forced read-only access in this case.
index f2cf52087475ae122ed30fc47874ae6d5dccb7e0..d5af68176d87377c5446f2dadc4c6e3b052568a8 100644 (file)
@@ -15,6 +15,7 @@
  *
  *  sysv/inode.c
  *  Copyright (C) 1993  Bruno Haible
+ *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
  *
  *  This file contains code for allocating/freeing inodes and for read/writing
  *  the superblock.
@@ -179,12 +180,25 @@ static const char* detect_sysv4 (struct super_block *sb, struct buffer_head *bh)
                return NULL;
        if (sbd->s_time < 315532800) /* this is likely to happen on SystemV2 FS */
                return NULL;
-       if (sbd->s_type > 3 || sbd->s_type < 1)
+       if ((sbd->s_type > 3 || sbd->s_type < 1) && (sbd->s_type > 0x30 || sbd->s_type < 0x10))
                return NULL;
-       detected_bs(sbd->s_type, sb);
+
+       /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10,
+          0x20 or 0x30 indicates that symbolic links and the 14-character
+          filename limit is gone. Due to lack of information about this
+           feature read-only mode seems to be a reasonable approach... -KGB */
+
+       if (sbd->s_type >= 0x10) {
+               printk("SysV FS: can't handle long file names on %s, "
+                      "forcing read-only mode.\n", kdevname(sb->s_dev));
+               sb->s_flags |= MS_RDONLY;
+       }
+
+       detected_bs(sbd->s_type >= 0x10 ? (sbd->s_type >> 4) : sbd->s_type, sb);
        sb->sv_type = FSTYPE_SYSV4;
        return "SystemV";
 }
+
 static struct super_block * detected_sysv4 (struct super_block *sb, struct buffer_head *bh)
 {
        struct sysv4_super_block * sbd;
index c7277f1a1bfc519c6a32ee72c17afbc617f24948..1ae336647396fb7fa8cafc098157fdecfeebfc33 100644 (file)
@@ -9,6 +9,7 @@
  *
  *  sysv/namei.c
  *  Copyright (C) 1993  Bruno Haible
+ *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
  */
 
 
index 87e69f657bcb9c8a250d1bc1d5e2c69482ce4df6..a55752abb0e9b8d3d1bcb99bac2e360ee2e9443d 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ALPHA_DELAY_H
 #define __ALPHA_DELAY_H
 
-extern unsigned long loops_per_sec;
+#include <asm/smp.h>
 
 /*
  * Copyright (C) 1993 Linus Torvalds
@@ -9,7 +9,8 @@ extern unsigned long loops_per_sec;
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
 
-extern __inline__ void __delay(unsigned long loops)
+extern __inline__ void
+__delay(unsigned long loops)
 {
        __asm__ __volatile__(".align 3\n"
                "1:\tsubq %0,1,%0\n\t"
@@ -24,15 +25,46 @@ extern __inline__ void __delay(unsigned long loops)
  * lookup table, really, as the multiplications take much too long with
  * short delays.  This is a "reasonable" implementation, though (and the
  * first constant multiplications gets optimized away if the delay is
- * a constant)
+ * a constant).
+ *
+ * Optimize small constants further by exposing the second multiplication
+ * to the compiler.  In addition, mulq is 2 cycles faster than umulh.
  */
-extern __inline__ void udelay(unsigned long usecs)
+
+extern __inline__ void
+__udelay(unsigned long usecs, unsigned long lps)
 {
+       /* compute (usecs * 2**64 / 10**6) * loops_per_sec / 2**64 */
+
        usecs *= 0x000010c6f7a0b5edUL;          /* 2**64 / 1000000 */
-       __asm__("umulh %1,%2,%0"
-               :"=r" (usecs)
-               :"r" (usecs),"r" (loops_per_sec));
+       __asm__("umulh %1,%2,%0" :"=r" (usecs) :"r" (usecs),"r" (lps));
+       __delay(usecs);
+}
+
+extern __inline__ void
+__small_const_udelay(unsigned long usecs, unsigned long lps)
+{
+       /* compute (usecs * 2**32 / 10**6) * loops_per_sec / 2**32 */
+
+        usecs *= 0x10c6;                /* 2^32 / 10^6 */
+       usecs *= lps;
+       usecs >>= 32;
        __delay(usecs);
 }
 
+#ifdef __SMP__
+#define udelay(usecs)                                          \
+       (__builtin_constant_p(usecs) && usecs < 0x100000000UL   \
+        ? __small_const_udelay(usecs,                          \
+               cpu_data[smp_processor_id()].loops_per_sec)     \
+        : __udelay(usecs,                                      \
+               cpu_data[smp_processor_id()].loops_per_sec))
+#else
+#define udelay(usecs)                                          \
+       (__builtin_constant_p(usecs) && usecs < 0x100000000UL   \
+        ? __small_const_udelay(usecs, loops_per_sec)           \
+        : __udelay(usecs, loops_per_sec))
+#endif
+
+
 #endif /* defined(__ALPHA_DELAY_H) */
index 7d769dfcd0fc20f93a1c889ed0ba097c9c18536e..f4a08c9f209983841ef01a8ad35bced41429fb9b 100644 (file)
@@ -12,4 +12,6 @@
 #define __FINIT                .previous
 #define __INITDATA     .section        .data.init,"a"
 
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
+
 #endif
index 124989d93c0c2b587837f6a4f83b12d6c07506a1..c983942e92e9ff1aa0d65432c79dccb7b975e53a 100644 (file)
@@ -93,6 +93,7 @@ static __inline__ int irq_cannonicalize(int irq)
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+struct pt_regs;
 extern void (*perf_irq)(unsigned long, struct pt_regs *);
 
 
index 639d7b4201903ddb360de9b11287d16b0c01ee24..b74744207166aa0625ca00f00e0eee04392c9afa 100644 (file)
@@ -175,7 +175,7 @@ struct ipi_msg_flush_tb_struct {
                struct vm_area_struct * flush_vma;
        } p;
        unsigned long flush_addr;
-  /*   unsigned long flush_end; */ /* not used by local_flush_tlb_range */
+       unsigned long flush_end;
 };
 
 extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
index 9d5e8e084c60f96f295a45499a70e557ea4e0430..04be8487db528de5d51c044a70374e510c8cc214 100644 (file)
@@ -12,7 +12,8 @@ struct cpuinfo_alpha {
        unsigned long *pgd_cache;
        unsigned long *pte_cache;
        unsigned long pgtable_cache_sz;
-};
+       unsigned long ipi_count;
+} __attribute__((aligned(32)));
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
@@ -36,9 +37,6 @@ static __inline__ unsigned char hard_smp_processor_id(void)
 #define smp_processor_id()     (current->processor)
 #define cpu_logical_map(cpu)   (cpu)
 
-/* For the benefit of panic.  */
-void smp_message_pass(int target, int msg, unsigned long data, int wait);
-
 #endif /* __SMP__ */
 
 #define NO_PROC_ID     (-1)
index cec9175254edf45f2ec21fe1e73930d620510b0d..d354371d8a723feff0f3614b64331cbd00097d99 100644 (file)
@@ -244,14 +244,14 @@ extern __inline__ unsigned long xchg_u32(volatile int *m, unsigned long val)
 
        __asm__ __volatile__(
        "1:     ldl_l %0,%2\n"
-       "       bis %3,%3,%1\n"
+       "       bis $31,%3,%1\n"
        "       stl_c %1,%2\n"
        "       beq %1,2f\n"
        ".section .text2,\"ax\"\n"
        "2:     br 1b\n"
        ".previous"
        : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "r" (val), "m" (*m));
+       : "rI" (val), "m" (*m));
 
        return val;
 }
@@ -262,14 +262,14 @@ extern __inline__ unsigned long xchg_u64(volatile long * m, unsigned long val)
 
        __asm__ __volatile__(
        "1:     ldq_l %0,%2\n"
-       "       bis %3,%3,%1\n"
+       "       bis $31,%3,%1\n"
        "       stq_c %1,%2\n"
        "       beq %1,2f\n"
        ".section .text2,\"ax\"\n"
        "2:     br 1b\n"
        ".previous"
        : "=&r" (val), "=&r" (dummy), "=m" (*m)
-       : "r" (val), "m" (*m));
+       : "rI" (val), "m" (*m));
 
        return val;
 }
index c0bfb799cd919b31121c974f21857737b37e7024..2576553b348ec1890d1619e5de9b555750e31f3d 100644 (file)
@@ -8,4 +8,23 @@
 
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
 
+/*
+ * Standard way to access the cycle counter.
+ * Currently only used on SMP for scheduling.
+ *
+ * Only the low 32 bits are available as a continuously counting entity. 
+ * But this only means we'll force a reschedule every 8 seconds or so,
+ * which isn't an evil thing.
+ */
+
+typedef unsigned int cycles_t;
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+       cycles_t ret;
+       __asm__ __volatile__ ("rpcc %0" : "=r"(ret));
+       return ret;
+}
+
 #endif
index 5cd7e94d67a0b1495599ba44c71172dd125ccfef..a177377c62257b0e5beaa1ad9356b5185f293cf6 100644 (file)
@@ -312,10 +312,55 @@ __initfunc(static void check_cx686_cpuid_slop(void))
        }
 }
 
+/*
+ * Check wether we are able to run this kernel safely with this
+ * configuration.  Various configs imply certain minimum requirements
+ * of the machine:
+ *
+ * - In order to run on a i386, we need to be compiled for i386
+ *   (for due to lack of "invlpg" and working WP on a i386)
+ * - In order to run on anything without a TSC, we need to be
+ *   compiled for a i486.
+ * - In order to work on a Pentium/SMP machine, we need to be
+ *   compiled for a Pentium or lower, as a PPro config implies
+ *   a properly working local APIC without the need to do extra
+ *   reads from the APIC.
+ */
+__initfunc(static void check_config(void))
+{
+       /* Configuring for a i386 will boot on anything */
+#ifndef CONFIG_M386
+       /* Configuring for an i486 only implies 'invlpg' and a working WP bit */
+       if (boot_cpu_data.x86 == 3)
+               panic("Kernel requires i486+ for 'invlpg' and other features");
+
+#ifndef CONFIG_M486
+
+#ifndef CONFIG_M586
+       /* Configuring for a PPro implies that we have an IO-APIC without the read-before-write bug */
+
+#endif /* CONFIG_M586 */
+#endif /* CONFIG_M486 */
+#endif /* CONFIG_M386 */
+
+/* If we configured ourselves for a TSC, we'd better have one! */
+#ifdef CONFIG_TSC
+       if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC))
+               panic("Kernel compiled for Pentium+, requires TSC");
+#endif
+
+/* If we were told we had a good APIC for SMP, we'd better be a PPro */
+#ifdef CONFIG_GOOD_APIC
+       if (smp_found_config && boot_cpu_data.x86 <= 5)
+               panic("Kernel compiled for PPro+, assumes local APIC without read-before-write bug");
+#endif
+}
+
 __initfunc(static void check_bugs(void))
 {
        check_cyrix_cpu();
        identify_cpu(&boot_cpu_data);
+       check_config();
 #ifndef __SMP__
        printk("CPU: ");
        print_cpu_info(&boot_cpu_data);
index 51d66f8fc233570e0eab90b20033ea2860fa78fb..d8c8cf580030cab796c592c3aa9d152329109d4c 100644 (file)
@@ -12,7 +12,7 @@
 
 static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
-#if defined(__KERNEL__) && !defined(CONFIG_M386)
+#ifdef CONFIG_BSWAP
        __asm__("bswap %0" : "=r" (x) : "0" (x));
 #else
        __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
index 65a74c5cb038e0a118b7edcad466c7385f457c7d..dacd01b99eb9d944995f5a2374708cf4b6c53291 100644 (file)
@@ -32,8 +32,16 @@ typedef struct user_i387_struct elf_fpregset_t;
    This provides a mean for the dynamic linker to call DT_FINI functions for
    shared libraries that have been loaded before the code runs.
 
-   A value of 0 tells we have no such handler.  */
-#define ELF_PLAT_INIT(_r)      _r->edx = 0
+   A value of 0 tells we have no such handler. 
+
+   We might as well make sure everything else is cleared too (except for %esp),
+   just to make things more deterministic.
+ */
+#define ELF_PLAT_INIT(_r)      do { \
+       _r->ebx = 0; _r->ecx = 0; _r->edx = 0; \
+       _r->esi = 0; _r->edi = 0; _r->ebp = 0; \
+       _r->eax = 0; \
+} while (0)
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
index e0cd4b361466d1f3f78d3e8b1405587469be2d99..5ca57fc3dd74207592da815258c848929343f55f 100644 (file)
@@ -41,7 +41,7 @@
 #define __flush_tlb() \
 do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0)
 
-#ifdef CONFIG_M386
+#ifndef CONFIG_INVLPG
 #define __flush_tlb_one(addr) flush_tlb()
 #else
 #define __flush_tlb_one(addr) \
@@ -218,18 +218,16 @@ static inline void flush_tlb_range(struct mm_struct *mm,
  * memory. 
  */
 #define _PAGE_PRESENT  0x001
-#define _PAGE_PROTNONE 0x002           /* If not present */
-#define _PAGE_RW       0x002           /* If present */
+#define _PAGE_RW       0x002
 #define _PAGE_USER     0x004
 #define _PAGE_WT       0x008
 #define _PAGE_PCD      0x010
 #define _PAGE_ACCESSED 0x020
 #define _PAGE_DIRTY    0x040
-#define _PAGE_4M       0x080   /* 4 MB page, Pentium+.. */
+#define _PAGE_4M       0x080   /* 4 MB page, Pentium+, if present.. */
 #define _PAGE_GLOBAL   0x100   /* Global TLB entry PPro+ */
 
-#define _PAGE_READABLE  (_PAGE_PRESENT)             
-#define _PAGE_WRITABLE  (_PAGE_PRESENT | _PAGE_RW)
+#define _PAGE_PROTNONE 0x080   /* If not present */
 
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -340,21 +338,17 @@ extern inline int pte_read(pte_t pte)             { return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_exec(pte_t pte)          { return pte_val(pte) & _PAGE_USER; }
 extern inline int pte_dirty(pte_t pte)         { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_write(pte_t pte)         { return pte_val(pte) & _PAGE_RW; }
 
 extern inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_USER; return pte; }
 extern inline pte_t pte_exprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_USER; return pte; }
 extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
 extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~_PAGE_RW; return pte; }
 extern inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) |= _PAGE_USER; return pte; }
 extern inline pte_t pte_mkexec(pte_t pte)      { pte_val(pte) |= _PAGE_USER; return pte; }
 extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= _PAGE_DIRTY; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-
-/*
- * These are harder, as writability is two bits, not one..
- */
-extern inline int pte_write(pte_t pte)         { return (pte_val(pte) & _PAGE_WRITABLE) == _PAGE_WRITABLE; }
-extern inline pte_t pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~((pte_val(pte) & _PAGE_PRESENT) << 1); return pte; }
 extern inline pte_t pte_mkwrite(pte_t pte)     { pte_val(pte) |= _PAGE_RW; return pte; }
 
 /*
@@ -589,9 +583,9 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 {
 }
 
-#define SWP_TYPE(entry) (((entry) >> 2) & 0x3f)
+#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 8))
+#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
 #define module_map      vmalloc
 #define module_unmap    vfree
index dea282ad012f19d73e24d094d41db324ca2d6503..940392f161f746d75e0bc3aef0a70697182a8e90 100644 (file)
@@ -159,6 +159,7 @@ extern int smp_scan_config(unsigned long, unsigned long);
 extern unsigned long smp_alloc_memory(unsigned long mem_base);
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
+extern unsigned long cpu_online_map;
 extern volatile int cpu_number_map[NR_CPUS];
 extern volatile unsigned long smp_invalidate_needed;
 extern void smp_flush_tlb(void);
index 65d72fabfbea4c5efc94b919b9feeea8c5088d42..5e553ef40e0889b769f2b96ab3715672d8e550bd 100644 (file)
 #define __HAVE_ARCH_STRCPY
 extern inline char * strcpy(char * dest,const char *src)
 {
+int d0, d1, d2;
 __asm__ __volatile__(
        "cld\n"
        "1:\tlodsb\n\t"
        "stosb\n\t"
        "testb %%al,%%al\n\t"
        "jne 1b"
-       : /* no output */
-       :"S" (src),"D" (dest):"si","di","ax","memory");
+       : "=&S" (d0), "=&D" (d1), "=&a" (d2)
+       :"0" (src),"1" (dest) : "memory");
 return dest;
 }
 
 #define __HAVE_ARCH_STRNCPY
 extern inline char * strncpy(char * dest,const char *src,size_t count)
 {
+int d0, d1, d2, d3;
 __asm__ __volatile__(
        "cld\n"
        "1:\tdecl %2\n\t"
@@ -55,14 +57,15 @@ __asm__ __volatile__(
        "rep\n\t"
        "stosb\n"
        "2:"
-       : /* no output */
-       :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
+       : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+       :"0" (src),"1" (dest),"2" (count) : "memory");
 return dest;
 }
 
 #define __HAVE_ARCH_STRCAT
 extern inline char * strcat(char * dest,const char * src)
 {
+int d0, d1, d2, d3;
 __asm__ __volatile__(
        "cld\n\t"
        "repne\n\t"
@@ -72,20 +75,21 @@ __asm__ __volatile__(
        "stosb\n\t"
        "testb %%al,%%al\n\t"
        "jne 1b"
-       : /* no output */
-       :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
+       : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+       : "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
 return dest;
 }
 
 #define __HAVE_ARCH_STRNCAT
 extern inline char * strncat(char * dest,const char * src,size_t count)
 {
+int d0, d1, d2, d3;
 __asm__ __volatile__(
        "cld\n\t"
        "repne\n\t"
        "scasb\n\t"
        "decl %1\n\t"
-       "movl %4,%3\n"
+       "movl %8,%3\n"
        "1:\tdecl %3\n\t"
        "js 2f\n\t"
        "lodsb\n\t"
@@ -94,15 +98,16 @@ __asm__ __volatile__(
        "jne 1b\n"
        "2:\txorl %2,%2\n\t"
        "stosb"
-       : /* no output */
-       :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
-       :"si","di","ax","cx","memory");
+       : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+       : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
+       : "memory");
 return dest;
 }
 
 #define __HAVE_ARCH_STRCMP
 extern inline int strcmp(const char * cs,const char * ct)
 {
+int d0, d1;
 register int __res;
 __asm__ __volatile__(
        "cld\n"
@@ -116,7 +121,8 @@ __asm__ __volatile__(
        "2:\tsbbl %%eax,%%eax\n\t"
        "orb $1,%%al\n"
        "3:"
-       :"=a" (__res):"S" (cs),"D" (ct):"si","di");
+       :"=a" (__res), "=&S" (d0), "=&D" (d1)
+                    :"1" (cs),"2" (ct));
 return __res;
 }
 
@@ -124,6 +130,7 @@ return __res;
 extern inline int strncmp(const char * cs,const char * ct,size_t count)
 {
 register int __res;
+int d0, d1, d2;
 __asm__ __volatile__(
        "cld\n"
        "1:\tdecl %3\n\t"
@@ -138,13 +145,15 @@ __asm__ __volatile__(
        "3:\tsbbl %%eax,%%eax\n\t"
        "orb $1,%%al\n"
        "4:"
-       :"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
+                    :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+                    :"1" (cs),"2" (ct),"3" (count));
 return __res;
 }
 
 #define __HAVE_ARCH_STRCHR
 extern inline char * strchr(const char * s, int c)
 {
+int d0;
 register char * __res;
 __asm__ __volatile__(
        "cld\n\t"
@@ -157,13 +166,14 @@ __asm__ __volatile__(
        "movl $1,%1\n"
        "2:\tmovl %1,%0\n\t"
        "decl %0"
-       :"=a" (__res):"S" (s),"0" (c):"si");
+       :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
 return __res;
 }
 
 #define __HAVE_ARCH_STRRCHR
 extern inline char * strrchr(const char * s, int c)
 {
+int d0, d1;
 register char * __res;
 __asm__ __volatile__(
        "cld\n\t"
@@ -174,104 +184,24 @@ __asm__ __volatile__(
        "leal -1(%%esi),%0\n"
        "2:\ttestb %%al,%%al\n\t"
        "jne 1b"
-       :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
-return __res;
-}
-
-#define __HAVE_ARCH_STRSPN
-extern inline size_t strspn(const char * cs, const char * ct)
-{
-register char * __res;
-__asm__ __volatile__(
-       "cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "je 1b\n"
-       "2:\tdecl %0"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
-return __res-cs;
-}
-
-#define __HAVE_ARCH_STRCSPN
-extern inline size_t strcspn(const char * cs, const char * ct)
-{
-register char * __res;
-__asm__ __volatile__(
-       "cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 1b\n"
-       "2:\tdecl %0"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
-return __res-cs;
-}
-
-#define __HAVE_ARCH_STRPBRK
-extern inline char * strpbrk(const char * cs,const char * ct)
-{
-register char * __res;
-__asm__ __volatile__(
-       "cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "movl %%ecx,%%edx\n"
-       "1:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 2f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 1b\n\t"
-       "decl %0\n\t"
-       "jmp 3f\n"
-       "2:\txorl %0,%0\n"
-       "3:"
-       :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
-       :"ax","cx","dx","di");
+       :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
 return __res;
 }
 
 #define __HAVE_ARCH_STRSTR
 extern inline char * strstr(const char * cs,const char * ct)
 {
+int d0, d1, d2, d3;
 register char * __res;
 __asm__ __volatile__(
        "cld\n\t" \
-       "movl %4,%%edi\n\t"
+       "movl %8,%%edi\n\t"
        "repne\n\t"
        "scasb\n\t"
        "notl %%ecx\n\t"
        "decl %%ecx\n\t"        /* NOTE! This also sets Z if searchstring='' */
        "movl %%ecx,%%edx\n"
-       "1:\tmovl %4,%%edi\n\t"
+       "1:\tmovl %8,%%edi\n\t"
        "movl %%esi,%%eax\n\t"
        "movl %%edx,%%ecx\n\t"
        "repe\n\t"
@@ -283,14 +213,14 @@ __asm__ __volatile__(
        "jne 1b\n\t"
        "xorl %%eax,%%eax\n\t"
        "2:"
-       :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
-       :"cx","dx","di","si");
+       :"=a" (__res), "=&c" (d0), "=&S" (d1), "=&d" (d2), "=&D" (d3) : "0" (0),"1" (0xffffffff),"2" (cs),"g" (ct));
 return __res;
 }
 
 #define __HAVE_ARCH_STRLEN
 extern inline size_t strlen(const char * s)
 {
+int d0;
 register int __res;
 __asm__ __volatile__(
        "cld\n\t"
@@ -298,86 +228,26 @@ __asm__ __volatile__(
        "scasb\n\t"
        "notl %0\n\t"
        "decl %0"
-       :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
-return __res;
-}
-
-#define __HAVE_ARCH_STRTOK
-extern inline char * strtok(char * s,const char * ct)
-{
-register char * __res;
-__asm__ __volatile__(
-       "testl %1,%1\n\t"
-       "jne 1f\n\t"
-       "testl %0,%0\n\t"
-       "je 8f\n\t"
-       "movl %0,%1\n"
-       "1:\txorl %0,%0\n\t"
-       "movl $-1,%%ecx\n\t"
-       "xorl %%eax,%%eax\n\t"
-       "cld\n\t"
-       "movl %4,%%edi\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "notl %%ecx\n\t"
-       "decl %%ecx\n\t"
-       "je 7f\n\t"                     /* empty delimiter-string */
-       "movl %%ecx,%%edx\n"
-       "2:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 7f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "je 2b\n\t"
-       "decl %1\n\t"
-       "cmpb $0,(%1)\n\t"
-       "je 7f\n\t"
-       "movl %1,%0\n"
-       "3:\tlodsb\n\t"
-       "testb %%al,%%al\n\t"
-       "je 5f\n\t"
-       "movl %4,%%edi\n\t"
-       "movl %%edx,%%ecx\n\t"
-       "repne\n\t"
-       "scasb\n\t"
-       "jne 3b\n\t"
-       "decl %1\n\t"
-       "cmpb $0,(%1)\n\t"
-       "je 5f\n\t"
-       "movb $0,(%1)\n\t"
-       "incl %1\n\t"
-       "jmp 6f\n"
-       "5:\txorl %1,%1\n"
-       "6:\tcmpb $0,(%0)\n\t"
-       "jne 7f\n\t"
-       "xorl %0,%0\n"
-       "7:\ttestl %0,%0\n\t"
-       "jne 8f\n\t"
-       "movl %0,%1\n"
-       "8:"
-       :"=b" (__res),"=S" (___strtok)
-       :"0" (___strtok),"1" (s),"g" (ct)
-       :"ax","cx","dx","di","memory");
+       :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
 return __res;
 }
 
 extern inline void * __memcpy(void * to, const void * from, size_t n)
 {
+int d0, d1, d2;
 __asm__ __volatile__(
        "cld\n\t"
        "rep ; movsl\n\t"
-       "testb $2,%b1\n\t"
+       "testb $2,%b4\n\t"
        "je 1f\n\t"
        "movsw\n"
-       "1:\ttestb $1,%b1\n\t"
+       "1:\ttestb $1,%b4\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
-       : /* no output */
-       :"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
-       : "cx","di","si","memory");
+       : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+       :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+       : "memory");
 return (to);
 }
 
@@ -431,19 +301,23 @@ extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
                        return to;
        }
 #define COMMON(x) \
-__asm__("cld\n\t" \
+__asm__ __volatile__( \
+       "cld\n\t" \
        "rep ; movsl" \
        x \
-       : /* no outputs */ \
-       : "c" (n/4),"D" ((long) to),"S" ((long) from) \
-       : "cx","di","si","memory");
-
+       : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
+       : "0" (n/4),"1" ((long) to),"2" ((long) from) \
+       : "memory");
+{
+       int d0, d1, d2;
        switch (n % 4) {
                case 0: COMMON(""); return to;
                case 1: COMMON("\n\tmovsb"); return to;
                case 2: COMMON("\n\tmovsw"); return to;
                default: COMMON("\n\tmovsw\n\tmovsb"); return to;
        }
+}
+  
 #undef COMMON
 }
 
@@ -456,25 +330,26 @@ __asm__("cld\n\t" \
 #define __HAVE_ARCH_MEMMOVE
 extern inline void * memmove(void * dest,const void * src, size_t n)
 {
+int d0, d1, d2;
 if (dest<src)
 __asm__ __volatile__(
        "cld\n\t"
        "rep\n\t"
        "movsb"
-       : /* no output */
-       :"c" (n),"S" (src),"D" (dest)
-       :"cx","si","di");
+       : "=&c" (d0), "=&S" (d1), "=&D" (d2)
+       :"0" (n),"1" (src),"2" (dest)
+       : "memory");
 else
 __asm__ __volatile__(
        "std\n\t"
        "rep\n\t"
        "movsb\n\t"
        "cld"
-       : /* no output */
-       :"c" (n),
-        "S" (n-1+(const char *)src),
-        "D" (n-1+(char *)dest)
-       :"cx","si","di","memory");
+       : "=&c" (d0), "=&S" (d1), "=&D" (d2)
+       :"0" (n),
+        "1" (n-1+(const char *)src),
+        "2" (n-1+(char *)dest)
+       :"memory");
 return dest;
 }
 
@@ -483,6 +358,7 @@ return dest;
 #define __HAVE_ARCH_MEMCHR
 extern inline void * memchr(const void * cs,int c,size_t count)
 {
+int d0;
 register void * __res;
 if (!count)
        return NULL;
@@ -493,20 +369,20 @@ __asm__ __volatile__(
        "je 1f\n\t"
        "movl $1,%0\n"
        "1:\tdecl %0"
-       :"=D" (__res):"a" (c),"D" (cs),"c" (count)
-       :"cx");
+       :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
 return __res;
 }
 
 extern inline void * __memset_generic(void * s, char c,size_t count)
 {
+int d0, d1;
 __asm__ __volatile__(
        "cld\n\t"
        "rep\n\t"
        "stosb"
-       : /* no output */
-       :"a" (c),"D" (s),"c" (count)
-       :"cx","di","memory");
+       : "=&c" (d0), "=&D" (d1)
+       :"a" (c),"1" (s),"0" (count)
+       :"memory");
 return s;
 }
 
@@ -520,19 +396,20 @@ return s;
  */
 extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 {
+int d0, d1;
 __asm__ __volatile__(
        "cld\n\t"
        "rep ; stosl\n\t"
-       "testb $2,%b1\n\t"
+       "testb $2,%b3\n\t"
        "je 1f\n\t"
        "stosw\n"
-       "1:\ttestb $1,%b1\n\t"
+       "1:\ttestb $1,%b3\n\t"
        "je 2f\n\t"
        "stosb\n"
        "2:"
-       : /* no output */
-       :"a" (c), "q" (count), "c" (count/4), "D" ((long) s)
-       :"cx","di","memory");
+       : "=&c" (d0), "=&D" (d1)
+       :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
+       :"memory");
 return (s);    
 }
 
@@ -540,20 +417,20 @@ return (s);
 #define __HAVE_ARCH_STRNLEN
 extern inline size_t strnlen(const char * s, size_t count)
 {
+int d0;
 register int __res;
 __asm__ __volatile__(
-       "movl %1,%0\n\t"
+       "movl %2,%0\n\t"
        "jmp 2f\n"
        "1:\tcmpb $0,(%0)\n\t"
        "je 3f\n\t"
        "incl %0\n"
-       "2:\tdecl %2\n\t"
-       "cmpl $-1,%2\n\t"
+       "2:\tdecl %1\n\t"
+       "cmpl $-1,%1\n\t"
        "jne 1b\n"
-       "3:\tsubl %1,%0"
-       :"=a" (__res)
-       :"c" (s),"d" (count)
-       :"dx");
+       "3:\tsubl %2,%0"
+       :"=a" (__res), "=&d" (d0)
+       :"c" (s),"1" (count));
 return __res;
 }
 /* end of additional stuff */
@@ -582,19 +459,22 @@ extern inline void * __constant_c_and_count_memset(void * s, unsigned long patte
                        return s;
        }
 #define COMMON(x) \
-__asm__("cld\n\t" \
+__asm__  __volatile__("cld\n\t" \
        "rep ; stosl" \
        x \
-       : /* no outputs */ \
-       : "a" (pattern),"c" (count/4),"D" ((long) s) \
-       : "cx","di","memory")
-
+       : "=&c" (d0), "=&D" (d1) \
+       : "a" (pattern),"0" (count/4),"1" ((long) s) \
+       : "memory")
+{
+       int d0, d1;
        switch (count % 4) {
                case 0: COMMON(""); return s;
                case 1: COMMON("\n\tstosb"); return s;
                case 2: COMMON("\n\tstosw"); return s;
                default: COMMON("\n\tstosw\n\tstosb"); return s;
        }
+}
+  
 #undef COMMON
 }
 
index 10b18b433d372cdd45946f6bce26e5300dd8f483..374d7d19de59707cbada13cd90e4141ff8a80d6c 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef _ASMi386_TIMEX_H
 #define _ASMi386_TIMEX_H
 
+#include <linux/config.h>
+
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
 #define CLOCK_TICK_FACTOR      20      /* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
@@ -32,7 +34,7 @@ extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles (void)
 {
-#if CPU < 586
+#ifndef CONFIG_TSC
        return 0;
 #else
        unsigned long eax, edx;
index 5cfa0512fe09e3ad1d953ccd0809fbebba849c8c..f5d8b4fdfe63177f3c341f57c15cfe5accde6e8a 100644 (file)
@@ -4,6 +4,7 @@
 /*
  * User space memory access functions
  */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <asm/page.h>
 
@@ -44,7 +45,7 @@ extern int __verify_write(const void *, unsigned long);
                :"1" (addr),"g" (size),"g" (current->addr_limit.seg)); \
        flag; })
 
-#if CPU > 386
+#ifdef CONFIG_WP_WORKS_OK
 
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 
index 1c18664bc22d0190d2dbaf7ea9a9ca5833ceedf2..e635ff5993a34bcaeac195b7aff13c4a15718a3a 100644 (file)
@@ -83,13 +83,13 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
                                                   unsigned int sum) 
 {
     __asm__("
-       add %0,%0,%1
-       add %0,%0,%2
-       add %0,%0,%0
-       addi %0,%0,0
+       addc %0,%0,%1
+       adde %0,%0,%2
+       adde %0,%0,%3
+       addze %0,%0
        "
        : "=r" (sum)
-       : "r" (daddr), "r"(saddr), "r"((ntohs(len)<<16)+proto*256), "0"(sum));
+       : "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum));
     return sum;
 }
 
index 75f77641caba6003095ff1876a6e9d68b12c2ab2..6df9a99d452924c1485f7bb91fc06df08e49e520 100644 (file)
@@ -200,14 +200,54 @@ static __inline__ void ide_fix_driveid (struct hd_driveid *id) {
                id->word79         = __le16_to_cpu(id->word79);
                id->word80         = __le16_to_cpu(id->word80);
                id->word81         = __le16_to_cpu(id->word81);
-               id->word82         = __le16_to_cpu(id->word82);
+               id->command_sets   = __le16_to_cpu(id->command_sets);
                id->word83         = __le16_to_cpu(id->word83);
                id->word84         = __le16_to_cpu(id->word84);
                id->word85         = __le16_to_cpu(id->word85);
                id->word86         = __le16_to_cpu(id->word86);
                id->word87         = __le16_to_cpu(id->word87);
                id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-               for (i=0; i<167; i++)
+               id->word89         = __le16_to_cpu(id->word89);
+               id->word90         = __le16_to_cpu(id->word90);
+               id->word91         = __le16_to_cpu(id->word91);
+               id->word92         = __le16_to_cpu(id->word92);
+               id->word93         = __le16_to_cpu(id->word93);
+               id->word94         = __le16_to_cpu(id->word94);
+               id->word95         = __le16_to_cpu(id->word95);
+               id->word96         = __le16_to_cpu(id->word96);
+               id->word97         = __le16_to_cpu(id->word97);
+               id->word98         = __le16_to_cpu(id->word98);
+               id->word99         = __le16_to_cpu(id->word99);
+               id->word100        = __le16_to_cpu(id->word100);
+               id->word101        = __le16_to_cpu(id->word101);
+               id->word102        = __le16_to_cpu(id->word102);
+               id->word103        = __le16_to_cpu(id->word103);
+               id->word104        = __le16_to_cpu(id->word104);
+               id->word105        = __le16_to_cpu(id->word105);
+               id->word106        = __le16_to_cpu(id->word106);
+               id->word107        = __le16_to_cpu(id->word107);
+               id->word108        = __le16_to_cpu(id->word108);
+               id->word109        = __le16_to_cpu(id->word109);
+               id->word110        = __le16_to_cpu(id->word110);
+               id->word111        = __le16_to_cpu(id->word111);
+               id->word112        = __le16_to_cpu(id->word112);
+               id->word113        = __le16_to_cpu(id->word113);
+               id->word114        = __le16_to_cpu(id->word114);
+               id->word115        = __le16_to_cpu(id->word115);
+               id->word116        = __le16_to_cpu(id->word116);
+               id->word117        = __le16_to_cpu(id->word117);
+               id->word118        = __le16_to_cpu(id->word118);
+               id->word119        = __le16_to_cpu(id->word119);
+               id->word120        = __le16_to_cpu(id->word120);
+               id->word121        = __le16_to_cpu(id->word121);
+               id->word122        = __le16_to_cpu(id->word122);
+               id->word123        = __le16_to_cpu(id->word123);
+               id->word124        = __le16_to_cpu(id->word124);
+               id->word125        = __le16_to_cpu(id->word125);
+               id->word126        = __le16_to_cpu(id->word126);
+               id->word127        = __le16_to_cpu(id->word127);
+               id->security       = __le16_to_cpu(id->security);
+               for (i=0; i<127; i++)
                        id->reserved[i] = __le16_to_cpu(id->reserved[i]);
        }
 }
index ea24bbab7d765e22290b315e81b54e5809711701..5ee43593c9b13a325095cfc21c64805b994e6c52 100644 (file)
@@ -31,6 +31,9 @@
 #define __FINIT        .previous
 #define __INITDATA     .section        ".data.init",#alloc,#write
 
+#define __cacheline_aligned __attribute__ \
+                        ((__section__ (".data.cacheline_aligned")))
+
 #else /* not egcs */
 
 #define __init
@@ -52,5 +55,7 @@
 #define __openfirmware
 #define __openfirmwaredata
 #define __openfirmwarefunc(x) x
+
+#define __cacheline_aligned
 #endif /* egcs */
 #endif
index d0c0673b3dd27ecfd44c55832309d4b9daadc041..ebad8d5f02cbb7d3cbf955d85a950c54a17ca6c7 100644 (file)
@@ -121,6 +121,7 @@ extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
 #define _PAGE_DIRTY    0x080   /* C: page changed */
 #define _PAGE_ACCESSED 0x100   /* R: page referenced */
 #define _PAGE_HWWRITE  0x200   /* software: _PAGE_RW & _PAGE_DIRTY */
+#define _PAGE_SHARED   0
 
 #else
 #define _PAGE_PRESENT  0x0001  /* Page is valid */
@@ -147,28 +148,23 @@ extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
 
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
+#ifdef __SMP__
+#define _PAGE_BASE     _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT
+#else
+#define _PAGE_BASE     _PAGE_PRESENT | _PAGE_ACCESSED
+#endif
+#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE
+
 #define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
 
-#ifndef CONFIG_8xx
-#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
-                                _PAGE_ACCESSED)
-#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
-                                _PAGE_HWWRITE | _PAGE_ACCESSED)
-#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
-                                _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
-#else
-#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
-                                _PAGE_ACCESSED | _PAGE_SHARED)
-#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
-                                _PAGE_SHARED | _PAGE_ACCESSED)
-#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
-                                _PAGE_SHARED | _PAGE_DIRTY | _PAGE_ACCESSED)
-#endif /* CONFIG_8xx */
-     
+#define PAGE_SHARED    __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | \
+                                _PAGE_SHARED)
+#define PAGE_COPY      __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY  __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_KERNEL    __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | \
+                                _PAGE_NO_CACHE )
+
 /*
  * The PowerPC can only do execute protection on a segment (256MB) basis,
  * not on a page basis.  So we consider execute permission the same as read.
index 55e6bd16fc84fdef4cd4f189d3128384d76c0e85..c048dbc1ad3b0738721e1e915ae4866835485363 100644 (file)
@@ -3,12 +3,23 @@
 
 #ifndef __SMP__
 
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+/*
+ * Your basic spinlocks, allowing only a single CPU anywhere
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
+ */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
 
 #define spin_lock_init(lock)   do { } while(0)
 #define spin_lock(lock)                do { } while(0)
 #define spin_trylock(lock)     do { } while(0)
+#define spin_unlock_wait(lock) do { } while(0)
 #define spin_unlock(lock)      do { } while(0)
 #define spin_lock_irq(lock)    cli()
 #define spin_unlock_irq(lock)  sti()
@@ -27,9 +38,16 @@ typedef struct { } spinlock_t;
  * can "mix" irq-safe locks - any writer needs to get a
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
  */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define read_lock(lock)                do { } while(0)
 #define read_unlock(lock)      do { } while(0)
@@ -63,8 +81,8 @@ typedef struct {
        volatile unsigned long owner_cpu;
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED     { 0, 0, 0 }
-#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0)
+#define SPIN_LOCK_UNLOCKED     (spinlock_t) { 0, 0, 0 }
+#define spin_lock_init(lp)     do { (lp)->lock = 0; } while(0)
 #define spin_unlock_wait(lp)   do { barrier(); } while((lp)->lock)
 
 extern void _spin_lock(spinlock_t *lock);
@@ -99,7 +117,7 @@ typedef struct {
        volatile unsigned long owner_pc;
 } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
 extern void _read_lock(rwlock_t *rw);
 extern void _read_unlock(rwlock_t *rw);
index 32d01e7f248bd918dae902ffa4d683e7dfeca12b..5a1740847c9a5e77918a106a2cb28c05b736659c 100644 (file)
@@ -5,7 +5,15 @@
 #include <asm/processor.h>
 #include <asm/atomic.h>
 
+/*
+ * Memory barrier.
+ * The sync instruction guarantees that all memory accesses initiated
+ * by this processor have been performed (with respect to all other
+ * mechanisms that access memory).
+ */
 #define mb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
+#define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
 
 #define __save_flags(flags)    ({\
        __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
index c6385d4a7a91489f92490ca07389763f20b4d720..13b3591b81b3641cc90ff06de721b11828d94069 100644 (file)
@@ -182,6 +182,8 @@ struct termio {
 #define N_MASC         8       /* Reserved for Mobitex module <kaz@cafe.net> */
 #define N_R3964                9       /* Reserved for Simatic R3964 module */
 #define N_PROFIBUS_FDL 10      /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA         11      /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
+#define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
 
 #ifdef __KERNEL__
 
index a20f6031c907582e4c34a86c72030aab58d74b11..4fac4ea39694fce8b3ee7f151fa4c52e2a757007 100644 (file)
        (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
                << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+typedef unsigned long cycles_t;
+
+/*
+ * For the "cycle" counter we use the timebase lower half.
+ * Currently only used on SMP.
+ *
+ * Since SMP kernels won't run on the PPC601 CPU (which doesn't have
+ * the timebase register) anyway, we don't bother checking the CPU version.
+ */
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles(void)
+{
+#ifdef __SMP__
+       cycles_t ret;
+
+       __asm__("mftb %0" : "=r" (ret) : );
+       return ret;
+#else
+       return 0;
+#endif
+}
+
 #endif
index 054c59f15a37b649aa778f4db731f2bb018c6fdd..4c0f2e05d8d7172b7984103a64f94a5aa945344a 100644 (file)
@@ -192,7 +192,7 @@ extern int arcnet_debug;
 
 
 
-#define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
+#define JIFFER(time) for (delayval=jiffies+time; time_before(jiffies,delayval);) ;
 
        /* a complete ARCnet packet */
 union ArcPacket
index fd0bcd43fdba0cb1df5682a9806218949a923eda..dee4b654c58984ff36bb218d638c1fbc78e655ad 100644 (file)
@@ -11,5 +11,5 @@
 struct vc_data;
 
 extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
-extern unsigned short *set_translate(int m);
+extern unsigned short *set_translate(int m,int currcons);
 extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
index 41d57b95900848647f6eb860cd7176bd523d4808..6e67b5414d86cc6545e0c8d6d7653dbdd6c1b980 100644 (file)
@@ -581,6 +581,7 @@ struct cyclades_port {
 #define        CyISA_Ywin      0x2000
 
 #define CyPCI_Ywin     0x4000
+#define CyPCI_Yctl     0x80
 #define CyPCI_Zctl     CTRL_WINDOW_SIZE
 #define CyPCI_Zwin     0x80000
 #define CyPCI_Ze_win   (2 * CyPCI_Zwin)
index 93b86369558f0d2ca5d480c9abe50fe24e743d6e..6d4242206ebac8636e7491ed6f604cb4cfe23dc0 100644 (file)
@@ -42,7 +42,7 @@ static __inline__ unsigned long end_name_hash(unsigned long hash)
 }
 
 /* Compute the hash for a name string. */
-static __inline__ unsigned int full_name_hash(const char * name, unsigned int len)
+static __inline__ unsigned int full_name_hash(const unsigned char * name, unsigned int len)
 {
        unsigned long hash = init_name_hash();
        while (len--)
index 79d657a0d650b95d762e57a1c7a07d47fbe9fe5e..a164f2a955291d81331504b3a4cef78e5164d3fe 100644 (file)
 #define WIN_SETIDLE1           0xE3
 #define WIN_SETIDLE2           0x97
 
+#define WIN_STANDBYNOW1                0xE0
+#define WIN_STANDBYNOW2                0x94
+#define WIN_SLEEPNOW1          0xE6
+#define WIN_SLEEPNOW2          0x99
+#define WIN_CHECKPOWERMODE1    0xE5
+#define WIN_CHECKPOWERMODE2    0x98
+
 #define WIN_DOORLOCK           0xde    /* lock door on removable drives */
 #define WIN_DOORUNLOCK         0xdf    /* unlock door on removable drives */
 
@@ -59,6 +66,7 @@
 #define WIN_MULTWRITE          0xC5    /* write sectors using multiple mode */
 #define WIN_SETMULT            0xC6    /* enable/disable multiple mode */
 #define WIN_IDENTIFY           0xEC    /* ask drive to identify itself */
+#define WIN_IDENTIFY_DMA       0xEE    /* same as WIN_IDENTIFY, but DMA */
 #define WIN_SETFEATURES                0xEF    /* set special drive features */
 #define WIN_READDMA            0xc8    /* read sectors using DMA transfers */
 #define WIN_WRITEDMA           0xca    /* write sectors using DMA transfers */
 #define SMART_STATUS           0xda
 #define SMART_AUTO_OFFLINE     0xdb
 
+/* WIN_SECURITY sub-commands */
+#define SECURITY_SET_PASSWORD          0xBA    /* 0xF1 */
+#define SECURITY_UNLOCK                        0xBB    /* 0xF2 */
+#define SECURITY_ERASE_PREPARE         0xBC    /* 0xF3 */
+#define SECURITY_ERASE_UNIT            0xBD    /* 0xF4 */
+#define SECURITY_FREEZE_LOCK           0xBE    /* 0xF5 */
+#define SECURITY_DISABLE_PASSWORD      0xBF    /* 0xF6 */
+
 /* Bits for HD_ERROR */
 #define MARK_ERR       0x01    /* Bad address mark */
 #define TRK0_ERR       0x02    /* couldn't find track 0 */
@@ -184,14 +200,54 @@ struct hd_driveid {
        unsigned short  word79;
        unsigned short  word80;
        unsigned short  word81;
-       unsigned short  word82;
-       unsigned short  word83;
+       unsigned short  command_sets;   /* bits 0:Smart 1:Security 2:Removable 3:PM */
+       unsigned short  word83;         /* bits 14:Smart Enabled 13:0 zero */
        unsigned short  word84;
        unsigned short  word85;
        unsigned short  word86;
        unsigned short  word87;
        unsigned short  dma_ultra;
-       unsigned short  reserved[167];
+       unsigned short  word89;         /* reserved (word 89) */
+       unsigned short  word90;         /* reserved (word 90) */
+       unsigned short  word91;         /* reserved (word 91) */
+       unsigned short  word92;         /* reserved (word 92) */
+       unsigned short  word93;         /* reserved (word 93) */
+       unsigned short  word94;         /* reserved (word 94) */
+       unsigned short  word95;         /* reserved (word 95) */
+       unsigned short  word96;         /* reserved (word 96) */
+       unsigned short  word97;         /* reserved (word 97) */
+       unsigned short  word98;         /* reserved (word 98) */
+       unsigned short  word99;         /* reserved (word 99) */
+       unsigned short  word100;        /* reserved (word 100) */
+       unsigned short  word101;        /* reserved (word 101) */
+       unsigned short  word102;        /* reserved (word 102) */
+       unsigned short  word103;        /* reserved (word 103) */
+       unsigned short  word104;        /* reserved (word 104) */
+       unsigned short  word105;        /* reserved (word 105) */
+       unsigned short  word106;        /* reserved (word 106) */
+       unsigned short  word107;        /* reserved (word 107) */
+       unsigned short  word108;        /* reserved (word 108) */
+       unsigned short  word109;        /* reserved (word 109) */
+       unsigned short  word110;        /* reserved (word 110) */
+       unsigned short  word111;        /* reserved (word 111) */
+       unsigned short  word112;        /* reserved (word 112) */
+       unsigned short  word113;        /* reserved (word 113) */
+       unsigned short  word114;        /* reserved (word 114) */
+       unsigned short  word115;        /* reserved (word 115) */
+       unsigned short  word116;        /* reserved (word 116) */
+       unsigned short  word117;        /* reserved (word 117) */
+       unsigned short  word118;        /* reserved (word 118) */
+       unsigned short  word119;        /* reserved (word 119) */
+       unsigned short  word120;        /* reserved (word 120) */
+       unsigned short  word121;        /* reserved (word 121) */
+       unsigned short  word122;        /* reserved (word 122) */
+       unsigned short  word123;        /* reserved (word 123) */
+       unsigned short  word124;        /* reserved (word 124) */
+       unsigned short  word125;        /* reserved (word 125) */
+       unsigned short  word126;        /* reserved (word 126) */
+       unsigned short  word127;        /* reserved (word 127) */
+       unsigned short  security;       /* bits 0:support 1:enabled 2:locked 3:frozen */
+       unsigned short  reserved[127];
 };
 
 /*
index f81844cf7b7dc66ffe14ef068e3c5d0021134e49..2b3b44ff93bc45e091a6e34d54418dcb229b18ba 100644 (file)
@@ -71,10 +71,10 @@ asmlinkage int printk(const char * fmt, ...)
  */
 
 #define NIPQUAD(addr) \
-       (int)(((addr) >> 0)  & 0xff), \
-       (int)(((addr) >> 8)  & 0xff), \
-       (int)(((addr) >> 16) & 0xff), \
-       (int)(((addr) >> 24) & 0xff)
+       ((unsigned char *)&addr)[0], \
+       ((unsigned char *)&addr)[1], \
+       ((unsigned char *)&addr)[2], \
+       ((unsigned char *)&addr)[3]
 
 #endif /* __KERNEL__ */
 
index aea15a68b105d2ead12f16be928f3123e81d8908..4c32fe530be4712902af246161f460e4ae8b679c 100644 (file)
  */
 #define NFSD_VERSION           "0.4"
 
-/*
- * Maximum number of nfsd processes
- */
-#define NFSD_MAXSERVS          16
-
 #ifdef __KERNEL__
 /*
  * Special flags for nfsd_permission. These must be different from MAY_READ,
@@ -76,6 +71,7 @@ int           nfsd_svc(unsigned short port, int nrservs);
 /* nfsd/vfs.c */
 int            fh_lock_parent(struct svc_fh *, struct dentry *);
 void           nfsd_racache_init(void);
+void           nfsd_racache_shutdown(void);
 int            nfsd_lookup(struct svc_rqst *, struct svc_fh *,
                                const char *, int, struct svc_fh *);
 int            nfsd_setattr(struct svc_rqst *, struct svc_fh *,
@@ -167,6 +163,11 @@ extern u32 nfs_ok,
  */
 extern struct timeval  nfssvc_boot;
 
+/*
+ * The number of nfsd threads.
+ */
+extern int             nfsd_nservers;
+
 #endif /* __KERNEL__ */
 
 #endif /* LINUX_NFSD_NFSD_H */
index 066d9c20a142ba1cc205d2c09e6b2c30c45b0633..ad996ef84f3669c1bf9a33221947a6adb26dcfde 100644 (file)
 #define PCI_VENDOR_ID_QLOGIC           0x1077
 #define PCI_DEVICE_ID_QLOGIC_ISP1020   0x1020
 #define PCI_DEVICE_ID_QLOGIC_ISP1022   0x1022
+#define PCI_DEVICE_ID_QLOGIC_ISP2100   0x2100
 
 #define PCI_VENDOR_ID_CYRIX            0x1078
 #define PCI_DEVICE_ID_CYRIX_5510       0x0000
 #define PCI_DEVICE_ID_VIA_82C597_1     0x8597
 #define PCI_DEVICE_ID_VIA_82C598_1      0x8598
 
+#define PCI_VENDOR_ID_SMC2             0x1113
+#define PCI_DEVICE_ID_SMC2_1211TX      0x1211
+
 #define PCI_VENDOR_ID_VORTEX           0x1119
 #define PCI_DEVICE_ID_VORTEX_GDT60x0   0x0000
 #define PCI_DEVICE_ID_VORTEX_GDT6000B  0x0001
 #define PCI_DEVICE_ID_S3_ViRGE_MXPMV   0x8c03
 #define PCI_DEVICE_ID_S3_SONICVIBES    0xca00
 
+#define PCI_VENDOR_ID_DCI       0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4    0x0001
+
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_82375      0x0482
 #define PCI_DEVICE_ID_INTEL_82424      0x0483
index f0f8e03845e55b43a5eef9ea419f2de5e87308e3..8ec30527f22b8b20c6932ce6ba030543570fb944 100644 (file)
@@ -128,7 +128,7 @@ void                rpc_killall_tasks(struct rpc_clnt *);
 void           rpc_execute(struct rpc_task *);
 void           rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
                                        rpc_action action);
-void           rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
+int            rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
 void           rpc_remove_wait_queue(struct rpc_task *);
 void           rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
                                        rpc_action action, rpc_action timer);
index 7c9a1e525502701732c2143f087e2b1a6039aa06..4ab59ed1c500f39e76c1a24e0e75d09cefe86342 100644 (file)
@@ -106,7 +106,8 @@ struct svc_rqst {
        u32                     rq_prot;        /* IP protocol */
        unsigned short          rq_verfed  : 1, /* reply has verifier */
                                rq_userset : 1, /* auth->setuser OK */
-                               rq_secure  : 1; /* secure port */
+                               rq_secure  : 1, /* secure port */
+                               rq_auth    : 1; /* check client */
 
        void *                  rq_argp;        /* decoded arguments */
        void *                  rq_resp;        /* xdr'd results */
index 3141875a1ad0998019492fb25fd8b51cf1e7012e..a976c74693207d198dc7c3c925d364f485165860 100644 (file)
@@ -112,7 +112,7 @@ enum
        VM_PAGECACHE=7,         /* struct: Set cache memory thresholds */
        VM_PAGERDAEMON=8,       /* struct: Control kswapd behaviour */
        VM_PGT_CACHE=9,         /* struct: Set page table cache parameters */
-       VM_PAGE_CLUSTER=10      /* int: set log2 number of pages to swap together */
+       VM_PAGE_CLUSTER=10      /* int: set number of pages to swap together */
 };
 
 
@@ -376,11 +376,12 @@ enum
 
 /* /proc/sys/net/decnet */
 enum {
-       NET_DECNET_NODE_TYPE=1,
-       NET_DECNET_NODE_ADDRESS=2,
-       NET_DECNET_NODE_NAME=3,
-       NET_DECNET_DEFAULT_DEVICE=4,
-       NET_DECNET_DEBUG_LEVEL=255
+       NET_DECNET_DEF_T3_BROADCAST=1,
+       NET_DECNET_DEF_T3_POINTTOPOINT=2,
+       NET_DECNET_DEF_T1=3,
+       NET_DECNET_DEF_BCT1=4,
+       NET_DECNET_CACHETIMEOUT=5,
+       NET_DECNET_DEBUG_LEVEL=6
 };
 
 /* CTL_PROC names: */
@@ -397,7 +398,7 @@ enum
        FS_MAXFILE=7,   /* int:maximum number of filedescriptors that can be allocated */
        FS_DENTRY=8,
        FS_NRSUPER=9,   /* int:current number of allocated super_blocks */
-       FS_MAXSUPER=10  /* int:maximum number of super_blocks that can be allocated */
+       FS_MAXSUPER=10  /* int:maximum number of super_blocks that can be allocated */
 };
 
 /* CTL_DEBUG names: */
index 76dab1072bd6af986a6154e01f12a4d82a2bbf00..547e5c2c1ca88d6bab153deacda7f8b9172a334c 100644 (file)
@@ -98,7 +98,9 @@ struct xenix_super_block {
        char            s_fill[371];
        s32             s_magic;        /* version of file system */
        s32             s_type;         /* type of file system: 1 for 512 byte blocks
-                                                               2 for 1024 byte blocks */
+                                                               2 for 1024 byte blocks
+                                                               3 for 2048 byte blocks */
+                                                               
 };
 
 /* Xenix free list block on disk */
index 9aa69359d9cfe9b47d08a91bd6cc2ef7b6e2b0a0..b7224f330054a253c72fec12d818404ab19d493a 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -624,6 +624,7 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
        unsigned int id, idx;
 
        id = SWP_OFFSET(code) & SHM_ID_MASK;
+#ifdef DEBUG_SHM
        if (id != (SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK)) {
                printk ("shm_swap_in: code id = %d and shmd id = %ld differ\n",
                        id, SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK);
@@ -633,12 +634,17 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
                printk ("shm_swap_in: id=%d too big. proc mem corrupted\n", id);
                return BAD_PAGE;
        }
+#endif
        shp = shm_segs[id];
+
+#ifdef DEBUG_SHM
        if (shp == IPC_UNUSED || shp == IPC_NOID) {
                printk ("shm_swap_in: id=%d invalid. Race.\n", id);
                return BAD_PAGE;
        }
+#endif
        idx = (SWP_OFFSET(code) >> SHM_IDX_SHIFT) & SHM_IDX_MASK;
+#ifdef DEBUG_SHM
        if (idx != (offset >> PAGE_SHIFT)) {
                printk ("shm_swap_in: code idx = %u and shmd idx = %lu differ\n",
                        idx, offset >> PAGE_SHIFT);
@@ -648,6 +654,7 @@ static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, uns
                printk ("shm_swap_in : too large page index. id=%d\n", id);
                return BAD_PAGE;
        }
+#endif
 
        pte = __pte(shp->shm_pages[idx]);
        if (!pte_present(pte)) {
index 110296bca325c173f816411c1897182bb9143d88..dc0baed323e734ec0ac3c132b3a9c9de637143f6 100644 (file)
@@ -124,12 +124,12 @@ static int check_free_space(struct file *file)
        if (acct_active) {
                if (act < 0) {
                        acct_active = 0;
-                       printk(KERN_INFO "Process accounting paused\r\n");
+                       printk(KERN_INFO "Process accounting paused\n");
                }
        } else {
                if (act > 0) {
                        acct_active = 1;
-                       printk(KERN_INFO "Process accounting resumed\r\n");
+                       printk(KERN_INFO "Process accounting resumed\n");
                }
        }
 
index 2c1b2312a91d81a7554322a2536958cc80f48e58..93b13bac3b84743e683939e7e97b8ff85ffbacc6 100644 (file)
@@ -129,6 +129,7 @@ EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
 EXPORT_SYMBOL(fput);
+EXPORT_SYMBOL(put_filp);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
@@ -360,6 +361,7 @@ EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(brw_page);
 
 /* all busmice */
 EXPORT_SYMBOL(add_mouse_randomness);
index 0c7bd869923a471a0bc53aabeb79d60275efc90e..d511160e6284e0cb62aa6231dd7c1965439a69f8 100644 (file)
@@ -155,6 +155,15 @@ send:
 }
 #endif /* __SMP__ */
 
+/*
+ * If there is a dependency between p1 and p2,
+ * don't be too eager to go into the slow schedule.
+ * In particular, if p1 and p2 both want the kernel
+ * lock, there is no point in trying to make them
+ * extremely parallel..
+ */
+#define related(p1,p2) ((p1)->lock_depth && (p2)->lock_depth)
+
 static inline void reschedule_idle(struct task_struct * p)
 {
 
@@ -197,7 +206,7 @@ static inline void reschedule_idle(struct task_struct * p)
         *
         * [We can switch to something more finegrained in 2.3.]
         */
-       if ((current->avg_slice < cacheflush_time) && !in_interrupt())
+       if ((current->avg_slice < cacheflush_time) && related(current, p))
                return;
 
        reschedule_idle_slow(p);
index ad23a8d5fa815653d72375e9a1c5a0b676922388..67e6f334ef82e9149f5996d064d7410e8ec8e9a7 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/nfs_fs.h>
 #endif
 
-#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+#if defined(CONFIG_SYSCTL)
 
 /* External variables not in a header file. */
 extern int panic_timeout;
@@ -36,6 +36,8 @@ extern int console_loglevel, C_A_D;
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 extern int sysctl_overcommit_memory;
+extern int nr_queued_signals, max_queued_signals;
+
 #ifdef CONFIG_KMOD
 extern char modprobe_path[];
 #endif
@@ -70,7 +72,9 @@ static struct ctl_table_header root_table_header =
 
 static ctl_table kern_table[];
 static ctl_table vm_table[];
+#ifdef CONFIG_NET
 extern ctl_table net_table[];
+#endif
 static ctl_table proc_table[];
 static ctl_table fs_table[];
 static ctl_table debug_table[];
@@ -123,18 +127,20 @@ struct inode_operations proc_sys_inode_operations =
 
 extern struct proc_dir_entry proc_sys_root;
 
-extern int inodes_stat[];
-extern int dentry_stat[];
 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 #endif
+extern int inodes_stat[];
+extern int dentry_stat[];
 
 /* The default sysctl tables: */
 
 static ctl_table root_table[] = {
        {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
        {CTL_VM, "vm", NULL, 0, 0555, vm_table},
+#ifdef CONFIG_NET
        {CTL_NET, "net", NULL, 0, 0555, net_table},
+#endif
        {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
        {CTL_FS, "fs", NULL, 0, 0555, fs_table},
        {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
@@ -195,6 +201,10 @@ static ctl_table kern_table[] = {
        {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
        0644, NULL, &proc_dointvec},
 #endif
+       {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
+        0444, NULL, &proc_dointvec},
+       {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
+        0644, NULL, &proc_dointvec},
        {0}
 };
 
@@ -868,14 +878,14 @@ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 
 #else /* CONFIG_PROC_FS */
 
-int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
-                         void *buffer, size_t *lenp)
+int proc_dostring(ctl_table *table, int write, struct file *filp,
+                 void *buffer, size_t *lenp)
 {
-  return -ENOSYS; 
+       return -ENOSYS;
 }
 
-int proc_dostring(ctl_table *table, int write, struct file *filp,
-                 void *buffer, size_t *lenp)
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+                           void *buffer, size_t *lenp)
 {
        return -ENOSYS;
 }
@@ -1055,7 +1065,7 @@ int do_struct (
 }
 
 
-#else /* CONFIG_PROC_FS && CONFIG_SYSCTL */
+#else /* CONFIG_SYSCTL */
 
 
 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
@@ -1111,7 +1121,4 @@ void unregister_sysctl_table(struct ctl_table_header * table)
 {
 }
 
-#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */
-
-
-
+#endif /* CONFIG_SYSCTL */
index 0f782a94f5915faf0080268870b7d0667afaa52c..293eadf893d458df764267e1051b5164474dc7e9 100644 (file)
@@ -564,10 +564,10 @@ int try_to_free_pages(unsigned int gfp_mask, int count)
        
                priority = 5;
                do {
+                       shrink_dcache_memory(priority, gfp_mask);
                        free_memory(shrink_mmap(priority, gfp_mask));
                        free_memory(shm_swap(priority, gfp_mask));
                        free_memory(swap_out(priority, gfp_mask));
-                       shrink_dcache_memory(priority, gfp_mask);
                } while (--priority >= 0);
                retval = 0;
 done:
index 43e0e1705899de0b08d987b9e13cd6a42832f023..ae9abe2e5c61cb44421214d7f481ddcc6db008a9 100644 (file)
@@ -54,11 +54,14 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL
   bool 'CPU is too slow to handle full bandwidth' CONFIG_CPU_IS_SLOW
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'QoS and/or fair queueing'
   bool 'QoS and/or fair queueing' CONFIG_NET_SCHED
   if [ "$CONFIG_NET_SCHED" = "y" ]; then
     source net/sched/Config.in
   fi
 #  bool 'Network code profiler' CONFIG_NET_PROFILE
+  endmenu
   fi
 fi
 endmenu
index ecbe9d99a7cc79c712d68e32f831c640e2d90f64..5df65cd226d1f2c9161f4dc3ce2d9d222ada52a3 100644 (file)
@@ -12,8 +12,10 @@ O_TARGET := core.o
 O_OBJS := sock.o skbuff.o iovec.o datagram.o scm.o
 
 ifeq ($(CONFIG_SYSCTL),y)
+ifeq ($(CONFIG_NET),y)
 O_OBJS += sysctl_net_core.o
 endif
+endif
 
 ifdef CONFIG_FILTER
 O_OBJS += filter.o
index 5d685b0d240771351c2a29ce85f63c9f126d1aef..fc7b1a5171379e81250d88cf110e1395c6dac511 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/semaphore.h>
 
 struct semaphore firewall_sem = MUTEX; 
@@ -89,6 +90,7 @@ int unregister_firewall(int pf, struct firewall_ops *fw)
                        struct firewall_ops *f=fw->next;
                        *nl = f;
                        up(&firewall_sem); 
+                       synchronize_bh();
                        return 0;
                }
                nl=&((*nl)->next);
index ac7c04432df64eac3e62e35868ee2b7440db9966..dc0c426f5bb4eb2cd8876a6a83460c0dbf320e27 100644 (file)
@@ -208,9 +208,16 @@ inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa)
 {
        struct in_ifaddr *ifa1, **ifap, **last_primary;
 
-       if (ifa->ifa_local == 0) {
-               inet_free_ifa(ifa);
-               return 0;
+       /* Allow 0.0.0.0, but it must be the only address to avoid
+           multiple matches. */
+       if (in_dev->ifa_list) {
+               if (ifa->ifa_local == 0) {
+                       inet_free_ifa(ifa);
+                       return 0;
+               }
+
+               if (in_dev->ifa_list->ifa_local == 0)
+                       inet_del_ifa(in_dev, &in_dev->ifa_list, 1);
        }
 
        ifa->ifa_flags &= ~IFA_F_SECONDARY;
@@ -1001,18 +1008,12 @@ static void devinet_sysctl_unregister(struct ipv4_devconf *p)
 
 __initfunc(int inet_add_bootp_addr(struct device *dev))
 {
-       struct in_device *in_dev = dev->ip_ptr;
        struct in_ifaddr *ifa;
 
-       if (!in_dev && !(in_dev = inetdev_init(dev)))
-               return -ENOBUFS;
        if (!(ifa = inet_alloc_ifa()))
                return -ENOBUFS;
-       ifa->ifa_dev = in_dev;
-       in_dev->ifa_list = ifa;
-       rtmsg_ifa(RTM_NEWADDR, ifa);
-       notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
-       return 0;
+
+       return inet_set_ifa(dev, ifa);
 }
 
 __initfunc(void inet_del_bootp_addr(struct device *dev))
index 013a4ba9a95e2e64298bf73adc2d3446be1c3c55..0308bbc247c93ff11779c4154265838d4e6543d1 100644 (file)
@@ -443,13 +443,13 @@ static void fib_add_ifaddr(struct in_ifaddr *ifa)
        if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
                fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
 
-       if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+       if (!(ifa->ifa_flags&IFA_F_SECONDARY) &&
            (prefix != addr || ifa->ifa_prefixlen < 32)) {
                fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
                          RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
 
                /* Add network specific broadcasts, when it takes a sense */
-               if (ifa->ifa_prefixlen < 31) {
+               if (!ZERONET(prefix) && ifa->ifa_prefixlen < 31) {
                        fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
                        fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
                }
index db1d7fc3f0dbf3600e7376ca080caf6da65bf89d..4a3f2a747d82aeffe57d445e1548f7e0aac18f66 100644 (file)
@@ -410,96 +410,6 @@ struct bootp_pkt {         /* BOOTP packet format */
 static struct bootp_pkt *ic_xmit_bootp __initdata = NULL; /* Packet being transmitted */
 static struct bootp_pkt *ic_recv_bootp __initdata = NULL; /* Packet being received */
 
-/*
- *  Dirty tricks for BOOTP packet routing.  We replace the standard lookup function
- *  for the local fib by our version which does fake lookups and returns our private
- *  fib entries. Ugly, but it seems to be the simplest way to do the job.
- */
-
-static void *ic_old_local_lookup __initdata = NULL;    /* Old local routing table lookup function */
-static struct fib_info *ic_bootp_tx_fib __initdata = NULL; /* Our fake fib entries */
-static struct fib_info *ic_bootp_rx_fib __initdata = NULL;
-
-__initfunc(static int ic_bootp_route_lookup(struct fib_table *tb, const struct rt_key *key,
-       struct fib_result *res))
-{
-       static u32 ic_brl_zero = 0;
-
-       DBG(("BOOTP: Route lookup: %d:%08x -> %d:%08x: ", key->iif, key->src, key->oif, key->dst));
-       res->scope = RT_SCOPE_UNIVERSE;
-       res->prefix = &ic_brl_zero;
-       res->prefixlen = 0;
-       res->nh_sel = 0;
-       if (key->src == 0 && key->dst == 0xffffffff && key->iif == loopback_dev.ifindex) { /* Packet output */
-               DBG(("Output\n"));
-               res->type = RTN_UNICAST;
-               res->fi = ic_bootp_tx_fib;
-       } else if (key->iif && key->iif != loopback_dev.ifindex && key->oif == 0) {     /* Packet input */
-               DBG(("Input\n"));
-               res->type = RTN_LOCAL;
-               res->fi = ic_bootp_rx_fib;
-       } else if (!key->iif && !key->oif && !key->src) {       /* Address check by inet_addr_type() */
-               DBG(("Check\n"));
-               res->type = RTN_UNICAST;
-               res->fi = ic_bootp_tx_fib;
-       } else {
-               DBG(("Drop\n"));
-               return -EINVAL;
-       }
-       return 0;
-}
-
-__initfunc(static int ic_set_bootp_route(struct ic_device *d))
-{
-       struct fib_info *f = ic_bootp_tx_fib;
-       struct fib_nh *n = &f->fib_nh[0];
-
-       n->nh_dev = d->dev;
-       n->nh_oif = n->nh_dev->ifindex;
-       rt_cache_flush(0);
-       return 0;
-}
-
-__initfunc(static int ic_bootp_route_init(void))
-{
-       int size = sizeof(struct fib_info) + sizeof(struct fib_nh);
-       struct fib_info *rf, *tf;
-       struct fib_nh *nh;
-
-       if (!(rf = ic_bootp_rx_fib = kmalloc(size, GFP_KERNEL)) ||
-           !(tf = ic_bootp_tx_fib = kmalloc(size, GFP_KERNEL)))
-               return -1;
-
-       memset(rf, 0, size);
-       rf->fib_nhs = 1;
-       nh = &rf->fib_nh[0];
-       nh->nh_scope = RT_SCOPE_UNIVERSE;
-
-       memset(tf, 0, size);
-       rf->fib_nhs = 1;
-       nh = &rf->fib_nh[0];
-       nh->nh_dev = ic_first_dev->dev;
-       nh->nh_scope = RT_SCOPE_UNIVERSE;
-       nh->nh_oif = nh->nh_dev->ifindex;
-
-       /* Dirty trick: replace standard routing table lookup by our function */
-       ic_old_local_lookup = local_table->tb_lookup;
-       local_table->tb_lookup = ic_bootp_route_lookup;
-
-       return 0;
-}
-
-__initfunc(static void ic_bootp_route_cleanup(void))
-{
-       if (ic_old_local_lookup)
-               local_table->tb_lookup = ic_old_local_lookup;
-       if (ic_bootp_rx_fib)
-               kfree_s(ic_bootp_rx_fib, sizeof(struct fib_info) + sizeof(struct fib_nh));
-       if (ic_bootp_tx_fib)
-               kfree_s(ic_bootp_tx_fib, sizeof(struct fib_info) + sizeof(struct fib_nh));
-}
-
-
 /*
  *  Allocation and freeing of BOOTP packet buffers.
  */
@@ -677,10 +587,9 @@ __initfunc(static int ic_bootp_init(void))
        /* Add fake zero addresses to all interfaces */
        if (ic_bootp_addrs_add() < 0)
                return -1;
-
-       /* Initialize BOOTP routing */
-       if (ic_bootp_route_init() < 0)
-               return -1;
+       
+       /* Setting the addresses automatically creates appropriate
+          routes. */   
 
        /* Initialize common portion of BOOTP request */
        memset(ic_xmit_bootp, 0, sizeof(struct bootp_pkt));
@@ -699,7 +608,6 @@ __initfunc(static int ic_bootp_init(void))
        ic_bootp_xmit_sock->sk->broadcast = 1;
        ic_bootp_xmit_sock->sk->reuse = 1;
        ic_bootp_recv_sock->sk->reuse = 1;
-       ic_set_bootp_route(ic_first_dev);
        if (ic_udp_bind(ic_bootp_recv_sock, INADDR_ANY, 68) ||
            ic_udp_bind(ic_bootp_xmit_sock, INADDR_ANY, 68) ||
            ic_udp_connect(ic_bootp_xmit_sock, INADDR_BROADCAST, 67))
@@ -718,7 +626,6 @@ __initfunc(static void ic_bootp_cleanup(void))
        ic_udp_close(ic_bootp_recv_sock);
        ic_bootp_addrs_del();
        ic_bootp_free();
-       ic_bootp_route_cleanup();
 }
 
 
@@ -735,7 +642,6 @@ __initfunc(static int ic_bootp_send_if(struct ic_device *d, u32 jiffies))
        memset(b->hw_addr, 0, sizeof(b->hw_addr));
        memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
        b->secs = htons(jiffies / HZ);
-       ic_set_bootp_route(d);
        return ic_udp_send(ic_bootp_xmit_sock, b, sizeof(struct bootp_pkt));
 }
 
index a3d002fae6273bb3e6332e268e03cea3afddf907..710a6077a169c97676062d127496a77d77ebd90c 100644 (file)
@@ -950,6 +950,10 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
        if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
                goto martian_destination;
 
+       /* Accept anything arriving at 0.0.0.0 */
+       if (in_dev->ifa_list && in_dev->ifa_list->ifa_local == 0)
+               goto local_input;
+
        /*
         *      Now we are ready to route packet.
         */
index b6f1c7a93a958a03990e7970a772ea05329fb4c9..bdd96afe721703ebe9c11500b06b4edccf9b4b80 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.132 1998/11/08 13:21:14 davem Exp $
+ * Version:    $Id: tcp.c,v 1.133 1998/11/30 15:13:06 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1612,19 +1612,15 @@ struct sock *tcp_accept(struct sock *sk, int flags)
        if(sk->keepopen)
                tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
 
-       /*
-        * This does not pass any already set errors on the new socket
-        * to the user, but they will be returned on the first socket operation
-        * after the accept.
-        *
-        * Once linux gets a multithreaded net_bh or equivalent there will be a race
-        * here - you'll have to check for sk->zapped as set by the ICMP handler then.
-        */
+       release_sock(sk);
+       return newsk;
 
-       error = 0;
 out:
+       /* sk should be in LISTEN state, thus accept can use sk->err for
+        * internal purposes without stomping one anyone's feed.
+        */ 
+       sk->err = error; 
        release_sock(sk);
-       sk->err = error;
        return newsk;
 }
 
index 59ae01f88891610c1dc0156681f4899bd4cd5570..09413e35d458e6aa568588a2b2236180b483a482 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.141 1998/11/18 02:12:07 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.143 1998/12/20 20:20:20 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -301,7 +301,7 @@ static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp,
                        /* The retransmission queue is always in order, so
                         * we can short-circuit the walk early.
                         */
-                       if(!before(start_seq, TCP_SKB_CB(skb)->end_seq))
+                       if(after(TCP_SKB_CB(skb)->seq, start_seq))
                                break;
 
                        /* We play conservative, we don't allow SACKS to partially
@@ -598,6 +598,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
        unsigned long now = jiffies;
        int acked = 0;
 
+       /* If we are retransmitting, and this ACK clears up to
+        * the retransmit head, or further, then clear our state.
+        */
+       if (tp->retrans_head != NULL &&
+           !before(ack, TCP_SKB_CB(tp->retrans_head)->end_seq))
+               tp->retrans_head = NULL;
+
        while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) {
                struct tcp_skb_cb *scb = TCP_SKB_CB(skb); 
                __u8 sacked = scb->sacked;
@@ -625,6 +632,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
                        if(tp->fackets_out)
                                tp->fackets_out--;
                } else {
+                       /* This is pure paranoia. */
                        tp->retrans_head = NULL;
                }               
                tp->packets_out--;
@@ -633,9 +641,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
                __skb_unlink(skb, skb->list);
                kfree_skb(skb);
        }
-
-       if (acked)
-               tp->retrans_head = NULL;
        return acked;
 }
 
@@ -740,7 +745,6 @@ static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
         * congestion window is handled properly by that code.
         */
        if (tp->retransmits) {
-               tp->retrans_head = NULL;
                tcp_xmit_retransmit_queue(sk);
                tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
        } else {
@@ -1657,9 +1661,12 @@ static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len
        }
 }
 
-/*
- * Clean first the out_of_order queue, then the receive queue until
- * the socket is in its memory limits again.
+/* Clean the out_of_order queue if we can, trying to get
+ * the socket within its memory limits again.
+ *
+ * Return less than zero if we should stop dropping frames
+ * until the socket owning process reads some of the data
+ * to stabilize the situation.
  */
 static int prune_queue(struct sock *sk)
 {
@@ -1670,8 +1677,8 @@ static int prune_queue(struct sock *sk)
 
        net_statistics.PruneCalled++; 
 
-       /* First Clean the out_of_order queue. */
-       /* Start with the end because there are probably the least
+       /* Clean the out_of_order queue.
+        * Start with the end because there are probably the least
         * useful packets (crossing fingers).
         */
        while ((skb = __skb_dequeue_tail(&tp->out_of_order_queue))) { 
@@ -1681,35 +1688,32 @@ static int prune_queue(struct sock *sk)
                        return 0;
        }
        
-       /* Now continue with the receive queue if it wasn't enough.
-        * But only do this if we are really being abused.
+       /* If we are really being abused, tell the caller to silently
+        * drop receive data on the floor.  It will get retransmitted
+        * and hopefully then we'll have sufficient space.
+        *
+        * We used to try to purge the in-order packets too, but that
+        * turns out to be deadly and fraught with races.  Consider:
+        *
+        * 1) If we acked the data, we absolutely cannot drop the
+        *    packet.  This data would then never be retransmitted.
+        * 2) It is possible, with a proper sequence of events involving
+        *    delayed acks and backlog queue handling, to have the user
+        *    read the data before it gets acked.  The previous code
+        *    here got this wrong, and it lead to data corruption.
+        * 3) Too much state changes happen when the FIN arrives, so once
+        *    we've seen that we can't remove any in-order data safely.
+        *
+        * The net result is that removing in-order receive data is too
+        * complex for anyones sanity.  So we don't do it anymore.  But
+        * if we are really having our buffer space abused we stop accepting
+        * new receive data.
         */
-       while ((atomic_read(&sk->rmem_alloc) >= (sk->rcvbuf * 2)) &&
-              (skb = skb_peek_tail(&sk->receive_queue))) {
-               /* Never toss anything when we've seen the FIN.
-                * It's just too complex to recover from it.
-                */
-               if(skb->h.th->fin)
-                       break;
-
-               /* Never remove packets that have been already acked */
-               if (before(TCP_SKB_CB(skb)->end_seq, tp->last_ack_sent+1)) {
-                       SOCK_DEBUG(sk, "prune_queue: hit acked data c=%x,%x,%x\n",
-                                  tp->copied_seq, TCP_SKB_CB(skb)->end_seq,
-                                  tp->last_ack_sent);
-                       return -1;
-               }
-
-               net_statistics.RcvPruned += skb->len; 
+       if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1))
+               return 0;
 
-               __skb_unlink(skb, skb->list);
-               tp->rcv_nxt = TCP_SKB_CB(skb)->seq;
-               SOCK_DEBUG(sk, "prune_queue: removing %x-%x (c=%x)\n",
-                          TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-                          tp->copied_seq); 
-               kfree_skb(skb);
-       }
-       return 0;
+       /* Massive buffer overcommit. */
+       return -1;
 }
 
 /*
index f486852d10753fed41b9cc7753eb06402015d5a7..421ffce0b49f2b286ad5b0e595731d425ef887da 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.162 1998/11/07 11:50:26 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.163 1998/11/30 15:24:22 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -265,7 +265,7 @@ unsigned short tcp_good_socknum(void)
        struct tcp_bind_bucket *tb;
        int low = sysctl_local_port_range[0];
        int high = sysctl_local_port_range[1];
-       int remaining = high - low + 1;
+       int remaining = (high - low) + 1;
        int rover;
 
        SOCKHASH_LOCK();
index 25695f05d627722b59fb668d0ca350a534bcbc9a..dc11d25643feb3190c49d1e7bb98b27c2d22da13 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.97 1998/11/08 13:21:27 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.98 1998/12/12 06:43:35 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -80,15 +80,28 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
                int tcp_header_size = tp->tcp_header_len;
                struct tcphdr *th;
+               int sysctl_flags;
 
+#define SYSCTL_FLAG_TSTAMPS    0x1
+#define SYSCTL_FLAG_WSCALE     0x2
+#define SYSCTL_FLAG_SACK       0x4
+
+               sysctl_flags = 0;
                if(tcb->flags & TCPCB_FLAG_SYN) {
                        tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
-                       if(sysctl_tcp_timestamps)
+                       if(sysctl_tcp_timestamps) {
                                tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
-                       if(sysctl_tcp_window_scaling)
+                               sysctl_flags |= SYSCTL_FLAG_TSTAMPS;
+                       }
+                       if(sysctl_tcp_window_scaling) {
                                tcp_header_size += TCPOLEN_WSCALE_ALIGNED;
-                       if(sysctl_tcp_sack && !sysctl_tcp_timestamps)
-                               tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
+                               sysctl_flags |= SYSCTL_FLAG_WSCALE;
+                       }
+                       if(sysctl_tcp_sack) {
+                               sysctl_flags |= SYSCTL_FLAG_SACK;
+                               if(!sysctl_tcp_timestamps)
+                                       tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
+                       }
                } else if(tp->sack_ok && tp->num_sacks) {
                        /* A SACK is 2 pad bytes, a 2 byte header, plus
                         * 2 32-bit sequence numbers for each SACK block.
@@ -118,9 +131,9 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                         */
                        th->window      = htons(tp->rcv_wnd);
                        tcp_syn_build_options((__u32 *)(th + 1), tp->mss_clamp,
-                                             sysctl_tcp_timestamps,
-                                             sysctl_tcp_sack,
-                                             sysctl_tcp_window_scaling,
+                                             (sysctl_flags & SYSCTL_FLAG_TSTAMPS),
+                                             (sysctl_flags & SYSCTL_FLAG_SACK),
+                                             (sysctl_flags & SYSCTL_FLAG_WSCALE),
                                              tp->rcv_wscale,
                                              TCP_SKB_CB(skb)->when);
                } else {
@@ -134,6 +147,9 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                tcp_statistics.TcpOutSegs++;
                tp->af_specific->queue_xmit(skb);
        }
+#undef SYSCTL_FLAG_TSTAMPS
+#undef SYSCTL_FLAG_WSCALE
+#undef SYSCTL_FLAG_SACK
 }
 
 /* This is the main buffer sending routine. We queue the buffer
index ea46d326893d838e22254e4e3dad4d9f04ca43c0..6e728572cc9e3cdea3403ecca43f056efdf058d8 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.55 1998/11/07 11:55:42 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.56 1998/11/30 15:18:12 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -170,8 +170,13 @@ void tcp_delack_timer(unsigned long data)
 
        if(!sk->zapped &&
           sk->tp_pinfo.af_tcp.delayed_acks &&
-          sk->state != TCP_CLOSE)
-               tcp_send_ack(sk);
+          sk->state != TCP_CLOSE) {
+               /* If socket is currently locked, defer the ACK. */
+               if (!atomic_read(&sk->sock_readers))
+                       tcp_send_ack(sk);
+               else
+                       tcp_send_delayed_ack(&(sk->tp_pinfo.af_tcp), HZ/10);
+       }
 }
 
 void tcp_probe_timer(unsigned long data)
index d3e96333d452476abc59b41b5c3c0d28ecd99bfe..8c46a1b031fb81054214e5517280121d5b7702e2 100644 (file)
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/in.h>
-#include <net/sock.h>
-#include <net/dst.h>
-#include <net/checksum.h>
-#include <net/pkt_sched.h>
 #include <linux/netdevice.h>
-#include <linux/etherdevice.h>
 #include <linux/fddidevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
 #include <net/neighbour.h>
 #include <net/snmp.h>
+#include <net/dst.h>
+#include <net/checksum.h>
+#include <linux/etherdevice.h>
+#include <net/pkt_sched.h>
 
 #ifdef CONFIG_BRIDGE
 #include <net/br.h>
@@ -29,6 +28,7 @@
 
 #ifdef CONFIG_INET
 #include <linux/ip.h>
+#include <linux/etherdevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/scm.h>
 #include <net/inet_common.h>
+#include <net/pkt_sched.h>
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
 
 extern struct net_proto_family inet_family_ops;
 
-#ifdef CONFIG_DLCI_MODULE
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-EXPORT_SYMBOL(dlci_ioctl_hook);
-#endif
-
-#endif
-
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
 #include <linux/icmpv6.h>
@@ -62,6 +56,7 @@ EXPORT_SYMBOL(dlci_ioctl_hook);
 extern int tcp_tw_death_row_slot;
 #endif
 
+#endif
 
 #include <linux/rtnetlink.h>
 
@@ -87,6 +82,10 @@ extern void destroy_8023_client(struct datalink_proto *);
 
 #ifdef CONFIG_ATALK_MODULE
 #include <net/sock.h>
+#include <net/dst.h>
+#include <net/checksum.h>
+#include <linux/etherdevice.h>
+#include <net/pkt_sched.h>
 #endif
 
 #ifdef CONFIG_SYSCTL
@@ -136,6 +135,9 @@ EXPORT_SYMBOL(sock_no_sendmsg);
 EXPORT_SYMBOL(sock_no_recvmsg);
 EXPORT_SYMBOL(sock_rfree);
 EXPORT_SYMBOL(sock_wfree);
+EXPORT_SYMBOL(sock_wmalloc);
+EXPORT_SYMBOL(sock_rmalloc);
+EXPORT_SYMBOL(sock_rspace);
 EXPORT_SYMBOL(skb_recv_datagram);
 EXPORT_SYMBOL(skb_free_datagram);
 EXPORT_SYMBOL(skb_copy_datagram);
@@ -222,6 +224,7 @@ EXPORT_SYMBOL(ip_route_output);
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(ip_options_compile);
 EXPORT_SYMBOL(arp_send);
+EXPORT_SYMBOL(arp_broken_ops);
 EXPORT_SYMBOL(ip_id_count);
 EXPORT_SYMBOL(ip_send_check);
 EXPORT_SYMBOL(ip_fragment);
@@ -233,13 +236,16 @@ EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
 EXPORT_SYMBOL(ip_cmsg_recv);
 EXPORT_SYMBOL(__release_sock);
-EXPORT_SYMBOL(arp_find);
-EXPORT_SYMBOL(ip_rcv);
-EXPORT_SYMBOL(arp_rcv);
 
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
 
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
+
 #ifdef CONFIG_IPV6
 EXPORT_SYMBOL(ipv6_addr_type);
 EXPORT_SYMBOL(icmpv6_send);
@@ -273,7 +279,6 @@ EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
 EXPORT_SYMBOL(net_timer);
 /* UDP/TCP exported functions for TCPv6 */
-EXPORT_SYMBOL(sock_rspace);
 EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_connect);
 EXPORT_SYMBOL(udp_sendmsg);
@@ -370,8 +375,17 @@ EXPORT_SYMBOL(rtnl_rlockct);
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_unlock);
 
-EXPORT_SYMBOL(sock_wmalloc);
-EXPORT_SYMBOL(sock_rmalloc);
+                  
+/* Used by at least ipip.c.  */
+EXPORT_SYMBOL(ipv4_config);
+EXPORT_SYMBOL(dev_open);
+
+EXPORT_SYMBOL(ip_rcv);
+EXPORT_SYMBOL(arp_rcv);
+EXPORT_SYMBOL(arp_tbl);
+EXPORT_SYMBOL(arp_find);
+
+#endif  /* CONFIG_INET */
 
 #if    defined(CONFIG_ULTRA)   ||      defined(CONFIG_WD80x3)          || \
        defined(CONFIG_EL2)     ||      defined(CONFIG_NE2000)          || \
@@ -395,12 +409,6 @@ EXPORT_SYMBOL(unregister_trdev);
 EXPORT_SYMBOL(init_trdev);
 EXPORT_SYMBOL(tr_freedev);
 #endif
-                  
-/* Used by at least ipip.c.  */
-EXPORT_SYMBOL(ipv4_config);
-EXPORT_SYMBOL(dev_open);
-
-#endif  /* CONFIG_INET */
 
 /* Device callback registration */
 EXPORT_SYMBOL(register_netdevice_notifier);
@@ -445,10 +453,11 @@ EXPORT_SYMBOL(netdev_fc_xoff);
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
+EXPORT_SYMBOL(dev_mc_delete);
+EXPORT_SYMBOL(dev_mc_upload);
 EXPORT_SYMBOL(n_tty_ioctl);
 EXPORT_SYMBOL(tty_register_ldisc);
 EXPORT_SYMBOL(kill_fasync);
-EXPORT_SYMBOL(dev_mc_delete);
 
 EXPORT_SYMBOL(if_port_text);
 
index 0a907a8f199a2b7ba721d3a1291c29da06db7ee1..96d81dd5aada2e5d2028c2ce6b2743c0e3314f60 100644 (file)
@@ -117,7 +117,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth)
                                printk("RPC: rpcauth_gc_credcache looping!\n");
                                break;
                        }
-                       if (!cred->cr_count && time_after(jiffies, cred->cr_expire)) {
+                       if (!cred->cr_count && time_before(cred->cr_expire, jiffies)) {
                                *q = cred->cr_next;
                                cred->cr_next = free;
                                free = cred;
@@ -160,7 +160,7 @@ rpcauth_lookup_credcache(struct rpc_task *task)
 
        nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR);
 
-       if (time_after(jiffies, auth->au_nextgc))
+       if (time_before(auth->au_nextgc, jiffies))
                rpcauth_gc_credcache(auth);
 
        q = &auth->au_credcache[nr];
index 26f1efc072f88f439f379836a777b0b7cd0ea3f2..ff1dfd2dccbbca3aa744fa6773b7752c625da3aa 100644 (file)
@@ -79,13 +79,16 @@ static int                  swap_buffer_used = 0;
  * improve overall performance.
  * Everyone else gets appended to the queue to ensure proper FIFO behavior.
  */
-void
+int
 rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
 {
        if (task->tk_rpcwait) {
                if (task->tk_rpcwait != queue)
+               {
                        printk(KERN_WARNING "RPC: doubly enqueued task!\n");
-               return;
+                       return -EWOULDBLOCK;
+               }
+               return 0;
        }
        if (RPC_IS_SWAPPER(task))
                rpc_insert_list(&queue->task, task);
@@ -95,6 +98,8 @@ rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
 
        dprintk("RPC: %4d added to queue %p \"%s\"\n",
                                task->tk_pid, queue, rpc_qname(queue));
+
+       return 0;
 }
 
 /*
@@ -168,7 +173,13 @@ rpc_make_runnable(struct rpc_task *task)
                return;
        }
        if (RPC_IS_ASYNC(task)) {
-               rpc_add_wait_queue(&schedq, task);
+               int status;
+               status = rpc_add_wait_queue(&schedq, task);
+               if (status)
+               {
+                       printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+                       task->tk_status = status;
+               }
                wake_up(&rpciod_idle);
        } else {
                wake_up(&task->tk_wait);
@@ -202,6 +213,7 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
                        rpc_action action, rpc_action timer)
 {
        unsigned long   oldflags;
+       int status;
 
        dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid,
                                rpc_qname(q), jiffies);
@@ -211,11 +223,20 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
         */
        save_flags(oldflags); cli();
 
-       rpc_add_wait_queue(q, task);
-       task->tk_callback = action;
-       if (task->tk_timeout)
-               rpc_add_timer(task, timer);
-       task->tk_flags &= ~RPC_TASK_RUNNING;
+       status = rpc_add_wait_queue(q, task);
+       if (status)
+       {
+               printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+               task->tk_status = status;
+               task->tk_flags |= RPC_TASK_RUNNING;
+       }
+       else
+       {
+               task->tk_callback = action;
+               if (task->tk_timeout)
+                       rpc_add_timer(task, timer);
+               task->tk_flags &= ~RPC_TASK_RUNNING;
+       }
 
        restore_flags(oldflags);
        return;
index 1d1c0a95e1b245923b325e6a7b593ce5b7627192..2353c2e272e5433bf62ae215e5d3a754f2bac23b 100644 (file)
@@ -244,6 +244,12 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
        argp->buf += 5;
        argp->len -= 5;
 
+       /* Used by nfsd to only allow the NULL procedure for amd. */
+       if (rqstp->rq_auth && !rqstp->rq_client && proc) {
+               auth_stat = rpc_autherr_badcred;
+               goto err_bad_auth;
+       }
+
        /*
         * Decode auth data, and add verifier to reply buffer.
         * We do this before anything else in order to get a decent
index 827a8d42ee383d566871cef986e546d4269e3c67..6b1dc373da4d0f32ed7321643ccf2f973ae32b45 100644 (file)
@@ -543,7 +543,7 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
                pkt_cnt++;
                pkt_len += req->rq_slen + copied;
                pkt_rtt += jiffies - req->rq_xtime;
-               if (time_after(jiffies, nextstat)) {
+               if (time_before(nextstat, jiffies)) {
                        printk("RPC: %lu %ld cwnd\n", jiffies, xprt->cwnd);
                        printk("RPC: %ld %ld %ld %ld stat\n",
                                        jiffies, pkt_cnt, pkt_len, pkt_rtt);
@@ -936,6 +936,7 @@ xprt_transmit(struct rpc_task *task)
        struct rpc_timeout *timeo;
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
+       int status;
 
        /*DEBUG*/int ac_debug=xprt->snd_sent;
        
@@ -993,10 +994,18 @@ xprt_transmit(struct rpc_task *task)
         * the pending list now:
         */
        start_bh_atomic();
-       rpc_add_wait_queue(&xprt->pending, task);
-       task->tk_callback = NULL;
+       status = rpc_add_wait_queue(&xprt->pending, task);
+       if (!status)
+               task->tk_callback = NULL;
        end_bh_atomic();
 
+       if (status)
+       {
+               printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+               task->tk_status = status;
+               return;
+       }
+
        /* Continue transmitting the packet/record. We must be careful
         * to cope with writespace callbacks arriving _after_ we have
         * called xprt_sendmsg().
index 311dc7136315c17d5146c0d0ef2d1022fbcada54..18942bd201a555fd027d56e4aede922f9ea2161b 100644 (file)
@@ -32,6 +32,7 @@
 *                               kernel space (for big firmwares)
 *****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/stddef.h>      /* offsetof(), etc. */
 #include <linux/errno.h>       /* return codes */
 #include <linux/kernel.h>
@@ -87,10 +88,8 @@ static int delete_interface (wan_device_t* wandev, char* name, int forse);
  *     Global Data
  */
 
-#ifdef MODULE
 static char fullname[]         = "WAN Router";
 static char copyright[]                = "(c) 1995-1997 Sangoma Technologies Inc.";
-#endif
 static char modname[]          = ROUTER_NAME;  /* short module name */
 wan_device_t * router_devlist  = NULL; /* list of registered devices */
 static int devcnt              = 0;