diff -u --recursive --new-file v2.2.0-pre1/linux/CREDITS linux/CREDITS --- v2.2.0-pre1/linux/CREDITS Mon Dec 28 15:00:51 1998 +++ linux/CREDITS Tue Dec 29 17:31:48 1998 @@ -147,7 +147,8 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.2.0-pre1/linux/Documentation/Configure.help Mon Dec 28 15:00:51 1998 +++ linux/Documentation/Configure.help Wed Dec 30 14:50:00 1998 @@ -91,6 +91,9 @@ 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 @@ 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,14 +3779,19 @@ 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). diff -u --recursive --new-file v2.2.0-pre1/linux/Documentation/kernel-docs.txt linux/Documentation/kernel-docs.txt --- v2.2.0-pre1/linux/Documentation/kernel-docs.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/kernel-docs.txt Tue Dec 29 15:47:32 1998 @@ -0,0 +1,331 @@ + + + INDEX OF DOCUMENTATION FOR PEOPLE INTERESTED IN WRITING AND/OR UNDERSTANDING + THE LINUX KERNEL. + + Juan-Mariano de Goyeneche + + + /* + * 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. diff -u --recursive --new-file v2.2.0-pre1/linux/MAINTAINERS linux/MAINTAINERS --- v2.2.0-pre1/linux/MAINTAINERS Mon Dec 28 15:00:52 1998 +++ linux/MAINTAINERS Wed Dec 30 15:21:47 1998 @@ -181,12 +181,6 @@ 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 @@ 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 @@ -405,6 +399,13 @@ P: H. Peter Anvin 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 diff -u --recursive --new-file v2.2.0-pre1/linux/Makefile linux/Makefile --- v2.2.0-pre1/linux/Makefile Mon Dec 28 15:00:52 1998 +++ linux/Makefile Mon Dec 28 15:01:07 1998 @@ -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/) diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.2.0-pre1/linux/arch/alpha/config.in Tue Dec 22 14:16:53 1998 +++ linux/arch/alpha/config.in Wed Dec 30 21:22:00 1998 @@ -13,7 +13,6 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.2.0-pre1/linux/arch/alpha/kernel/alpha_ksyms.c Tue Dec 22 14:16:53 1998 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Dec 29 13:56:15 1998 @@ -86,6 +86,7 @@ EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(memcmp); diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.2.0-pre1/linux/arch/alpha/kernel/entry.S Fri Oct 23 22:01:19 1998 +++ linux/arch/alpha/kernel/entry.S Tue Dec 29 13:56:15 1998 @@ -689,7 +689,8 @@ .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__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.2.0-pre1/linux/arch/alpha/kernel/irq.c Mon Dec 28 15:00:52 1998 +++ linux/arch/alpha/kernel/irq.c Tue Dec 29 13:56:15 1998 @@ -11,6 +11,7 @@ */ #include +#include #include #include #include diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h --- v2.2.0-pre1/linux/arch/alpha/kernel/irq.h Mon Dec 28 15:00:52 1998 +++ linux/arch/alpha/kernel/irq.h Wed Dec 30 15:06:22 1998 @@ -8,6 +8,8 @@ * with the IRQ handling routines in irq.c. */ +#include + #define STANDARD_INIT_IRQ_PROLOG \ outb(0, DMA1_RESET_REG); \ outb(0, DMA2_RESET_REG); \ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.2.0-pre1/linux/arch/alpha/kernel/ptrace.c Fri Oct 23 22:01:19 1998 +++ linux/arch/alpha/kernel/ptrace.c Tue Dec 29 16:17:00 1998 @@ -541,7 +541,9 @@ /* 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 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.2.0-pre1/linux/arch/alpha/kernel/smp.c Fri Oct 23 22:01:19 1998 +++ linux/arch/alpha/kernel/smp.c Tue Dec 29 13:56:15 1998 @@ -30,7 +30,14 @@ #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 @@ 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 @@ 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 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" (¤t_set[cpuid]) - : "memory" /* paranoid */); - current->mm->mmap->vm_page_prot = PAGE_SHARED; - current->mm->mmap->vm_start = PAGE_OFFSET; - current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + while(!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 @@ 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 @@ 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; - - /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_PID); - idle = task[++cpucount]; + 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]; 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; + prev = i; + } + } + cpu_data[prev].next = first; - /* Ok, they are spinning and ready to go. */ - smp_processors_ready = 1; + /* Ok, they are spinning and ready to go. */ + smp_processors_ready = 1; } -__initfunc(void ioapic_pirq_setup(char *str, int *ints)) +static void __init +smp_setup_percpu_timer(void) { - /* this is prolly INTEL-specific */ -} - -static void 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 @@ 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; - - 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 + /* 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 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 @@ 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 @@ } 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); + + 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; - 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); - } +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 @@ * * 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 @@ } 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 @@ 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 @@ 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; -} + struct percpu_struct *cpu; -static int -local_flush_tlb_all(unsigned int this_cpu) -{ - tbia(); - 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_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; -} + mycpu = hard_smp_processor_id(); -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; + for (i = 0; i < NR_CPUS; i++) { + if (!(txrdy & (1L << i))) + continue; - 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; -} + DBGS(("secondary_console_message: " + "TXRDY contains CPU %d.\n", i)); -static int -wrapper_local_flush_tlb_page(unsigned int this_cpu) -{ -#if 0 - int cpu = smp_processor_id(); + 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 @@ { int this_cpu = smp_processor_id(); volatile int * pending_ipis = &ipi_bits[this_cpu]; - int ops; + unsigned long ops, which; - 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. */ + 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; + + 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 @@ 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 @@ #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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.2.0-pre1/linux/arch/i386/Makefile Tue Jul 21 00:15:30 1998 +++ linux/arch/i386/Makefile Wed Dec 30 14:17:25 1998 @@ -35,6 +35,10 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.2.0-pre1/linux/arch/i386/config.in Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/config.in Wed Dec 30 14:50:18 1998 @@ -14,8 +14,24 @@ 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 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.2.0-pre1/linux/arch/i386/defconfig Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/defconfig Wed Dec 30 14:44:48 1998 @@ -12,8 +12,11 @@ # # 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_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_CODA_FS is not set CONFIG_NFS_FS=y -CONFIG_NFSD=y # CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.2.0-pre1/linux/arch/i386/kernel/i386_ksyms.c Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/kernel/i386_ksyms.c Tue Dec 29 11:18:18 1998 @@ -58,6 +58,9 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.2.0-pre1/linux/arch/i386/kernel/irq.c Mon Dec 28 15:00:52 1998 +++ linux/arch/i386/kernel/irq.c Tue Dec 29 11:21:49 1998 @@ -900,7 +900,7 @@ /* * 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(); /* diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.2.0-pre1/linux/arch/i386/kernel/ptrace.c Fri Nov 27 13:09:22 1998 +++ linux/arch/i386/kernel/ptrace.c Tue Dec 29 15:59:32 1998 @@ -420,7 +420,9 @@ 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 @@ /* 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.2.0-pre1/linux/arch/i386/kernel/setup.c Sun Nov 8 14:02:42 1998 +++ linux/arch/i386/kernel/setup.c Tue Dec 29 14:20:42 1998 @@ -597,7 +597,7 @@ for(n=0; n cpucount+1)) { do_boot_cpu(i); @@ -1126,9 +1215,9 @@ * 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 @@ if (cpucount==0) { printk(KERN_ERR "Error: only one processor found.\n"); - cpu_present_map=(1<>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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ */ #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 @@ 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 @@ 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 @@ * 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 @@ 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... */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.2.0-pre1/linux/arch/ppc/kernel/idle.c Thu Nov 19 09:56:27 1998 +++ linux/arch/ppc/kernel/idle.c Wed Dec 30 10:55:07 1998 @@ -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 @@ 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__ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.2.0-pre1/linux/arch/ppc/kernel/irq.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/irq.c Wed Dec 30 10:55:07 1998 @@ -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 @@ } -#define MAXCOUNT 100000000 static inline void wait_on_irq(int cpu) { int count = MAXCOUNT; @@ -510,7 +509,7 @@ void synchronize_bh(void) { if (atomic_read(&global_bh_count) && !in_interrupt()) - wait_on_bh(); + wait_on_bh(); } @@ -532,6 +531,8 @@ 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 @@ /* 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 @@ #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,15 +665,39 @@ #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; } /* could be here due to a do_fake_interrupt call but we don't 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__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.2.0-pre1/linux/arch/ppc/kernel/misc.S Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/misc.S Wed Dec 30 10:55:07 1998 @@ -610,16 +610,6 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.2.0-pre1/linux/arch/ppc/kernel/ppc_ksyms.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/ppc_ksyms.c Wed Dec 30 10:55:07 1998 @@ -25,6 +25,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ #include @@ -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(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); diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.2.0-pre1/linux/arch/ppc/kernel/process.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/process.c Wed Dec 30 10:55:07 1998 @@ -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 @@ 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__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.2.0-pre1/linux/arch/ppc/kernel/ptrace.c Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/kernel/ptrace.c Tue Dec 29 16:32:36 1998 @@ -362,7 +362,9 @@ 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 @@ /* 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.2.0-pre1/linux/arch/ppc/kernel/smp.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/smp.c Wed Dec 30 10:55:07 1998 @@ -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 @@ 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_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 @@ 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 @@ 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 @@ 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 *)¤t_set[1]); + /* XXX ??? */ + for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32) + asm volatile("dcbf 0,%0" : : "r" (a) : "memory"); + asm volatile("sync"); + + /*dcbf((void *)¤t_set[1]);*/ /* setup entry point of secondary processor */ *(volatile unsigned long *)(0xf2800000) = (unsigned long)__secondary_start-KERNELBASE; @@ -238,7 +259,7 @@ 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 @@ while(!smp_commenced) barrier(); __sti(); + printk("SMP %d: smp_callin done\n", current->processor); } void __init smp_setup(char *str, int *ints) diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.2.0-pre1/linux/arch/ppc/kernel/time.c Tue Dec 22 14:16:54 1998 +++ linux/arch/ppc/kernel/time.c Wed Dec 30 10:55:07 1998 @@ -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 @@ 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 @@ 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); } diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c --- v2.2.0-pre1/linux/arch/ppc/lib/locks.c Thu Nov 19 09:56:27 1998 +++ linux/arch/ppc/lib/locks.c Wed Dec 30 10:55:07 1998 @@ -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 @@ 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. */ } /* diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig --- v2.2.0-pre1/linux/arch/ppc/pmac_defconfig Mon Dec 28 15:00:52 1998 +++ linux/arch/ppc/pmac_defconfig Wed Dec 30 10:55:07 1998 @@ -14,8 +14,8 @@ # 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 @@ # 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_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_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_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_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_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_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_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 @@ # 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_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 # diff -u --recursive --new-file v2.2.0-pre1/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds --- v2.2.0-pre1/linux/arch/ppc/vmlinux.lds Fri May 8 23:14:45 1998 +++ linux/arch/ppc/vmlinux.lds Wed Dec 30 10:55:07 1998 @@ -64,6 +64,9 @@ __ex_table : { *(__ex_table) } __stop___ex_table = .; + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } diff -u --recursive --new-file v2.2.0-pre1/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.2.0-pre1/linux/arch/sparc/kernel/ptrace.c Thu May 7 22:51:47 1998 +++ linux/arch/sparc/kernel/ptrace.c Tue Dec 29 16:35:08 1998 @@ -592,7 +592,9 @@ 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 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.2.0-pre1/linux/drivers/block/Config.in Thu Nov 19 09:56:28 1998 +++ linux/drivers/block/Config.in Tue Dec 29 11:21:49 1998 @@ -69,7 +69,7 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.2.0-pre1/linux/drivers/block/acsi.c Thu Nov 12 16:21:18 1998 +++ linux/drivers/block/acsi.c Tue Dec 29 11:23:59 1998 @@ -425,7 +425,7 @@ { 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 @@ { 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 { diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.2.0-pre1/linux/drivers/block/acsi_slm.c Wed Aug 26 11:37:34 1998 +++ linux/drivers/block/acsi_slm.c Tue Dec 29 11:23:59 1998 @@ -101,17 +101,8 @@ 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 }; diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v2.2.0-pre1/linux/drivers/block/ataflop.c Wed Aug 26 11:37:35 1998 +++ linux/drivers/block/ataflop.c Tue Dec 29 11:23:59 1998 @@ -1838,7 +1838,7 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.2.0-pre1/linux/drivers/block/ide-disk.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/ide-disk.c Wed Dec 30 13:36:02 1998 @@ -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 * and Gadi Oxman + * and Andre Hedrick * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. * @@ -19,10 +20,13 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } /* 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 @@ } } 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.2.0-pre1/linux/drivers/block/ide-dma.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/ide-dma.c Tue Dec 29 11:14:57 1998 @@ -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 #include #include @@ -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 @@ * 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 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.2.0-pre1/linux/drivers/block/ide-tape.c Fri Oct 9 13:27:07 1998 +++ linux/drivers/block/ide-tape.c Wed Dec 30 14:51:31 1998 @@ -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 * @@ -212,6 +212,8 @@ * 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: @@ -479,6 +481,11 @@ #define IDETAPE_FIFO_THRESHOLD 2 /* + * Some tape drives require a long irq timeout + */ +#define IDETAPE_WAIT_CMD 60 + +/* * DSC timings. */ #define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */ @@ -1432,8 +1439,7 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ * 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 @@ } #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 @@ */ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.2.0-pre1/linux/drivers/block/ide.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/ide.c Wed Dec 30 15:48:22 1998 @@ -2275,6 +2275,12 @@ * 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 @@ 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 @@ 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 @@ 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 (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) + 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 @@ } 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 @@ (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 */ } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.2.0-pre1/linux/drivers/block/ide.h Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/ide.h Wed Dec 30 22:34:26 1998 @@ -438,6 +438,8 @@ *start = page + off; \ return len; \ } +#else +#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0; #endif /* diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- v2.2.0-pre1/linux/drivers/block/pdc4030.c Thu May 7 22:51:48 1998 +++ linux/drivers/block/pdc4030.c Tue Dec 29 11:24:57 1998 @@ -92,13 +92,13 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.2.0-pre1/linux/drivers/char/console.c Sun Nov 8 14:02:53 1998 +++ linux/drivers/char/console.c Tue Dec 29 14:28:37 1998 @@ -1029,7 +1029,7 @@ */ translate = set_translate(charset == 0 ? G0_charset - : G1_charset); + : G1_charset,currcons); disp_ctrl = 0; toggle_meta = 0; break; @@ -1037,7 +1037,7 @@ * 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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: diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.2.0-pre1/linux/drivers/char/consolemap.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/consolemap.c Tue Dec 29 14:28:37 1998 @@ -7,6 +7,8 @@ * aeb, 950210 * * Support for multiple unimaps by Jakub Jelinek , July 1998 + * + * Fix bug in inverse translation. Stanislav Voronyi , Dec 1998 */ #include @@ -167,7 +169,7 @@ #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 @@ } } -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 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) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.2.0-pre1/linux/drivers/char/cyclades.c Thu Nov 19 09:56:28 1998 +++ linux/drivers/char/cyclades.c Wed Dec 30 21:20:31 1998 @@ -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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.2.0-pre1/linux/drivers/char/epca.c Sun Nov 8 14:02:54 1998 +++ linux/drivers/char/epca.c Tue Dec 29 11:24:57 1998 @@ -286,7 +286,8 @@ #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 @@ #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) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/ftape/RELEASE-NOTES linux/drivers/char/ftape/RELEASE-NOTES --- v2.2.0-pre1/linux/drivers/char/ftape/RELEASE-NOTES Tue Nov 25 14:45:26 1997 +++ linux/drivers/char/ftape/RELEASE-NOTES Tue Dec 29 11:27:38 1998 @@ -423,9 +423,7 @@ 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. diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/ftape/lowlevel/fdc-io.c linux/drivers/char/ftape/lowlevel/fdc-io.c --- v2.2.0-pre1/linux/drivers/char/ftape/lowlevel/fdc-io.c Thu Nov 12 16:21:19 1998 +++ linux/drivers/char/ftape/lowlevel/fdc-io.c Tue Dec 29 11:27:38 1998 @@ -1348,21 +1348,12 @@ 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 @@ "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 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/hfmodem/Config.in linux/drivers/char/hfmodem/Config.in --- v2.2.0-pre1/linux/drivers/char/hfmodem/Config.in Wed Feb 4 11:36:00 1998 +++ linux/drivers/char/hfmodem/Config.in Tue Dec 29 11:28:49 1998 @@ -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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.2.0-pre1/linux/drivers/char/istallion.c Sun Nov 8 14:02:54 1998 +++ linux/drivers/char/istallion.c Tue Dec 29 11:29:54 1998 @@ -2311,7 +2311,7 @@ if (signal_pending(current)) break; stli_delay(2); - if (jiffies >= tend) + if (time_after_eq(jiffies, tend)) break; } } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.2.0-pre1/linux/drivers/char/riscom8.c Sun Nov 8 14:02:55 1998 +++ linux/drivers/char/riscom8.c Tue Dec 29 11:29:54 1998 @@ -228,7 +228,7 @@ { 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 @@ 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; } } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.2.0-pre1/linux/drivers/char/specialix.c Sun Nov 8 14:02:56 1998 +++ linux/drivers/char/specialix.c Tue Dec 29 11:29:54 1998 @@ -353,7 +353,7 @@ { unsigned long i; - for (i = jiffies + delay; i > jiffies; ) ; + for (i = jiffies + delay; time_after(i, jiffies); ) ; } @@ -1073,7 +1073,7 @@ /* 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 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.2.0-pre1/linux/drivers/char/stallion.c Sun Nov 8 14:02:56 1998 +++ linux/drivers/char/stallion.c Tue Dec 29 11:29:54 1998 @@ -1697,7 +1697,7 @@ if (signal_pending(current)) break; stl_delay(2); - if (jiffies >= tend) + if (time_after_eq(jiffies, tend)) break; } } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.2.0-pre1/linux/drivers/isdn/Config.in Wed Apr 1 20:11:49 1998 +++ linux/drivers/isdn/Config.in Tue Dec 29 11:29:54 1998 @@ -38,7 +38,9 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.2.0-pre1/linux/drivers/net/Makefile Tue Dec 22 14:16:55 1998 +++ linux/drivers/net/Makefile Tue Dec 29 11:29:54 1998 @@ -1035,13 +1035,6 @@ # # 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.2.0-pre1/linux/drivers/net/bmac.c Thu Nov 19 09:56:28 1998 +++ linux/drivers/net/bmac.c Wed Dec 30 10:55:07 1998 @@ -5,6 +5,7 @@ * Copyright (C) 1998 Randy Gobbel. */ #include +#include #include #include #include @@ -59,7 +60,6 @@ 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 @@ 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_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 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ } } - 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 @@ 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 @@ } } 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; itx_bufs[i] != NULL) { @@ -1379,7 +1372,6 @@ bp->tx_bufs[i] = NULL; } } - bp->tx_allocated = 0; bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); @@ -1539,3 +1531,32 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.2.0-pre1/linux/drivers/net/de4x5.c Sun Nov 8 14:03:00 1998 +++ linux/drivers/net/de4x5.c Wed Dec 30 15:09:18 1998 @@ -415,11 +415,12 @@ 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 #include @@ -443,6 +444,7 @@ #include #include #include +#include #include #include @@ -508,11 +510,11 @@ ** 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 @@ 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 @@ 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 @@ ** 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 @@ 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 @@ ** 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 @@ } 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 @@ 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 @@ 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 @@ lp->interrupt = UNMASK_INTERRUPTS; ENABLE_IRQs; + spin_unlock(&lp->lock); return; } @@ -2069,7 +2076,9 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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; idev_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; idev_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 @@ 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 @@ 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 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.2.0-pre1/linux/drivers/net/de4x5.h Thu Jul 16 18:09:25 1998 +++ linux/drivers/net/de4x5.h Wed Dec 30 15:09:18 1998 @@ -121,6 +121,7 @@ #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)) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.2.0-pre1/linux/drivers/net/dgrs.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/net/dgrs.c Tue Dec 29 11:32:06 1998 @@ -1098,7 +1098,7 @@ */ 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 @@ 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) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.2.0-pre1/linux/drivers/net/eepro.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/net/eepro.c Tue Dec 29 11:30:56 1998 @@ -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: @@ -23,6 +23,33 @@ 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 @@ -48,37 +75,37 @@ 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 /* 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 @@ #include #include #include +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 +#include +#endif #include -#include -#include #include #include #include +/* need to remove these asap */ +/* 2.1.xx compatibility macros... */ +/* */ + + +#include + +/* For linux 2.1.xx */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + +#include +#include + +#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 @@ /* 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) + +/* 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_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 @@ 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 @@ #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 @@ #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 @@ #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 @@ #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 @@ 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 @@ } #endif +void printEEPROMInfo(short ioaddr) +{ + unsigned short Word; + int i,j; + + for (i=0, j=ee_Checksum; i>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 @@ 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 (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE)) + dev->if_port = BNC; + else dev->if_port = TPE; + + + /* ............... */ - 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 (net_debug>3) +// printk("id: %x\n", id); - if (dev->irq < 2 && eepro) { + + 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<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 @@ 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 @@ */ 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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 @@ 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 @@ 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; + /* 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); - 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; - hardware_send_packet(dev, buf, length); - dev->trans_start = jiffies; + /* 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; + +#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 @@ /* 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ /* 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } /* 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); + /* 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); + /* 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 @@ 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 @@ { 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 }; - -static int io = 0x200; -static int irq = 0; -static int mem = (RCV_RAM/1024); /* Size of the rx buffer in KB */ +#define MAX_EEPRO 8 +static char devicename[MAX_EEPRO][9]; +static struct device dev_eepro[MAX_EEPRO]; + +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 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; + 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(&dev_eepro) != 0) - return -EIO; - return 0; + 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; ipriv,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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.2.0-pre1/linux/drivers/net/hamradio/Config.in Tue Jun 9 11:57:29 1998 +++ linux/drivers/net/hamradio/Config.in Tue Dec 29 11:30:56 1998 @@ -13,8 +13,8 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c --- v2.2.0-pre1/linux/drivers/net/hamradio/hdlcdrv.c Fri Nov 27 13:09:24 1998 +++ linux/drivers/net/hamradio/hdlcdrv.c Tue Dec 29 11:30:56 1998 @@ -41,6 +41,7 @@ /*****************************************************************************/ #include +#include #include #include #include @@ -58,10 +59,8 @@ #include #include #include -#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* prototypes for ax25_encapsulate and ax25_rebuild_header */ #include -#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ /* make genksyms happy */ #include diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.2.0-pre1/linux/drivers/net/hp100.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/hp100.c Tue Dec 29 11:32:06 1998 @@ -2796,9 +2796,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ #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); diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.2.0-pre1/linux/drivers/net/plip.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/plip.c Tue Dec 29 11:51:50 1998 @@ -21,6 +21,10 @@ * - 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 @@ #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 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ spin_unlock_irq(&nl->lock); if (--cx == 0) { outb(0x00, data_addr); - return TIMEOUT; + return HS_TIMEOUT; } } @@ -760,7 +784,7 @@ 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 @@ 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 @@ dev->tbusy = 1; dev->start = 0; - disable_irq(dev->irq); + DISABLE(dev->irq); synchronize_irq(); #ifdef NOTDEF diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.2.0-pre1/linux/drivers/net/sdla.c Sun Jun 7 11:16:32 1998 +++ linux/drivers/net/sdla.c Tue Dec 29 11:32:06 1998 @@ -248,7 +248,7 @@ 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 @@ 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 @@ waiting = 1; len = 0; - while (waiting && (jiffies <= jiffs)) + while (waiting && time_before_eq(jiffies, jiffs)) { if (waiting++ % 3) { diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.2.0-pre1/linux/drivers/net/seeq8005.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/net/seeq8005.c Tue Dec 29 11:32:06 1998 @@ -247,10 +247,10 @@ 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 @@ /* 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 @@ 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) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.2.0-pre1/linux/drivers/net/sktr.c Sun Nov 8 14:03:00 1998 +++ linux/drivers/net/sktr.c Tue Dec 29 11:32:06 1998 @@ -1020,7 +1020,7 @@ 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 @@ { 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.2.0-pre1/linux/drivers/net/tulip.c Sun Jun 7 11:16:33 1998 +++ linux/drivers/net/tulip.c Wed Dec 30 22:00:40 1998 @@ -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 @@ -17,14 +17,27 @@ 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 @@ 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 -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -82,6 +75,8 @@ #include #include #include +#include + #include /* Processor type for cache alignment. */ #include #include @@ -106,28 +101,13 @@ #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 #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 @@ #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 #endif /* This my implementation of shared IRQs, now only used for 1.2.13. */ @@ -167,7 +147,7 @@ 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 @@ #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}; +enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, + LC82C168, MX98713, MX98715, MX98725}; -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 }; +/* 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 @@ /* 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 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 *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 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 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 -#include - -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 -#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 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; + if (! pcibios_present()) + return -ENODEV; #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); + 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; + if (tulip_debug > 2) + printk(KERN_DEBUG "Found %s at I/O %#x.\n", + tulip_tbl[chip_idx].chip_name, pci_ioaddr); - 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_tbl[chip_idx].io_size)) + continue; - if (check_region(pci_ioaddr, TULIP_TOTAL_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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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 @@ 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 @@ {"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 @@ {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 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 @@ } 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 @@ 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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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; - clear_bit(lp->fc_bit, &netdev_fc_xoff); - if (dev->start) - outl(lp->csr6 | 0x2002, dev->base_addr + CSR6); + 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; + } + + /* 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 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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,150 +1629,128 @@ break; } break; - case LC82C168: { - int phy_reg = inl(ioaddr + 0xB8); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n", - dev->name, phy_reg, inl(ioaddr + CSR5)); - if (phy_reg & 0x04000000) { /* Remote link fault */ - outl(0x0201F078, ioaddr + 0xB8); - next_tick = (24*HZ)/10; - } else - next_tick = 10*HZ; - if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */ + 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: %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) { - dev->if_port = 3; - } else - dev->if_port = 0; - next_tick = (24*HZ)/10; + 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); - dev->trans_start = jiffies; + next_tick = (24*HZ)/10; + break; } - 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; - } 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"); + 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; } - 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); @@ -1618,16 +1758,237 @@ } } +/* 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, csr5); + + if (phy_reg & 0x04000000) { /* Remote link fault */ + /*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 (tp->medialock) { + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + 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; + } + } + 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 - lp->stats.collisions += (status >> 3) & 15; - lp->stats.tx_packets++; +#if LINUX_VERSION_CODE > 0x20127 + tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff; +#endif + 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 @@ 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 } @@ -2242,56 +2429,48 @@ #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 @@ #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 @@ 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 @@ 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 @@ } #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 @@ } 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 @@ 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; @@ -2485,15 +2737,69 @@ } } +#ifdef CARDBUS + +#include + +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 */ + + #ifdef MODULE #if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Donald Becker "); 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 @@ 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 @@ { 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 @@ /* * 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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c --- v2.2.0-pre1/linux/drivers/nubus/nubus.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/nubus/nubus.c Tue Dec 29 11:32:06 1998 @@ -632,7 +632,9 @@ nubus_init_via(); printk("Scanning nubus slots.\n"); nubus_probe_bus(); +#ifdef CONFIG_PROC_FS proc_register(&proc_root, &proc_nubus); +#endif } diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.2.0-pre1/linux/drivers/pci/oldproc.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/pci/oldproc.c Tue Dec 29 14:01:38 1998 @@ -338,6 +338,7 @@ 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 @@ 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 @@ 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 @@ 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"; diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.2.0-pre1/linux/drivers/scsi/Config.in Tue Dec 22 14:16:56 1998 +++ linux/drivers/scsi/Config.in Tue Dec 29 13:54:32 1998 @@ -50,7 +50,7 @@ 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 '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 diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.2.0-pre1/linux/drivers/scsi/advansys.c Mon Dec 28 15:00:52 1998 +++ linux/drivers/scsi/advansys.c Tue Dec 29 11:35:48 1998 @@ -3941,6 +3941,8 @@ 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 @@ 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() * diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.2.0-pre1/linux/drivers/scsi/eata_dma.c Tue Apr 14 14:29:22 1998 +++ linux/drivers/scsi/eata_dma.c Tue Dec 29 11:35:48 1998 @@ -962,7 +962,7 @@ 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 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c --- v2.2.0-pre1/linux/drivers/scsi/eata_dma_proc.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/eata_dma_proc.c Tue Dec 29 11:35:48 1998 @@ -1,3 +1,4 @@ +#include void swap_statistics(u8 *p) { @@ -68,6 +69,8 @@ int hostno, int inout) { +#ifdef CONFIG_PROC_FS + Scsi_Device *scd, SDev; struct Scsi_Host *HBA_ptr; Scsi_Cmnd scmd; @@ -466,6 +469,9 @@ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); return (len); +#else /* CONFIG_PROC_FS */ + return 0; +#endif } /* diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v2.2.0-pre1/linux/drivers/scsi/eata_pio.c Wed May 20 19:10:39 1998 +++ linux/drivers/scsi/eata_pio.c Tue Dec 29 11:35:48 1998 @@ -500,7 +500,7 @@ 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)); diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/eata_pio_proc.c linux/drivers/scsi/eata_pio_proc.c --- v2.2.0-pre1/linux/drivers/scsi/eata_pio_proc.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/eata_pio_proc.c Tue Dec 29 11:35:48 1998 @@ -1,3 +1,5 @@ +#include + /* * eata_set_info * buffer : pointer to the data that has been written to the hostfile @@ -24,7 +26,7 @@ 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 @@ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); return (len); +#else + return 0; +#endif } /* diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.2.0-pre1/linux/drivers/scsi/fdomain.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/fdomain.c Tue Dec 29 11:44:53 1998 @@ -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 @@ -32,13 +30,34 @@ 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=,[,] + + 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: @@ -108,7 +127,8 @@ 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: @@ -207,6 +227,9 @@ patches. New PCI detection code written by Martin Mares + + Insmod parameter code based on patches from Daniel Graham + . All of the alpha testers deserve much thanks. @@ -282,7 +305,7 @@ 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 @@ 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 @@ if (!shpnt) return; /* This won't ever happen */ if (bios_major < 0 && bios_minor < 0) { - printk( "scsi%d : No BIOS; using scsi id %d\n", + printk( "scsi%d: No BIOS; using scsi id %d\n", shpnt->host_no, shpnt->this_id ); } else { - printk( "scsi%d : BIOS version ", shpnt->host_no ); + printk( "scsi%d: BIOS version ", shpnt->host_no ); if (bios_major >= 0) printk( "%d.", bios_major ); else printk( "?." ); @@ -523,7 +555,7 @@ 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 : %s chip at 0x%x irq ", + printk( "scsi%d: %s chip at 0x%x irq ", shpnt->host_no, chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" @@ -541,8 +573,9 @@ void fdomain_setup( char *str, int *ints ) { if (setup_called++ || ints[0] < 2 || ints[0] > 3) { - printk( "fdomain: usage: fdomain=,[,]\n" ); - printk( "fdomain: bad LILO parameters?\n" ); + printk( "scsi: " + " Usage: fdomain=,[,]\n" ); + printk( "scsi: Bad LILO/INSMOD parameters?\n" ); } port_base = ints[0] >= 1 ? ints[1] : 0; @@ -591,8 +624,6 @@ 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 @@ 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 @@ int options = inb( base + Configuration1 ); #if DEBUG_DETECT - printk( " Options = %x\n", options ); + printk( "scsi: Options = %x\n", options ); #endif /* Check for board with lowest bios_base -- @@ -673,10 +693,31 @@ 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_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 @@ 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 @@ /* 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: INFO: use lspci -v to see list of PCI devices\n" ); + printk( "scsi: 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: 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 @@ 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 @@ *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: 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: " + " 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 @@ 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: 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: Cannot locate chip at port base 0x%x\n", port_base ); - printk( "fdomain: bad LILO parameters?\n" ); + printk( "scsi: 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: Detection failed (no card)\n" ); + return 0; + } } } @@ -911,13 +942,10 @@ fdomain_16x0_reset( NULL, 0 ); if (fdomain_test_loopback()) { -#if DEBUG_DETECT - printk( "fdomain: LOOPBACK TEST FAILED, FAILING DETECT!\n" ); -#endif + printk( "scsi: 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: Bad LILO/INSMOD parameters?\n" ); } return 0; } @@ -946,7 +974,9 @@ /* Log IRQ with kernel */ if (!interrupt_level) { - panic( "fdomain: *NO* interrupt level selected!\n" ); + printk( "scsi: " + " Card Detected, but driver not loaded (no IRQ)\n" ); + return 0; } else { /* Register the IRQ with the kernel */ @@ -955,18 +985,21 @@ 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: 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: 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: 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: Detected, but driver not loaded (IRQ)\n" ); + return 0; } } @@ -987,7 +1020,7 @@ SCinit.use_sg = 0; SCinit.lun = 0; - printk( "fdomain: detection routine scanning for devices:\n" ); + printk( "scsi: 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 @@ 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 @@ printk( "Arbitration failed, status = %x\n", status ); #endif #if ERRORS_ONLY - printk( "fdomain: Arbitration failed, status = %x\n", status ); + printk( "scsi: Arbitration failed, status = %x\n", status ); #endif return 1; } @@ -1158,7 +1191,7 @@ if (!flag) /* Skip first failure for all chips. */ ++flag; else - printk( "fdomain: Selection failed\n" ); + printk( "scsi: Selection failed\n" ); } #endif return 1; @@ -1173,9 +1206,9 @@ 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: current_SC->scsi_done() == NULL" ); } else { - panic( "fdomain: my_done() called outside of command\n" ); + panic( "scsi: my_done() called outside of command\n" ); } #if DEBUG_RACE in_interrupt_flag = 0; @@ -1211,7 +1244,7 @@ /* 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: Interrupt after abort, ignoring\n" ); #endif /* return; */ @@ -1311,7 +1344,7 @@ 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: target = %d, command = %x, status = %x\n", current_SC->target, current_SC->cmnd[0], current_SC->SCp.Status ); @@ -1329,7 +1362,8 @@ 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: message = %x\n", + current_SC->SCp.Message ); } #endif break; @@ -1590,8 +1624,8 @@ || code == 0x24 || !code))) - printk( "fdomain: REQUEST SENSE " - "Key = %x, Code = %x, Qualifier = %x\n", + printk( "scsi: REQUEST SENSE" + " Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier ); } } @@ -1624,7 +1658,7 @@ 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_16x0_queue() NOT REENTRANT!\n" ); } #if EVERY_ACCESS printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", @@ -1704,7 +1738,8 @@ unsigned int isr; if (!SCpnt || !SCpnt->host) { - printk( "fdomain: cannot provide detailed information\n" ); + printk( "scsi: Cannot provide detailed information\n" ); + return; } printk( "%s\n", fdomain_16x0_info( SCpnt->host ) ); @@ -1770,7 +1805,7 @@ { unsigned long flags; #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT - printk( "fdomain: abort " ); + printk( "scsi: abort " ); #endif save_flags( flags ); @@ -1808,7 +1843,7 @@ #endif #if ERRORS_ONLY - if (SCpnt) printk( "fdomain: SCSI Bus Reset\n" ); + if (SCpnt) printk( "scsi: SCSI Bus Reset\n" ); #endif #if DEBUG_RESET @@ -1893,7 +1928,7 @@ */ if (MAJOR(dev) != SCSI_DISK0_MAJOR) { - printk("fdomain_16x0_biosparam: too many disks"); + printk("scsi: fdomain_16x0_biosparam: too many disks"); return 0; } drive = MINOR(dev) >> 4; diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.2.0-pre1/linux/drivers/scsi/ibmmca.c Fri Nov 27 13:09:24 1998 +++ linux/drivers/scsi/ibmmca.c Tue Dec 29 11:40:35 1998 @@ -1567,7 +1567,7 @@ /* 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 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.2.0-pre1/linux/drivers/scsi/mesh.c Thu Nov 19 09:56:28 1998 +++ linux/drivers/scsi/mesh.c Wed Dec 30 10:55:07 1998 @@ -1346,11 +1346,11 @@ 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 @@ 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 @@ cmd->host_scribble = NULL; queue_task(&ms->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); +#else + (*cmd->scsi_done)(cmd); +#endif } /* diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.2.0-pre1/linux/drivers/scsi/scsi.h Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/scsi.h Wed Dec 30 22:35:09 1998 @@ -319,7 +319,7 @@ #define ASKED_FOR_SENSE 0x20 -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(CONFIG_APUS) #include #define CONTIGUOUS_BUFFERS(X,Y) \ (virt_to_phys((X)->b_data+(X)->b_size-1)+1==virt_to_phys((Y)->b_data)) diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v2.2.0-pre1/linux/drivers/scsi/seagate.c Sat Sep 5 16:46:41 1998 +++ linux/drivers/scsi/seagate.c Tue Dec 29 11:40:35 1998 @@ -379,8 +379,8 @@ { 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 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.2.0-pre1/linux/drivers/scsi/wd7000.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/wd7000.c Tue Dec 29 11:40:35 1998 @@ -791,7 +791,7 @@ 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 @@ { register unsigned long time = jiffies + how_long; - while (jiffies < time); + while (time_before(jiffies, time)); } @@ -868,7 +868,7 @@ 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 @@ */ 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) { diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.2.0-pre1/linux/drivers/sound/dmasound.c Tue Dec 22 14:16:56 1998 +++ linux/drivers/sound/dmasound.c Wed Dec 30 10:55:07 1998 @@ -2084,8 +2084,7 @@ int utotal, ftotal; frameLeft >>= 2; - if (stereo) - userCount >>= 1; + userCount >>= (stereo? 2: 1); ftotal = frameLeft; utotal = userCount; while (frameLeft) { @@ -2130,8 +2129,7 @@ int utotal, ftotal; frameLeft >>= 2; - if (stereo) - userCount >>= 1; + userCount >>= (stereo? 2: 1); ftotal = frameLeft; utotal = userCount; while (frameLeft) { diff -u --recursive --new-file v2.2.0-pre1/linux/fs/Config.in linux/fs/Config.in --- v2.2.0-pre1/linux/fs/Config.in Mon Dec 28 15:00:52 1998 +++ linux/fs/Config.in Tue Dec 29 11:42:21 1998 @@ -56,7 +56,9 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/fs/buffer.c linux/fs/buffer.c --- v2.2.0-pre1/linux/fs/buffer.c Mon Dec 28 15:00:52 1998 +++ linux/fs/buffer.c Wed Dec 30 22:26:46 1998 @@ -424,10 +424,14 @@ 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 @@ 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; + } } } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/dcache.c linux/fs/dcache.c --- v2.2.0-pre1/linux/fs/dcache.c Mon Dec 28 15:00:52 1998 +++ linux/fs/dcache.c Wed Dec 30 17:13:57 1998 @@ -475,7 +475,7 @@ * too much. * * Priority: - * 0 - very urgent: schrink everything + * 0 - very urgent: shrink everything * ... * 6 - base-level: try to shrink a bit. */ diff -u --recursive --new-file v2.2.0-pre1/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.2.0-pre1/linux/fs/fat/inode.c Mon Dec 28 15:00:52 1998 +++ linux/fs/fat/inode.c Tue Dec 29 14:07:40 1998 @@ -366,7 +366,9 @@ 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)); diff -u --recursive --new-file v2.2.0-pre1/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.2.0-pre1/linux/fs/isofs/inode.c Mon Sep 28 10:51:34 1998 +++ linux/fs/isofs/inode.c Tue Dec 29 11:40:35 1998 @@ -409,11 +409,13 @@ 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 @@ 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 @@ } } #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 @@ } /* 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'; diff -u --recursive --new-file v2.2.0-pre1/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.2.0-pre1/linux/fs/lockd/clntproc.c Sun Nov 8 14:03:06 1998 +++ linux/fs/lockd/clntproc.c Tue Dec 29 11:42:25 1998 @@ -125,7 +125,8 @@ /* 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(¤t->blocked); /* Mask all signals */ recalc_sigpending(current); @@ -144,7 +145,8 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/fs/lockd/host.c linux/fs/lockd/host.c --- v2.2.0-pre1/linux/fs/lockd/host.c Mon Dec 28 15:00:52 1998 +++ linux/fs/lockd/host.c Tue Dec 29 11:42:25 1998 @@ -92,7 +92,7 @@ /* 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 @@ /* 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 @@ 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 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.2.0-pre1/linux/fs/lockd/svc.c Mon Dec 28 15:00:52 1998 +++ linux/fs/lockd/svc.c Tue Dec 29 11:42:25 1998 @@ -136,7 +136,7 @@ */ 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; /* diff -u --recursive --new-file v2.2.0-pre1/linux/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c --- v2.2.0-pre1/linux/fs/lockd/svcproc.c Tue Mar 10 10:03:34 1998 +++ linux/fs/lockd/svcproc.c Tue Dec 29 11:42:25 1998 @@ -499,15 +499,22 @@ /* * 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 @@ 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), diff -u --recursive --new-file v2.2.0-pre1/linux/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c --- v2.2.0-pre1/linux/fs/lockd/svcsubs.c Sun Jul 26 11:57:18 1998 +++ linux/fs/lockd/svcsubs.c Tue Dec 29 11:42:25 1998 @@ -52,6 +52,8 @@ 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 @@ /* 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; diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/Makefile linux/fs/nfsd/Makefile --- v2.2.0-pre1/linux/fs/nfsd/Makefile Wed Jun 24 22:54:09 1998 +++ linux/fs/nfsd/Makefile Tue Dec 29 11:42:25 1998 @@ -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) diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/auth.c linux/fs/nfsd/auth.c --- v2.2.0-pre1/linux/fs/nfsd/auth.c Sun Nov 8 14:03:07 1998 +++ linux/fs/nfsd/auth.c Tue Dec 29 11:42:25 1998 @@ -50,11 +50,10 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.2.0-pre1/linux/fs/nfsd/export.c Sun Nov 8 14:03:07 1998 +++ linux/fs/nfsd/export.c Tue Dec 29 11:42:25 1998 @@ -615,6 +615,112 @@ 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 + 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 diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/nfscache.c linux/fs/nfsd/nfscache.c --- v2.2.0-pre1/linux/fs/nfsd/nfscache.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfsd/nfscache.c Tue Dec 29 11:42:25 1998 @@ -314,8 +314,8 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- v2.2.0-pre1/linux/fs/nfsd/nfsctl.c Fri Oct 23 22:01:22 1998 +++ linux/fs/nfsd/nfsctl.c Tue Dec 29 11:42:25 1998 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,24 @@ 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_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 @@ 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(); diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.2.0-pre1/linux/fs/nfsd/nfsfh.c Mon Dec 28 15:00:53 1998 +++ linux/fs/nfsd/nfsfh.c Tue Dec 29 11:42:25 1998 @@ -1093,32 +1093,33 @@ /* * Security: Check that the export is valid for dentry */ + 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 @@ } /* 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.2.0-pre1/linux/fs/nfsd/nfssvc.c Sun Nov 8 14:03:07 1998 +++ linux/fs/nfsd/nfssvc.c Tue Dec 29 15:17:13 1998 @@ -44,6 +44,11 @@ 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,19 +57,30 @@ 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); @@ -93,6 +109,8 @@ 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 @@ * 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(¤t->sigmask_lock); - siginitsetinv(¤t->blocked, ALLOWED_SIGS); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - svc_process(serv, rqstp); - } + /* Process request with signals blocked. */ + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ALLOWED_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + svc_process(serv, rqstp); /* Unlock export hash tables */ exp_unlock(); @@ -166,6 +175,8 @@ printk("nfsd: last server exiting\n"); /* revoke all exports */ nfsd_export_shutdown(); + /* release read-ahead cache */ + nfsd_racache_shutdown(); } /* Destroy the thread */ diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/stats.c linux/fs/nfsd/stats.c --- v2.2.0-pre1/linux/fs/nfsd/stats.c Mon Jan 12 14:39:48 1998 +++ linux/fs/nfsd/stats.c Tue Dec 29 11:42:25 1998 @@ -13,6 +13,7 @@ * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ +#include #include #include #include @@ -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 @@ { svc_proc_unregister("nfsd"); } +#endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.2.0-pre1/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.2.0-pre1/linux/fs/nfsd/vfs.c Tue Dec 22 14:16:57 1998 +++ linux/fs/nfsd/vfs.c Tue Dec 29 11:42:25 1998 @@ -73,9 +73,10 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/open.c linux/fs/open.c --- v2.2.0-pre1/linux/fs/open.c Mon Dec 28 15:00:53 1998 +++ linux/fs/open.c Tue Dec 29 11:40:35 1998 @@ -523,19 +523,27 @@ 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 + * */ - 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 */ - 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/fs/sysv/CHANGES linux/fs/sysv/CHANGES --- v2.2.0-pre1/linux/fs/sysv/CHANGES Tue Dec 22 14:16:57 1998 +++ linux/fs/sysv/CHANGES Tue Dec 29 17:31:48 1998 @@ -38,3 +38,8 @@ 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. diff -u --recursive --new-file v2.2.0-pre1/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.2.0-pre1/linux/fs/sysv/inode.c Thu Sep 17 17:53:38 1998 +++ linux/fs/sysv/inode.c Tue Dec 29 17:31:48 1998 @@ -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 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.2.0-pre1/linux/fs/sysv/namei.c Tue Dec 22 14:16:57 1998 +++ linux/fs/sysv/namei.c Tue Dec 29 17:31:48 1998 @@ -9,6 +9,7 @@ * * sysv/namei.c * Copyright (C) 1993 Bruno Haible + * Copyright (C) 1997, 1998 Krzysztof G. Baranowski */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/delay.h linux/include/asm-alpha/delay.h --- v2.2.0-pre1/linux/include/asm-alpha/delay.h Fri May 8 23:14:54 1998 +++ linux/include/asm-alpha/delay.h Tue Dec 29 13:56:15 1998 @@ -1,7 +1,7 @@ #ifndef __ALPHA_DELAY_H #define __ALPHA_DELAY_H -extern unsigned long loops_per_sec; +#include /* * Copyright (C) 1993 Linus Torvalds @@ -9,7 +9,8 @@ * 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 @@ * 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) */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/init.h linux/include/asm-alpha/init.h --- v2.2.0-pre1/linux/include/asm-alpha/init.h Tue Aug 18 22:02:07 1998 +++ linux/include/asm-alpha/init.h Tue Dec 29 13:56:15 1998 @@ -12,4 +12,6 @@ #define __FINIT .previous #define __INITDATA .section .data.init,"a" +#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) + #endif diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h --- v2.2.0-pre1/linux/include/asm-alpha/irq.h Tue Dec 22 14:16:57 1998 +++ linux/include/asm-alpha/irq.h Tue Dec 29 13:56:15 1998 @@ -93,6 +93,7 @@ extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); +struct pt_regs; extern void (*perf_irq)(unsigned long, struct pt_regs *); diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h --- v2.2.0-pre1/linux/include/asm-alpha/pgtable.h Mon Dec 28 15:00:53 1998 +++ linux/include/asm-alpha/pgtable.h Tue Dec 29 13:56:15 1998 @@ -175,7 +175,7 @@ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h --- v2.2.0-pre1/linux/include/asm-alpha/smp.h Wed Sep 9 14:51:10 1998 +++ linux/include/asm-alpha/smp.h Tue Dec 29 13:56:15 1998 @@ -12,7 +12,8 @@ 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]; @@ -35,9 +36,6 @@ #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__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h --- v2.2.0-pre1/linux/include/asm-alpha/system.h Tue Dec 22 14:16:57 1998 +++ linux/include/asm-alpha/system.h Tue Dec 29 13:56:15 1998 @@ -244,14 +244,14 @@ __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 @@ __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; } diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-alpha/timex.h linux/include/asm-alpha/timex.h --- v2.2.0-pre1/linux/include/asm-alpha/timex.h Fri May 8 23:14:54 1998 +++ linux/include/asm-alpha/timex.h Tue Dec 29 13:56:15 1998 @@ -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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.2.0-pre1/linux/include/asm-i386/bugs.h Mon Oct 5 13:13:42 1998 +++ linux/include/asm-i386/bugs.h Wed Dec 30 21:58:13 1998 @@ -312,10 +312,55 @@ } } +/* + * 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); diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h --- v2.2.0-pre1/linux/include/asm-i386/byteorder.h Fri Jul 31 17:05:52 1998 +++ linux/include/asm-i386/byteorder.h Wed Dec 30 14:42:47 1998 @@ -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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/elf.h linux/include/asm-i386/elf.h --- v2.2.0-pre1/linux/include/asm-i386/elf.h Wed Jun 24 22:54:10 1998 +++ linux/include/asm-i386/elf.h Wed Dec 30 11:34:24 1998 @@ -32,8 +32,16 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.2.0-pre1/linux/include/asm-i386/pgtable.h Wed Sep 9 14:51:12 1998 +++ linux/include/asm-i386/pgtable.h Wed Dec 30 21:58:13 1998 @@ -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 @@ * 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_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 @@ { } -#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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h --- v2.2.0-pre1/linux/include/asm-i386/smp.h Mon Dec 28 15:00:53 1998 +++ linux/include/asm-i386/smp.h Wed Dec 30 21:58:13 1998 @@ -159,6 +159,7 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/string.h linux/include/asm-i386/string.h --- v2.2.0-pre1/linux/include/asm-i386/string.h Wed Jun 24 22:54:10 1998 +++ linux/include/asm-i386/string.h Tue Dec 29 11:18:18 1998 @@ -30,20 +30,22 @@ #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 @@ "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 @@ "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 @@ "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 @@ "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 @@ 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 @@ "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 @@ "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 @@ "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 @@ "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 @@ "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 @@ 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 @@ #define __HAVE_ARCH_MEMMOVE extern inline void * memmove(void * dest,const void * src, size_t n) { +int d0, d1, d2; if (dest + #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 @@ static inline cycles_t get_cycles (void) { -#if CPU < 586 +#ifndef CONFIG_TSC return 0; #else unsigned long eax, edx; diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.2.0-pre1/linux/include/asm-i386/uaccess.h Mon Dec 28 15:00:53 1998 +++ linux/include/asm-i386/uaccess.h Wed Dec 30 22:00:23 1998 @@ -4,6 +4,7 @@ /* * User space memory access functions */ +#include #include #include @@ -44,7 +45,7 @@ :"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) diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/checksum.h linux/include/asm-ppc/checksum.h --- v2.2.0-pre1/linux/include/asm-ppc/checksum.h Sat May 2 14:19:54 1998 +++ linux/include/asm-ppc/checksum.h Wed Dec 30 10:55:07 1998 @@ -83,13 +83,13 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h --- v2.2.0-pre1/linux/include/asm-ppc/ide.h Thu Nov 19 09:56:29 1998 +++ linux/include/asm-ppc/ide.h Tue Dec 29 11:14:57 1998 @@ -200,14 +200,54 @@ 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]); } } diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/init.h linux/include/asm-ppc/init.h --- v2.2.0-pre1/linux/include/asm-ppc/init.h Fri May 8 23:14:56 1998 +++ linux/include/asm-ppc/init.h Wed Dec 30 10:56:58 1998 @@ -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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h --- v2.2.0-pre1/linux/include/asm-ppc/pgtable.h Thu Nov 19 09:56:29 1998 +++ linux/include/asm-ppc/pgtable.h Wed Dec 30 10:55:07 1998 @@ -121,6 +121,7 @@ #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 @@ #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. diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h --- v2.2.0-pre1/linux/include/asm-ppc/spinlock.h Fri May 8 23:14:56 1998 +++ linux/include/asm-ppc/spinlock.h Wed Dec 30 10:55:07 1998 @@ -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 @@ * 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 @@ 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 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h --- v2.2.0-pre1/linux/include/asm-ppc/system.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-ppc/system.h Wed Dec 30 10:55:07 1998 @@ -5,7 +5,15 @@ #include #include +/* + * 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"); }) diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/termios.h linux/include/asm-ppc/termios.h --- v2.2.0-pre1/linux/include/asm-ppc/termios.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-ppc/termios.h Wed Dec 30 10:55:07 1998 @@ -182,6 +182,8 @@ #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#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__ diff -u --recursive --new-file v2.2.0-pre1/linux/include/asm-ppc/timex.h linux/include/asm-ppc/timex.h --- v2.2.0-pre1/linux/include/asm-ppc/timex.h Fri May 8 23:14:56 1998 +++ linux/include/asm-ppc/timex.h Wed Dec 30 16:04:22 1998 @@ -12,4 +12,28 @@ (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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h --- v2.2.0-pre1/linux/include/linux/arcdevice.h Sun Jun 7 11:16:39 1998 +++ linux/include/linux/arcdevice.h Tue Dec 29 11:18:18 1998 @@ -192,7 +192,7 @@ -#define JIFFER(time) for (delayval=jiffies+time; jiffies> 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__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h --- v2.2.0-pre1/linux/include/linux/nfsd/nfsd.h Fri Jul 31 17:10:04 1998 +++ linux/include/linux/nfsd/nfsd.h Wed Dec 30 21:59:06 1998 @@ -26,11 +26,6 @@ */ #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 @@ /* 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 *, @@ -166,6 +162,11 @@ * Time of server startup */ extern struct timeval nfssvc_boot; + +/* + * The number of nfsd threads. + */ +extern int nfsd_nservers; #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.2.0-pre1/linux/include/linux/pci.h Tue Dec 22 14:16:58 1998 +++ linux/include/linux/pci.h Wed Dec 30 21:58:13 1998 @@ -542,6 +542,7 @@ #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 @@ -734,6 +735,9 @@ #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 @@ -984,6 +988,9 @@ #define PCI_DEVICE_ID_S3_ViRGE_MXP 0x8c02 #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 diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h --- v2.2.0-pre1/linux/include/linux/sunrpc/sched.h Thu Aug 20 17:05:19 1998 +++ linux/include/linux/sunrpc/sched.h Wed Dec 30 21:59:08 1998 @@ -128,7 +128,7 @@ 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); diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/sunrpc/svc.h linux/include/linux/sunrpc/svc.h --- v2.2.0-pre1/linux/include/linux/sunrpc/svc.h Fri Jul 31 17:10:04 1998 +++ linux/include/linux/sunrpc/svc.h Wed Dec 30 21:59:48 1998 @@ -106,7 +106,8 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.2.0-pre1/linux/include/linux/sysctl.h Tue Dec 22 14:16:58 1998 +++ linux/include/linux/sysctl.h Tue Dec 29 11:18:18 1998 @@ -112,7 +112,7 @@ 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 @@ /* /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 @@ 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: */ diff -u --recursive --new-file v2.2.0-pre1/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v2.2.0-pre1/linux/include/linux/sysv_fs.h Thu Sep 17 17:53:38 1998 +++ linux/include/linux/sysv_fs.h Wed Dec 30 22:36:02 1998 @@ -98,7 +98,9 @@ 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 */ diff -u --recursive --new-file v2.2.0-pre1/linux/ipc/shm.c linux/ipc/shm.c --- v2.2.0-pre1/linux/ipc/shm.c Tue Dec 22 14:16:59 1998 +++ linux/ipc/shm.c Tue Dec 29 11:21:49 1998 @@ -624,6 +624,7 @@ 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 @@ 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 @@ 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)) { diff -u --recursive --new-file v2.2.0-pre1/linux/kernel/acct.c linux/kernel/acct.c --- v2.2.0-pre1/linux/kernel/acct.c Fri Nov 27 13:09:29 1998 +++ linux/kernel/acct.c Tue Dec 29 17:32:38 1998 @@ -124,12 +124,12 @@ 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"); } } diff -u --recursive --new-file v2.2.0-pre1/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.2.0-pre1/linux/kernel/ksyms.c Mon Dec 28 15:00:53 1998 +++ linux/kernel/ksyms.c Wed Dec 30 11:35:53 1998 @@ -129,6 +129,7 @@ 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(__down); EXPORT_SYMBOL(__down_interruptible); EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(brw_page); /* all busmice */ EXPORT_SYMBOL(add_mouse_randomness); diff -u --recursive --new-file v2.2.0-pre1/linux/kernel/sched.c linux/kernel/sched.c --- v2.2.0-pre1/linux/kernel/sched.c Mon Dec 28 15:00:53 1998 +++ linux/kernel/sched.c Tue Dec 29 18:27:23 1998 @@ -155,6 +155,15 @@ } #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 @@ * * [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); diff -u --recursive --new-file v2.2.0-pre1/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.2.0-pre1/linux/kernel/sysctl.c Tue Dec 22 14:16:59 1998 +++ linux/kernel/sysctl.c Tue Dec 29 15:31:09 1998 @@ -28,7 +28,7 @@ #include #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 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 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 @@ 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 @@ {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 @@ #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 @@ } -#else /* CONFIG_PROC_FS && CONFIG_SYSCTL */ +#else /* CONFIG_SYSCTL */ extern asmlinkage int sys_sysctl(struct __sysctl_args *args) @@ -1111,7 +1121,4 @@ { } -#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */ - - - +#endif /* CONFIG_SYSCTL */ diff -u --recursive --new-file v2.2.0-pre1/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.2.0-pre1/linux/mm/vmscan.c Tue Dec 22 14:16:59 1998 +++ linux/mm/vmscan.c Wed Dec 30 17:15:40 1998 @@ -564,10 +564,10 @@ 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: diff -u --recursive --new-file v2.2.0-pre1/linux/net/Config.in linux/net/Config.in --- v2.2.0-pre1/linux/net/Config.in Thu Sep 17 17:53:39 1998 +++ linux/net/Config.in Tue Dec 29 11:21:49 1998 @@ -54,11 +54,14 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/net/core/Makefile linux/net/core/Makefile --- v2.2.0-pre1/linux/net/core/Makefile Sat May 2 14:19:54 1998 +++ linux/net/core/Makefile Tue Dec 29 11:21:49 1998 @@ -12,7 +12,9 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/net/core/firewall.c linux/net/core/firewall.c --- v2.2.0-pre1/linux/net/core/firewall.c Mon Feb 23 18:12:12 1998 +++ linux/net/core/firewall.c Tue Dec 29 11:21:49 1998 @@ -10,6 +10,7 @@ #include #include #include +#include #include struct semaphore firewall_sem = MUTEX; @@ -89,6 +90,7 @@ struct firewall_ops *f=fw->next; *nl = f; up(&firewall_sem); + synchronize_bh(); return 0; } nl=&((*nl)->next); diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.2.0-pre1/linux/net/ipv4/devinet.c Sat Sep 5 16:46:42 1998 +++ linux/net/ipv4/devinet.c Tue Dec 29 17:33:35 1998 @@ -208,9 +208,16 @@ { 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 @@ __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)) diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.2.0-pre1/linux/net/ipv4/fib_frontend.c Sat Sep 5 16:46:42 1998 +++ linux/net/ipv4/fib_frontend.c Tue Dec 29 17:33:35 1998 @@ -443,13 +443,13 @@ 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); } diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.2.0-pre1/linux/net/ipv4/ipconfig.c Sun Nov 8 14:03:14 1998 +++ linux/net/ipv4/ipconfig.c Tue Dec 29 17:33:35 1998 @@ -411,96 +411,6 @@ 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. */ __initfunc(static int ic_bootp_alloc(void)) @@ -677,10 +587,9 @@ /* 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 @@ 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 @@ ic_udp_close(ic_bootp_recv_sock); ic_bootp_addrs_del(); ic_bootp_free(); - ic_bootp_route_cleanup(); } @@ -735,7 +642,6 @@ 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)); } diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.2.0-pre1/linux/net/ipv4/route.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/route.c Tue Dec 29 17:33:35 1998 @@ -950,6 +950,10 @@ 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. */ diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.2.0-pre1/linux/net/ipv4/tcp.c Thu Nov 19 09:56:29 1998 +++ linux/net/ipv4/tcp.c Wed Dec 30 21:19:20 1998 @@ -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, * Fred N. van Kempen, @@ -1612,19 +1612,15 @@ 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; } diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.2.0-pre1/linux/net/ipv4/tcp_input.c Thu Nov 19 09:56:29 1998 +++ linux/net/ipv4/tcp_input.c Wed Dec 30 21:19:20 1998 @@ -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, * Fred N. van Kempen, @@ -301,7 +301,7 @@ /* 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 @@ 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 @@ if(tp->fackets_out) tp->fackets_out--; } else { + /* This is pure paranoia. */ tp->retrans_head = NULL; } tp->packets_out--; @@ -633,9 +641,6 @@ __skb_unlink(skb, skb->list); kfree_skb(skb); } - - if (acked) - tp->retrans_head = NULL; return acked; } @@ -740,7 +745,6 @@ * 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 @@ } } -/* - * 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 @@ 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 @@ 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; } /* diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.2.0-pre1/linux/net/ipv4/tcp_ipv4.c Wed Dec 16 10:32:56 1998 +++ linux/net/ipv4/tcp_ipv4.c Wed Dec 30 21:19:20 1998 @@ -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 @@ 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(); diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.2.0-pre1/linux/net/ipv4/tcp_output.c Thu Nov 19 09:56:29 1998 +++ linux/net/ipv4/tcp_output.c Wed Dec 30 21:19:20 1998 @@ -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, * Fred N. van Kempen, @@ -80,15 +80,28 @@ 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 @@ */ 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 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.2.0-pre1/linux/net/ipv4/tcp_timer.c Sun Nov 8 14:03:15 1998 +++ linux/net/ipv4/tcp_timer.c Wed Dec 30 21:19:20 1998 @@ -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, * Fred N. van Kempen, @@ -170,8 +170,13 @@ 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) diff -u --recursive --new-file v2.2.0-pre1/linux/net/netsyms.c linux/net/netsyms.c --- v2.2.0-pre1/linux/net/netsyms.c Thu Nov 19 09:56:29 1998 +++ linux/net/netsyms.c Tue Dec 29 11:21:49 1998 @@ -11,17 +11,16 @@ #include #include #include -#include -#include -#include -#include #include -#include #include #include #include #include #include +#include +#include +#include +#include #ifdef CONFIG_BRIDGE #include @@ -29,6 +28,7 @@ #ifdef CONFIG_INET #include +#include #include #include #include @@ -38,19 +38,13 @@ #include #include #include +#include #include #include #include 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 #include @@ -62,6 +56,7 @@ extern int tcp_tw_death_row_slot; #endif +#endif #include @@ -87,6 +82,10 @@ #ifdef CONFIG_ATALK_MODULE #include +#include +#include +#include +#include #endif #ifdef CONFIG_SYSCTL @@ -136,6 +135,9 @@ 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(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(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(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_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(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(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); diff -u --recursive --new-file v2.2.0-pre1/linux/net/sunrpc/auth.c linux/net/sunrpc/auth.c --- v2.2.0-pre1/linux/net/sunrpc/auth.c Mon Dec 28 15:00:53 1998 +++ linux/net/sunrpc/auth.c Tue Dec 29 11:42:25 1998 @@ -117,7 +117,7 @@ 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 @@ 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]; diff -u --recursive --new-file v2.2.0-pre1/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.2.0-pre1/linux/net/sunrpc/sched.c Sun Nov 8 14:03:16 1998 +++ linux/net/sunrpc/sched.c Tue Dec 29 11:42:25 1998 @@ -79,13 +79,16 @@ * 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 @@ dprintk("RPC: %4d added to queue %p \"%s\"\n", task->tk_pid, queue, rpc_qname(queue)); + + return 0; } /* @@ -168,7 +173,13 @@ 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_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 @@ */ 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; diff -u --recursive --new-file v2.2.0-pre1/linux/net/sunrpc/svc.c linux/net/sunrpc/svc.c --- v2.2.0-pre1/linux/net/sunrpc/svc.c Fri Dec 19 10:54:10 1997 +++ linux/net/sunrpc/svc.c Tue Dec 29 11:42:25 1998 @@ -244,6 +244,12 @@ 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 diff -u --recursive --new-file v2.2.0-pre1/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.2.0-pre1/linux/net/sunrpc/xprt.c Mon Dec 28 15:00:53 1998 +++ linux/net/sunrpc/xprt.c Tue Dec 29 11:42:25 1998 @@ -543,7 +543,7 @@ 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 @@ 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,9 +994,17 @@ * 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 diff -u --recursive --new-file v2.2.0-pre1/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.2.0-pre1/linux/net/wanrouter/wanmain.c Mon Dec 28 15:00:53 1998 +++ linux/net/wanrouter/wanmain.c Wed Dec 30 15:07:00 1998 @@ -32,6 +32,7 @@ * kernel space (for big firmwares) *****************************************************************************/ +#include #include /* offsetof(), etc. */ #include /* return codes */ #include @@ -87,10 +88,8 @@ * 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;