diff -u --recursive --new-file v2.1.108/linux/CREDITS linux/CREDITS --- v2.1.108/linux/CREDITS Tue Jun 23 10:01:18 1998 +++ linux/CREDITS Tue Jul 7 10:48:58 1998 @@ -1,9 +1,9 @@ This is at least a partial credits-file of people that have - contributed to the linux project. It is sorted by name, and - formatted in a format that allows for easy grepping and - beautification by scripts. The fields are: name (N), email (E), - web-address (W), PGP key ID and fingerprint (P), description (D) - and snail-mail address (S). + contributed to the Linux project. It is sorted by name and + formatted to allow easy grepping and beautification by + scripts. The fields are: name (N), email (E), web-address + (W), PGP key ID and fingerprint (P), description (D), and + snail-mail address (S). Thanks, Linus @@ -46,8 +46,8 @@ P: 1024/FC4CFFED 78 3C 6A 19 FA 5D 92 5A FB AC 7B A5 A5 E1 FF 8E D: Maintainer of ide-cd and Uniform CD-ROM driver, D: ATAPI CD-Changer support, Major 2.1.x CD-ROM update. -S: 4538 South Carnegie Tech St. -S: West Valley City, UT 84120 +S: 4538 South Carnegie Tech Street +S: West Valley City, Utah 84120 S: USA N: H. Peter Anvin @@ -56,7 +56,7 @@ P: 2047/2A960705 BA 03 D3 2C 14 A8 A8 BD 1E DF FE 69 EE 35 BD 74 D: Author of the SYSLINUX boot loader, maintainer of the linux.* news D: hierarchy and the Linux Device List; various kernel hacks -S: 4390 Albany Dr. #46 +S: 4390 Albany Drive #46 S: San Jose, California 95129 S: USA @@ -85,7 +85,8 @@ D: Adaptec 274x driver S: Department of Computer Science S: University of Calgary -S: Calgary, Alberta, Canada +S: Calgary, Alberta +S: Canada N: Ralf Baechle E: ralf@gnu.ai.mit.edu @@ -143,7 +144,7 @@ N: Donald Becker E: becker@cesdis.gsfc.nasa.gov D: General low-level networking hacker -D: Most of the ethercard drivers +D: Most of the Ethernet drivers D: Original author of the NFS server S: USRA Center of Excellence in Space Data and Information Sciences S: Code 930.5, Goddard Space Flight Center @@ -185,7 +186,8 @@ D: Some Linux/ARM stuff D: Co-architect of the parallel port sharing system S: Nexus Electronics Ltd -S: 10 St Barnabas Road, Cambridge, UK. CB1 2BY +S: 10 St Barnabas Road, Cambridge CB1 2BY +S: United Kingdom N: Thomas Bogendoerfer E: tsbogend@alpha.franken.de @@ -217,8 +219,9 @@ W: http://coda.cs.cmu.edu/~braam D: Coda Filesystem S: Dept of Computer Science -S: 5000 Forbes Ave -S: Pittsburgh PA 15213 +S: 5000 Forbes Avenue +S: Pittsburgh, Pennsylvania 15213 +S: USA N: Andries Brouwer E: aeb@cwi.nl @@ -273,7 +276,8 @@ D: IGMP(Internet Group Management Protocol) version 2 S: 3F, 65 Tajen street S: Tamsui town, Taipei county, -S: Taiwan 251, Republic of China +S: Taiwan 251 +S: Republic of China N: Raymond Chen E: raymondc@microsoft.com @@ -412,7 +416,8 @@ N: Tom Dyas E: tdyas@eden.rutgers.edu D: minor hacks and some sparc port stuff -S: New Jersey, USA +S: New Jersey +S: USA N: Drew Eckhardt E: drew@PoohSticks.ORG @@ -425,7 +430,7 @@ N: Heiko Eissfeldt E: heiko@colossus.escape.de heiko@unifix.de -D: verify_area stuff, generic scsi fixes +D: verify_area stuff, generic SCSI fixes D: SCSI Programming HOWTO D: POSIX.1 compliance testing S: Unifix Software GmbH @@ -458,7 +463,7 @@ P: 1024/6E657BB5 AF 22 90 33 78 76 04 8B AF F9 97 1E B5 E2 65 30 D: Audio Excel DSP 16 init driver author D: libmodem author -D: Yet Another Micro Monitor port and current mantainer +D: Yet Another Micro Monitor port and current maintainer D: First ELF-HOWTO author D: random kernel hacker S: Via Paolo VI n.29 @@ -482,7 +487,7 @@ N: Jürgen Fischer E: fischer@et-inf.fho-emden.de (=?iso-8859-1?q?J=FCrgen?= Fischer) -D: Author of Adaptec AHA-152x scsi driver +D: Author of Adaptec AHA-152x SCSI driver S: Schulstraße 18 S: 26506 Norden S: Germany @@ -493,7 +498,7 @@ D: General mm minor tidyups S: 67 Surrey St. S: Darlinghurst, Sydney -S: NSW 2010 +S: New South Wales 2010 S: Australia N: Ralf Flaxa @@ -526,7 +531,7 @@ D: Dynamic PPP devices D: Sundry modularizations (PPP, IPX, ...) and fixes S: Caldera, Inc. -S: 240 West Center St. +S: 240 West Center Street S: Orem, Utah 84059-1920 S: USA @@ -571,7 +576,7 @@ D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's S: CSIRO Australia Telescope National Facility S: P.O. Box 76, Epping -S: N.S.W., 2121 +S: New South Wales, 2121 S: Australia N: Dmitry S. Gorodchanin @@ -586,7 +591,7 @@ W: http://rsphy1.anu.edu.au/~gpg109 D: Real Time Clock driver author. D: 8390 net driver hacker (ne2000, wd8013, smc-ultra, 3c503, etc.) -D: Ethernet-HowTo and BootPrompt-HowTo author. +D: Ethernet-HOWTO and BootPrompt-HOWTO author. D: Added many new CONFIG options (modules, ramdisk, generic-serial, etc.) D: Implemented 1st "official" kernel thread (moved user bdflush to kflushd) D: Various other random hacks, patches and utilities. @@ -601,7 +606,7 @@ N: Michael A. Griffith E: grif@cs.ucr.edu W: http://www.cs.ucr.edu/~grif -D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH +D: Loopback speedup, qlogic SCSI hacking, VT_LOCKSWITCH S: Department of Computer Science S: University of California, Riverside S: Riverside, California 92521-0304 @@ -613,7 +618,7 @@ D: original author of ppa driver for parallel port ZIP drive D: original architect of the parallel-port sharing scheme D: PARIDE subsystem: drivers for parallel port IDE & ATAPI devices -S: 44 St. Joseph St., Suite 506 +S: 44 St. Joseph Street, Suite 506 S: Toronto, Ontario, M4Y 2W4 S: Canada @@ -694,7 +699,7 @@ N: Michael Hipp E: mhipp@student.uni-tuebingen.de -D: drivers for the racal ni5210 & ni6510 ethernet-boards +D: drivers for the racal ni5210 & ni6510 Ethernet-boards S: Talstr. 1 S: D - 72072 Tuebingen S: Germany @@ -716,7 +721,7 @@ E: khollis@bitgate.com W: http://www.nurk.org/ D: Berkshire PC Watchdog Driver -S: PO Box 15 +S: Post Office Box 15 S: Grants Pass, Oregon 97526 S: USA @@ -739,7 +744,7 @@ D: Kernel development D: Minor kernel modifications to support Wabi and Wine S: Caldera, Inc. -S: 240 West Center St. +S: 240 West Center Street S: Orem, Utah 84059-1920 S: USA @@ -854,7 +859,7 @@ N: Russell King E: rmk@arm.uk.linux.org -D: Linux/arm integrater, maintainer & hacker +D: Linux/arm integrator, maintainer & hacker S: Burgh Heath, Tadworth, Surrey. S: England @@ -870,8 +875,8 @@ W: http://www.kluft.com/~ikluft/ D: NET-1 beta testing & minor patches, original Smail binary packages for D: Slackware and Debian, vote-taker for 2nd comp.os.linux reorganization -S: PO Box 611311 -S: San Jose, CA 95161-1311 +S: Post Office Box 611311 +S: San Jose, California 95161-1311 S: USA N: Alain L. Knaff @@ -991,7 +996,7 @@ N: Hans Lermen E: lermen@elserv.ffm.fgan.de D: Author of the LOADLIN Linux loader, hacking on boot stuff -D: Co-ordinator of DOSEMU releases +D: Coordinator of DOSEMU releases S: Am Muehlenweg 38 S: D53424 Remagen S: Germany @@ -1000,12 +1005,13 @@ E: achim@vortex.de D: GDT SCSI Disk Array Controller driver S: ICP vortex Computersysteme GmbH -S: Flein, Germany +S: Flein +S: Germany N: Phil Lewis E: beans@bucket.ualr.edu D: Promised to send money if I would put his name in the source tree. -S: PO Box 371 +S: Post Office Box 371 S: North Little Rock, Arkansas 72115 S: USA @@ -1041,7 +1047,7 @@ N: Warner Losh E: imp@village.org D: Linux/MIPS Deskstation support, Provided OI/OB for Linux -S: 8786 Niwot Rd +S: 8786 Niwot Road S: Niwot, Colorado 80503 S: USA @@ -1099,7 +1105,7 @@ N: James B. MacLean E: macleajb@ednet.ns.ca W: http://www.ednet.ns.ca/~macleajb/dosemu.html -D: Former Co-ordinator of DOSEMU releases +D: Former Coordinator of DOSEMU releases D: Program in DOSEMU S: PO BOX 220, HFX. CENTRAL S: Halifax, Nova Scotia @@ -1138,7 +1144,7 @@ W: http://www.invlogic.com/~mmclagan D: DLCI/FRAD drivers for Sangoma SDLAs S: Innovative Logic Corp -S: P.O. Box 1068 +S: Post Office Box 1068 S: Laurel, Maryland 20732 S: USA @@ -1202,7 +1208,7 @@ D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) S: 111 Alta Tierra Court -S: Los Gatos, CA 95032 +S: Los Gatos, California 95032 S: USA N: Rick Miller @@ -1242,7 +1248,7 @@ E: David.Mosberger@acm.org D: Linux/Alpha S: 35706 Runckel Lane -S: Fremont, CA 94536 +S: Fremont, California 94536 S: USA N: Ian A. Murdock @@ -1285,8 +1291,8 @@ P: 1024/83942741 FF 68 EE 27 A0 5A AA C3 F5 DC 05 62 BD 5B 20 2F D: Author of cs89x0, maintainer of kernel changelog through 1.3.3 D: Wrote many packet drivers, from which some Ethernet drivers are derived. -S: 521 Pleasant Valley Rd. -S: Potsdam, NY 13676 +S: 521 Pleasant Valley Road +S: Potsdam, New York 13676 S: USA N: Michael Neuffer @@ -1402,7 +1408,7 @@ W: http://www.pathname.com/~quinlan/ D: FSSTND coordinator; FHS editor D: random Linux documentation, patches, and hacks -S: 4390 Albany Dr. #41A +S: 4390 Albany Drive #41A S: San Jose, California 95129 S: USA @@ -1501,7 +1507,7 @@ N: Thomas Sailer E: sailer@ife.ee.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) -D: hfmodem, Baycom and Soundcard radio modem driver +D: hfmodem, Baycom and sound card radio modem driver S: Weinbergstrasse 76 S: 8408 Winterthur S: Switzerland @@ -1541,12 +1547,13 @@ D: CD-List, Books-List, Ex-FAQ D: Linux-Support, -Mailbox, -Stammtisch D: several improvements to system programs -S: Oldenburg, Germany +S: Oldenburg +S: Germany N: Darren Senn E: sinster@darkwater.com D: Whatever I notice needs doing (so far: itimers, /proc) -S: POB 64132 +S: Post Office Box 64132 S: Sunnyvale, California 94088-4132 S: USA @@ -1589,11 +1596,11 @@ N: Craig Small E: csmall@triode.apana.org.au E: vk2xlz@gonzo.vk2xlz.ampr.org (packet radio) +D: Gracilis PackeTwin device driver +D: RSPF daemon S: 10 Stockalls Place S: Minto, NSW, 2566 S: Australia -D: Gracilis PackeTwin device driver -D: RSPF daemon N: Chris Smith E: csmith@convex.com @@ -1681,14 +1688,14 @@ D: (bogomips, scope, eject, statserial) S: 1 Laurie Court S: Kanata, Ontario -S: CANADA K2L 1S2 +S: Canada K2L 1S2 N: Andrew Tridgell E: Andrew.Tridgell@anu.edu.au D: dosemu, networking, samba S: 3 Ballow Crescent -S: MacGregor A.C.T -S: 2615 Australia +S: MacGregor A.C.T 2615 +S: Australia N: Winfried Trümper E: winni@xpilot.org @@ -1720,7 +1727,8 @@ D: IGMP(Internet Group Management Protocol) version 2 S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD S: Taipei -S: Taiwan 112, Republic of China +S: Taiwan 112 +S: Republic of China S: 24335 Delta Drive S: Diamond Bar, California 91765 S: USA @@ -1799,7 +1807,7 @@ S: USA N: Dirk Verworner -D: Co-author of german book ``Linux-Kernel-Programmierung'' +D: Co-author of German book ``Linux-Kernel-Programmierung'' D: Co-founder of Berlin Linux User Group N: Patrick Volkerding @@ -1903,7 +1911,7 @@ N: Jonathan Woithe E: jwoithe@physics.adelaide.edu.au W: http://www.physics.adelaide.edu.au/~jwoithe -D: ALS-007 soundcard extensions to Sound Blaster driver +D: ALS-007 sound card extensions to Sound Blaster driver S: 4/36 Trevelyan St S: Wayville SA 5034 S: Australia diff -u --recursive --new-file v2.1.108/linux/Documentation/filesystems/ncpfs.txt linux/Documentation/filesystems/ncpfs.txt --- v2.1.108/linux/Documentation/filesystems/ncpfs.txt Tue Apr 2 02:33:13 1996 +++ linux/Documentation/filesystems/ncpfs.txt Wed Jul 8 10:33:42 1998 @@ -1,12 +1,12 @@ -ncpfs is a filesystem which understands the NCP protocol, designed by the -Novell Corporation for their NetWare(tm) product. NCP is functionally -similar to the NFS used in the tcp/ip community. -To mount a Netware-Filesystem, you need a special mount program, which -can be found in ncpfs package. Homesite for ncpfs is +The ncpfs filesystem understands the NCP protocol, designed by the +Novell Corporation for their NetWare(tm) product. NCP is functionally +similar to the NFS used in the TCP/IP community. +To mount a NetWare filesystem, you need a special mount program, which +can be found in the ncpfs package. The home site for ncpfs is ftp.gwdg.de/pub/linux/misc/ncpfs, but sunsite and its many mirrors will have it as well. Related products are linware and mars_nwe, which will give Linux partial -NetWare Server functionality. -Linware's home site is: klokan.sh.cvut.cz/pub/linux/linware, -Mars_nwe can be found on ftp.gwdg.de/pub/linux/misc/ncpfs. +NetWare server functionality. Linware's home site is +klokan.sh.cvut.cz/pub/linux/linware; mars_nwe can be found on +ftp.gwdg.de/pub/linux/misc/ncpfs. diff -u --recursive --new-file v2.1.108/linux/Makefile linux/Makefile --- v2.1.108/linux/Makefile Wed Jul 1 19:38:51 1998 +++ linux/Makefile Wed Jul 1 19:39:31 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 108 +SUBLEVEL = 109 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.1.108/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.108/linux/arch/i386/kernel/entry.S Wed Jul 1 19:38:52 1998 +++ linux/arch/i386/kernel/entry.S Tue Jul 7 13:03:41 1998 @@ -94,18 +94,31 @@ movl %dx,%ds; \ movl %dx,%es; -#define RESTORE_ALL \ - popl %ebx; \ - popl %ecx; \ - popl %edx; \ - popl %esi; \ - popl %edi; \ - popl %ebp; \ - popl %eax; \ - popl %ds; \ - popl %es; \ - addl $4,%esp; \ - iret +#define RESTORE_ALL \ + popl %ebx; \ + popl %ecx; \ + popl %edx; \ + popl %esi; \ + popl %edi; \ + popl %ebp; \ + popl %eax; \ +1: popl %ds; \ +2: popl %es; \ +3: addl $4,%esp; \ + iret; \ +.section fixup,"ax"; \ +4: pushl $0; \ + popl %ds; \ + jmp 2b; \ +5: pushl $0; \ + popl %es; \ + jmp 3b; \ +.previous; \ +.section __ex_table,"a";\ + .align 4; \ + .long 1b,4b; \ + .long 2b,5b; \ +.previous #define GET_CURRENT(reg) \ movl %esp, reg; \ diff -u --recursive --new-file v2.1.108/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.1.108/linux/arch/i386/kernel/ldt.c Thu Apr 23 20:21:28 1998 +++ linux/arch/i386/kernel/ldt.c Tue Jul 7 12:35:14 1998 @@ -35,21 +35,29 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { + struct mm_struct * mm = current->mm; + void * ldt; + __u32 entry_1, entry_2, *lp; + __u16 selector, reg_fs, reg_gs; + int error; struct modify_ldt_ldt_s ldt_info; - unsigned long *lp; - struct mm_struct * mm; - int error, i; + error = -EINVAL; if (bytecount != sizeof(ldt_info)) - return -EINVAL; - error = copy_from_user(&ldt_info, ptr, sizeof(ldt_info)); - if (error) - return -EFAULT; - - if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES) - return -EINVAL; - - mm = current->mm; + goto out; + error = -EFAULT; + if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) + goto out; + + error = -EINVAL; + if (ldt_info.entry_number >= LDT_ENTRIES) + goto out; + if (ldt_info.contents == 3) { + if (oldmode) + goto out; + if (ldt_info.seg_not_present == 0) + goto out; + } /* * Horrible dependencies! Try to get rid of this. This is wrong, @@ -62,60 +70,97 @@ * For no good reason except historical, the GDT index of the LDT * is chosen to follow the index number in the task[] array. */ - if (!mm->segments) { - for (i=1 ; isegments = (void *) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE))) - return -ENOMEM; - memset(mm->segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); - set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, mm->segments, LDT_ENTRIES); - load_ldt(i); - } + ldt = mm->segments; + if (!ldt) { + error = -ENOMEM; + ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (!ldt) + goto out; + memset(ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); + /* + * Make sure someone else hasn't allocated it for us ... + */ + if (!mm->segments) { + int i = current->tarray_ptr - &task[0]; + mm->segments = ldt; + set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, ldt, LDT_ENTRIES); + load_ldt(i); + if (mm->count > 1) + printk(KERN_WARNING + "LDT allocated for cloned task!\n"); + } else { + vfree(ldt); } } - - lp = (unsigned long *) (LDT_ENTRY_SIZE * ldt_info.entry_number + (unsigned long) mm->segments); + + /* + * Check whether the entry to be changed is currently in use. + * If it is, we may need extra validation checks in case the + * kernel is forced to save and restore the selector. + * + * Note: we check the fs and gs values as well, as these are + * loaded by the signal code and during a task switch. + */ + selector = (ldt_info.entry_number << 3) | 4; + __asm__("movw %%fs,%0" : "=r"(reg_fs)); + __asm__("movw %%gs,%0" : "=r"(reg_gs)); + + lp = (__u32 *) ((selector & ~7) + (char *) ldt); + /* Allow LDTs to be cleared by the user. */ - if (ldt_info.base_addr == 0 && ldt_info.limit == 0 - && (oldmode || - ( ldt_info.contents == 0 - && ldt_info.read_exec_only == 1 - && ldt_info.seg_32bit == 0 - && ldt_info.limit_in_pages == 0 - && ldt_info.seg_not_present == 1 - && ldt_info.useable == 0 )) ) { - *lp = 0; - *(lp+1) = 0; - return 0; + if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { + if (oldmode || + (ldt_info.contents == 0 && + ldt_info.read_exec_only == 1 && + ldt_info.seg_32bit == 0 && + ldt_info.limit_in_pages == 0 && + ldt_info.seg_not_present == 1 && + ldt_info.useable == 0 )) { + entry_1 = 0; + entry_2 = 0; + goto out_check; + } } - *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) | + + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | (ldt_info.limit & 0x0ffff); - *(lp+1) = (ldt_info.base_addr & 0xff000000) | - ((ldt_info.base_addr & 0x00ff0000)>>16) | + entry_2 = (ldt_info.base_addr & 0xff000000) | + ((ldt_info.base_addr & 0x00ff0000) >> 16) | (ldt_info.limit & 0xf0000) | - (ldt_info.contents << 10) | ((ldt_info.read_exec_only ^ 1) << 9) | + (ldt_info.contents << 10) | + ((ldt_info.seg_not_present ^ 1) << 15) | (ldt_info.seg_32bit << 22) | (ldt_info.limit_in_pages << 23) | - ((ldt_info.seg_not_present ^1) << 15) | 0x7000; - if (!oldmode) *(lp+1) |= (ldt_info.useable << 20); - return 0; + if (!oldmode) + entry_2 |= (ldt_info.useable << 20); + +out_check: + /* OK to change the entry ... */ + *lp = entry_1; + *(lp+1) = entry_2; + error = 0; +out: + return error; } asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) { - int ret; + int ret = -ENOSYS; lock_kernel(); - if (func == 0) + switch (func) { + case 0: ret = read_ldt(ptr, bytecount); - else if (func == 1) + break; + case 1: ret = write_ldt(ptr, bytecount, 1); - else if (func == 0x11) + break; + case 0x11: ret = write_ldt(ptr, bytecount, 0); - else - ret = -ENOSYS; + break; + } unlock_kernel(); return ret; } diff -u --recursive --new-file v2.1.108/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.108/linux/arch/i386/kernel/process.c Wed Jun 24 22:54:03 1998 +++ linux/arch/i386/kernel/process.c Wed Jul 8 21:05:21 1998 @@ -48,12 +48,10 @@ spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; -struct task_struct *last_task_used_math = NULL; - #ifdef __SMP__ -asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork"); +asmlinkage void ret_from_fork(void) __asm__("ret_from_smpfork"); #else -asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); +asmlinkage void ret_from_fork(void) __asm__("ret_from_sys_call"); #endif #ifdef CONFIG_APM @@ -427,15 +425,20 @@ void release_segments(struct mm_struct *mm) { - void * ldt; + void * ldt = mm->segments; + int nr; /* forget local segments */ __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs ; lldt %w0" : /* no outputs */ : "r" (0)); current->tss.ldt = 0; + /* + * Set the GDT entry back to the default. + */ + nr = current->tarray_ptr - &task[0]; + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, &default_ldt, 1); - ldt = mm->segments; if (ldt) { mm->segments = NULL; vfree(ldt); @@ -447,9 +450,7 @@ */ void exit_thread(void) { - /* forget lazy i387 state */ - if (last_task_used_math == current) - last_task_used_math = NULL; + /* nothing to do ... */ } void flush_thread(void) @@ -462,71 +463,103 @@ /* * Forget coprocessor state.. */ -#ifdef __SMP__ if (current->flags & PF_USEDFPU) { + current->flags &= ~PF_USEDFPU; stts(); } -#else - if (last_task_used_math == current) { - last_task_used_math = NULL; - stts(); - } -#endif current->used_math = 0; - current->flags &= ~PF_USEDFPU; } void release_thread(struct task_struct *dead_task) { } +static inline void unlazy_fpu(struct task_struct *tsk) +{ + if (tsk->flags & PF_USEDFPU) { + tsk->flags &= ~PF_USEDFPU; + __asm__("fnsave %0":"=m" (tsk->tss.i387)); + stts(); + } +} + +/* + * If new_mm is NULL, we're being called to set up the LDT descriptor + * for a clone task. Each clone must have a separate entry in the GDT. + */ void copy_segments(int nr, struct task_struct *p, struct mm_struct *new_mm) { - int ldt_size = 1; - void * ldt = &default_ldt; struct mm_struct * old_mm = current->mm; + void * old_ldt = old_mm->segments, * ldt = old_ldt; + int ldt_size = LDT_ENTRIES; p->tss.ldt = _LDT(nr); - if (old_mm->segments) { - new_mm->segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (new_mm->segments) { - ldt = new_mm->segments; - ldt_size = LDT_ENTRIES; - memcpy(ldt, old_mm->segments, LDT_ENTRIES*LDT_ENTRY_SIZE); + if (old_ldt) { + if (new_mm) { + ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + new_mm->segments = ldt; + if (!ldt) { + printk(KERN_WARNING "ldt allocation failed\n"); + goto no_ldt; + } + memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); } + } else { + no_ldt: + ldt = &default_ldt; + ldt_size = 1; } set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, ldt, ldt_size); } +/* + * Save a segment. + */ +#define savesegment(seg,value) \ + asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value))) + +/* + * Load a segment. Fall back on loading the zero + * segment if something goes wrong.. + */ +#define loadsegment(seg,value) \ + asm volatile("\n" \ + "1:\t" \ + "movl %0,%%" #seg "\n" \ + "2:\n" \ + ".section fixup,\"ax\"\n" \ + "3:\t" \ + "pushl $0\n\t" \ + "popl %%" #seg "\n\t" \ + "jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".align 4\n\t" \ + ".long 1b,3b\n" \ + ".previous" \ + : :"m" (*(unsigned int *)&(value))) + int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; p->tss.tr = _TSS(nr); - p->tss.es = __KERNEL_DS; - p->tss.cs = __KERNEL_CS; - p->tss.ss = __KERNEL_DS; - p->tss.ds = __KERNEL_DS; - p->tss.fs = __USER_DS; - p->tss.gs = __USER_DS; + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); p->tss.ss0 = __KERNEL_DS; p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p; + childregs = ((struct pt_regs *) (p->tss.esp0)) - 1; - p->tss.esp = (unsigned long) childregs; -#ifdef __SMP__ - p->tss.eip = (unsigned long) ret_from_smpfork; - p->tss.eflags = regs->eflags & 0xffffcdff; /* iopl always 0 for a new process */ -#else - p->tss.eip = (unsigned long) ret_from_sys_call; - p->tss.eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */ -#endif - p->tss.ebx = (unsigned long) p; *childregs = *regs; childregs->eax = 0; childregs->esp = esp; - p->tss.back_link = 0; - set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + childregs->eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */ + + p->tss.esp = (unsigned long) childregs; + p->tss.eip = (unsigned long) ret_from_fork; + + savesegment(fs,p->tss.fs); + savesegment(gs,p->tss.gs); /* * a bitmap offset pointing outside of the TSS limit causes a nicely @@ -535,12 +568,9 @@ */ p->tss.bitmap = sizeof(struct thread_struct); -#ifdef __SMP__ - if (current->flags & PF_USEDFPU) -#else - if (last_task_used_math == current) -#endif - __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); + unlazy_fpu(current); + asm volatile("fwait"); + p->tss.i387 = current->tss.i387; return 0; } @@ -552,16 +582,11 @@ { int fpvalid; - if ((fpvalid = current->used_math) != 0) { - if (boot_cpu_data.hard_math) { - if (last_task_used_math == current) { - __asm__("clts ; fsave %0; fwait": :"m" (*fpu)); - } - else - memcpy(fpu,¤t->tss.i387.hard,sizeof(*fpu)); - } else { - memcpy(fpu,¤t->tss.i387.hard,sizeof(*fpu)); - } + fpvalid = current->used_math; + if (fpvalid) { + unlazy_fpu(current); + asm volatile("fwait"); + memcpy(fpu,¤t->tss.i387.hard,sizeof(*fpu)); } return fpvalid; @@ -597,8 +622,8 @@ dump->regs.eax = regs->eax; dump->regs.ds = regs->xds; dump->regs.es = regs->xes; - __asm__("movl %%fs,%0":"=r" (dump->regs.fs)); - __asm__("movl %%gs,%0":"=r" (dump->regs.gs)); + savesegment(fs,dump->regs.fs); + savesegment(gs,dump->regs.gs); dump->regs.orig_eax = regs->orig_eax; dump->regs.eip = regs->eip; dump->regs.cs = regs->xcs; @@ -607,6 +632,89 @@ dump->regs.ss = regs->xss; dump->u_fpvalid = dump_fpu (regs, &dump->i387); +} + +/* + * This special macro can be used to load a debugging register + */ +#define loaddebug(tsk,register) \ + __asm__("movl %0,%%db" #register \ + : /* no output */ \ + :"r" (tsk->debugreg[register])) + + +/* + * switch_to(x,yn) should switch tasks from x to y. + * + * We fsave/fwait so that an exception goes off at the right time + * (as a call from the fsave or fwait in effect) rather than to + * the wrong process. Lazy FP saving no longer makes any sense + * with modern CPU's, and this simplifies a lot of things (SMP + * and UP become the same). + * + * NOTE! We used to use the x86 hardware context switching. The + * reason for not using it any more becomes apparent when you + * try to recover gracefully from saved state that is no longer + * valid (stale segment register values in particular). With the + * hardware task-switch, there is no way to fix up bad state in + * a reasonable manner. + * + * The fact that Intel documents the hardware task-switching to + * be slow is a fairly red herring - this code is not noticeably + * faster. However, there _is_ some room for improvement here, + * so the performance issues may eventually be a valid point. + * More important, however, is the fact that this allows us much + * more flexibility. + */ +void __switch_to(struct task_struct *prev, struct task_struct *next) +{ + /* Do the FPU save and set TS if it wasn't set before.. */ + unlazy_fpu(prev); + + /* + * Reload TR, LDT and the page table pointers.. + * + * We need TR for the IO permission bitmask (and + * the vm86 bitmasks in case we ever use enhanced + * v86 mode properly). + * + * We could do LDT things lazily if this turns out + * to be a win. Most processes will have the default + * LDT. + * + * We want to get rid of the TR register some day, + * and copy the bitmaps around by hand. Oh, well. + * In the meantime we have to clear the busy bit + * in the TSS entry, ugh. + */ + gdt_table[next->tss.tr >> 3].b &= 0xfffffdff; + asm volatile("ltr %0": :"g" (*(unsigned short *)&next->tss.tr)); + asm volatile("lldt %0": :"g" (*(unsigned short *)&next->tss.ldt)); + if (next->tss.cr3 != prev->tss.cr3) + asm volatile("movl %0,%%cr3": :"r" (next->tss.cr3)); + + /* + * Save away %fs and %gs. No need to save %es and %ds, as + * those are always kernel segments while inside the kernel. + * Restore the new values. + */ + asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->tss.fs)); + asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->tss.gs)); + + loadsegment(fs,next->tss.fs); + loadsegment(gs,next->tss.gs); + + /* + * Now maybe reload the debug registers + */ + if (next->debugreg[7]){ + loaddebug(next,0); + loaddebug(next,1); + loaddebug(next,2); + loaddebug(next,3); + loaddebug(next,6); + loaddebug(next,7); + } } asmlinkage int sys_fork(struct pt_regs regs) diff -u --recursive --new-file v2.1.108/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.1.108/linux/arch/i386/kernel/ptrace.c Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/ptrace.c Wed Jul 8 11:38:05 1998 @@ -624,14 +624,8 @@ #ifdef CONFIG_MATH_EMULATION if ( boot_cpu_data.hard_math ) { #endif - if (last_task_used_math == child) { - clts(); - __asm__("fnsave %0; fwait":"=m" (child->tss.i387.hard)); - last_task_used_math = NULL; - stts(); - } - __copy_to_user((void *)data, &child->tss.i387.hard, - sizeof(struct user_i387_struct)); + __copy_to_user((void *)data, &child->tss.i387.hard, + sizeof(struct user_i387_struct)); #ifdef CONFIG_MATH_EMULATION } else { save_i387_soft(&child->tss.i387.soft, @@ -652,13 +646,10 @@ #ifdef CONFIG_MATH_EMULATION if ( boot_cpu_data.hard_math ) { #endif - if (last_task_used_math == child) { - /* Discard the state of the FPU */ - last_task_used_math = NULL; - } __copy_from_user(&child->tss.i387.hard, (void *)data, sizeof(struct user_i387_struct)); child->flags &= ~PF_USEDFPU; + stts(); #ifdef CONFIG_MATH_EMULATION } else { restore_i387_soft(&child->tss.i387.soft, diff -u --recursive --new-file v2.1.108/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.1.108/linux/arch/i386/kernel/signal.c Tue Jun 23 10:01:19 1998 +++ linux/arch/i386/kernel/signal.c Wed Jul 8 11:39:23 1998 @@ -153,17 +153,10 @@ static inline int restore_i387_hard(struct _fpstate *buf) { -#ifdef __SMP__ if (current->flags & PF_USEDFPU) { + current->flags &= ~PF_USEDFPU; stts(); } -#else - if (current == last_task_used_math) { - last_task_used_math = NULL; - stts(); - } -#endif - current->flags &= ~PF_USEDFPU; return __copy_from_user(¤t->tss.i387.hard, buf, sizeof(*buf)); } @@ -315,20 +308,12 @@ static inline int save_i387_hard(struct _fpstate * buf) { -#ifdef __SMP__ if (current->flags & PF_USEDFPU) { - __asm__ __volatile__("fnsave %0":"=m"(current->tss.i387.hard)); - stts(); current->flags &= ~PF_USEDFPU; - } -#else - if (current == last_task_used_math) { __asm__ __volatile__("fnsave %0":"=m"(current->tss.i387.hard)); - last_task_used_math = NULL; - __asm__ __volatile__("fwait"); /* not needed on 486+ */ stts(); } -#endif + asm volatile("fwait"); current->tss.i387.hard.status = current->tss.i387.hard.swd; if (__copy_to_user(buf, ¤t->tss.i387.hard, sizeof(*buf))) return -1; diff -u --recursive --new-file v2.1.108/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.1.108/linux/arch/i386/kernel/traps.c Wed Jun 24 22:54:03 1998 +++ linux/arch/i386/kernel/traps.c Wed Jul 8 11:40:51 1998 @@ -66,23 +66,6 @@ unlock_kernel(); \ } -#define get_seg_byte(seg,addr) ({ \ -register unsigned char __res; \ -__asm__("pushl %%fs;movl %%ax,%%fs;movb %%fs:%2,%%al;popl %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ -__res;}) - -#define get_seg_long(seg,addr) ({ \ -register unsigned long __res; \ -__asm__("pushl %%fs;movl %%ax,%%fs;movl %%fs:%2,%%eax;popl %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ -__res;}) - -#define _fs() ({ \ -register unsigned short __res; \ -__asm__("movl %%fs,%%ax":"=a" (__res):); \ -__res;}) - void page_exception(void); asmlinkage void divide_error(void); @@ -118,6 +101,7 @@ static void show_registers(struct pt_regs *regs) { int i; + int in_kernel = 1; unsigned long esp; unsigned short ss; unsigned long *stack, addr, module_start, module_end; @@ -126,6 +110,7 @@ esp = (unsigned long) ®s->esp; ss = __KERNEL_DS; if (regs->xcs & 3) { + in_kernel = 0; esp = regs->esp; ss = regs->xss & 0xffff; } @@ -138,53 +123,59 @@ printk("ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); store_TR(i); - printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ", + printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", get_seg_long(ss,stack++)); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = get_seg_long(ss, stack++); - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { + + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + printk("\nStack: "); + stack = (unsigned long *) esp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & 4095) == 0) + break; if (i && ((i % 8) == 0)) printk("\n "); - printk("[<%08lx>] ", addr); - i++; + printk("%08lx ", *stack++); + } + printk("\nCall Trace: "); + stack = (unsigned long *) esp; + i = 1; + module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); + module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); + module_end = module_start + MODULE_RANGE; + while (((long) stack & 4095) != 0) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } } + printk("\nCode: "); + for(i=0;i<20;i++) + printk("%02x ", ((unsigned char *)regs->eip)[i]); + printk("\n"); } - printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip))); - printk("\n"); } spinlock_t die_lock; -void die_if_kernel(const char * str, struct pt_regs * regs, long err) +void die(const char * str, struct pt_regs * regs, long err) { - if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3) - return; console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); @@ -193,6 +184,12 @@ do_exit(SIGSEGV); } +static void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs)) + die(str, regs, err); +} + DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current) @@ -200,7 +197,7 @@ DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current) DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) -DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, current) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) @@ -224,17 +221,34 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + + if (!(regs->xcs & 3)) + goto gp_in_kernel; + lock_kernel(); - if (regs->eflags & VM_MASK) { - handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); - goto out; - } - die_if_kernel("general protection",regs,error_code); current->tss.error_code = error_code; current->tss.trap_no = 13; force_sig(SIGSEGV, current); -out: + return; + +gp_in_vm86: + lock_kernel(); + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); unlock_kernel(); + return; + +gp_in_kernel: + { + unsigned long fixup; + fixup = search_exception_table(regs->eip); + if (fixup) { + regs->eip = fixup; + return; + } + die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -295,9 +309,7 @@ __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); - goto out; } - die_if_kernel("debug",regs,error_code); out: unlock_kernel(); } @@ -313,16 +325,7 @@ lock_kernel(); clts(); -#ifdef __SMP__ task = current; -#else - task = last_task_used_math; - last_task_used_math = NULL; - if (!task) { - __asm__("fnclex"); - goto out; - } -#endif /* * Save the info for the exception handler */ @@ -333,9 +336,6 @@ force_sig(SIGFPE, task); task->tss.trap_no = 16; task->tss.error_code = 0; -#ifndef __SMP__ -out: -#endif unlock_kernel(); } @@ -373,15 +373,6 @@ * case we swap processors. We also don't use the coprocessor * timer - IRQ 13 mode isn't used with SMP machines (thank god). */ -#ifndef __SMP__ - if (last_task_used_math == current) - return; - if (last_task_used_math) - __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387)); - else - __asm__("fnclex"); - last_task_used_math = current; -#endif if(current->used_math) __asm__("frstor %0": :"m" (current->tss.i387)); diff -u --recursive --new-file v2.1.108/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.108/linux/arch/i386/mm/fault.c Tue Jun 23 10:01:20 1998 +++ linux/arch/i386/mm/fault.c Tue Jul 7 11:04:58 1998 @@ -22,7 +22,7 @@ #include #include -extern void die_if_kernel(const char *,struct pt_regs *,long); +extern void die(const char *,struct pt_regs *,long); /* * Ugly, ugly, but the goto's result in better assembly.. @@ -101,7 +101,7 @@ __asm__("movl %%cr2,%0":"=r" (address)); if (local_irq_count[smp_processor_id()]) - die_if_kernel("page fault from irq handler",regs,error_code); + die("page fault from irq handler",regs,error_code); tsk = current; mm = tsk->mm; @@ -235,7 +235,7 @@ printk(KERN_ALERT "*pte = %08lx\n", page); } lock_kernel(); - die_if_kernel("Oops", regs, error_code); + die("Oops", regs, error_code); do_exit(SIGKILL); unlock_kernel(); } diff -u --recursive --new-file v2.1.108/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.108/linux/arch/i386/mm/init.c Tue Jun 23 10:01:20 1998 +++ linux/arch/i386/mm/init.c Tue Jul 7 11:02:01 1998 @@ -27,7 +27,6 @@ #include #include -extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); void __bad_pte_kernel(pmd_t *pmd) diff -u --recursive --new-file v2.1.108/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.108/linux/drivers/char/console.c Wed Jun 24 22:54:04 1998 +++ linux/drivers/char/console.c Tue Jul 7 13:29:12 1998 @@ -2316,7 +2316,6 @@ { const char *display_desc = NULL; unsigned int currcons = 0; - char q[2] = { 0, 1 }; if (conswitchp) kmem_start = conswitchp->con_startup(kmem_start, @@ -2397,11 +2396,15 @@ #if 0 /* The logo is too ugly to live */ +{ + char q[2] = { 0, 1 }; + if (console_show_logo) q[1] += console_show_logo(); conswitchp->con_putcs(vc_cons[fg_console].d, linux_logo_banner, sizeof(linux_logo_banner)-1, q[1]-1, q[0]); putconsxy(0, q); +} #endif sw->con_cursor(vc_cons[currcons].d, CM_DRAW); printk("Console: %s %s %ldx%ld", diff -u --recursive --new-file v2.1.108/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.108/linux/drivers/net/de4x5.c Sun Jun 7 11:16:32 1998 +++ linux/drivers/net/de4x5.c Tue Jul 7 20:22:25 1998 @@ -213,14 +213,17 @@ insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. - For a compiled in driver, somewhere in this file, place e.g. + For a compiled in driver, at or above line 548, place e.g. #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" - Yes, I know full duplex isn't permissible on BNC or AUI; they're just - examples. By default, full duplex is turned off and AUTO is the default - autosense setting. In reality, I expect only the full duplex option to + Yes, I know full duplex isn't permissible on BNC or AUI; they're just + examples. By default, full duplex is turned off and AUTO is the default + autosense setting. In reality, I expect only the full duplex option to be used. Note the use of single quotes in the two examples above and the - lack of commas to separate items. + lack of commas to separate items. ALSO, you must get the requested media + correct in relation to what the adapter SROM says it has. There's no way + to determine this in advance other than by trial and error and common + sense, e.g. call a BNC connectored port 'BNC', not '10Mb'. TO DO: ------ @@ -374,11 +377,33 @@ 0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040. 0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure. **Incompatible with 2.0.x from here.** + 0.540 5-Jul-98 Atomicize assertion of dev->interrupt for SMP + from + Add TP, AUI and BNC cases to 21140m_autoconf() for + case where a 21140 under SROM control uses, e.g. AUI + from problem report by + Add MII parallel detection to 2114x_autoconf() for + case where no autonegotiation partner exists from + problem report by . + Add ability to force connection type directly even + when using SROM control from problem report by + . + Updated the PCI interface to conform with the latest + version. I hope nothing is broken... + Add TX done interrupt modification from suggestion + by . + Fix is_anc_capable() bug reported by + . + Fix type[13]_infoblock() bug: during MII search, PHY + lp->rst not run because lp->ibn not initialised - + from report & fix by . + Fix probe bug with EISA & PCI cards present from + report by . ========================================================================= */ -static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.540 1998/7/5 davies@maniac.ultranet.com\n"; #include #include @@ -933,7 +958,7 @@ static void eisa_probe(struct device *dev, u_long iobase); #endif static void pci_probe(struct device *dev, u_long iobase); -static void srom_search(int index); +static void srom_search(struct pci_dev *pdev); static char *build_setup_frame(struct device *dev, int mode); static void disable_ast(struct device *dev); static void enable_ast(struct device *dev, u32 time_out); @@ -980,12 +1005,12 @@ static char name[DE4X5_NAME_LENGTH + 1]; #if !defined(__sparc_v9__) && !defined(__powerpc__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; +static int lastEISA = 0; +#else +static int lastEISA = MAX_EISA_SLOTS; /* Only PCI probes */ #endif static int num_de4x5s = 0; static int cfrv = 0, useSROM = 0; -#if !defined(__sparc_v9__) && !defined(__powerpc__) -static int lastEISA = 0; -#endif static int lastPCI = -1; static struct device *lastModule = NULL; @@ -1036,9 +1061,9 @@ #define PHY_HARD_RESET {\ outl(GEP_HRST, DE4X5_GEP); /* Hard RESET the PHY dev. */\ - mdelay(1); /* Assert for 1ms */\ + mdelay(1); /* Assert for 1ms */\ outl(0x00, DE4X5_GEP);\ - mdelay(2); /* Wait for 2ms */\ + mdelay(2); /* Wait for 2ms */\ } @@ -1054,7 +1079,9 @@ #if !defined(__sparc_v9__) && !defined(__powerpc__) eisa_probe(dev, iobase); #endif - pci_probe(dev, iobase); + if (lastEISA == MAX_EISA_SLOTS) { + pci_probe(dev, iobase); + } return (dev->priv ? 0 : -ENODEV); } @@ -1151,21 +1178,15 @@ /* ** Choose correct autosensing in case someone messed up */ - if ((lp->params.autosense & AUTO) || lp->useSROM) { - lp->autosense = AUTO; - } else { - if (lp->chipset != DC21140) { - if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) { - lp->params.autosense = TP; - } - if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) { - lp->params.autosense = BNC; - } - lp->autosense = lp->params.autosense & 0x001f; - } else { - lp->autosense = lp->params.autosense & 0x00c0; - } - } + lp->autosense = lp->params.autosense; + if (lp->chipset != DC21140) { + if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) { + lp->params.autosense = TP; + } + if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) { + lp->params.autosense = BNC; + } + } lp->fdx = lp->params.fdx; sprintf(lp->adapter_name,"%s (%s)", name, dev->name); @@ -1308,8 +1329,9 @@ lp->state = OPEN; de4x5_dbg_open(dev); + if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, - lp->adapter_name, dev)) { + lp->adapter_name, dev)) { printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, lp->adapter_name, dev)) { @@ -1448,7 +1470,7 @@ } /* -** Writes a socket buffer address to the next available transmit descriptor +** Writes a socket buffer address to the next available transmit descriptor. */ static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) @@ -1542,12 +1564,11 @@ lp = (struct de4x5_private *)dev->priv; iobase = dev->base_addr; - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); + if (test_and_set_bit(MASK_INTERRUPTS, (void*) &dev->interrupt)) + printk("%s: Re-entering the interrupt handler.\n", dev->name); DISABLE_IRQs; /* Ensure non re-entrancy */ synchronize_irq(); - dev->interrupt = MASK_INTERRUPTS; for (limit=0; limit<8; limit++) { sts = inl(DE4X5_STS); /* Read IRQ status */ @@ -1868,16 +1889,27 @@ return; } +/* +** Removes the TD_IC flag from previous descriptor to improve TX performance. +** If the flag is changed on a descriptor that is being read by the hardware, +** I assume PCI transaction ordering will mean you are either successful or +** just miss asserting the change to the hardware. Anyway you're messing with +** a descriptor you don't own, but this shouldn't kill the chip provided +** the descriptor register is read only to the hardware. +*/ static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - + int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1); + lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf)); lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags); lp->tx_skb[lp->tx_new] = skb; + lp->tx_ring[entry].des1 &= cpu_to_le32(~TD_IC); barrier(); + lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN); barrier(); @@ -2044,7 +2076,7 @@ return; } -#endif /* !(__sparc_v9__) */ +#endif /* !(__sparc_v9__) && !(__powerpc__) */ /* ** PCI bus I/O device probe @@ -2057,22 +2089,25 @@ ** bit. Here, check for I/O accesses and then set BM. If you put the card in ** a non BM slot, you're on your own (and complain to the PC vendor that your ** PC doesn't conform to the PCI standard)! +** +** This function is only compatible with the *latest* 2.1.x kernels. For 2.0.x +** kernels use the V0.535[n] drivers. */ -#define PCI_DEVICE (dev_num << 3) #define PCI_LAST_DEV 32 __initfunc(static void pci_probe(struct device *dev, u_long ioaddr)) { - u_char pb, pbus, dev_num, dnum, dev_fn, timer; - u_short dev_id, vendor, index, status; + u_char pb, pbus, dev_num, dnum, timer; + u_short vendor, index, status; u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; + struct pci_dev *pdev = NULL; if (lastPCI == NO_MORE_PCI) return; - if (!pci_present()) { + if (!pcibios_present()) { lastPCI = NO_MORE_PCI; return; /* No PCI bus in this machine! */ } @@ -2088,96 +2123,77 @@ dnum = 0; } - for (index=lastPCI+1; - (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); - index++) { - dev_num = PCI_SLOT(dev_fn); - if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85) - struct pci_dev *pdev = pci_find_slot(pb, dev_fn); -#else - u_char tirq; - u_int tmp; -#endif - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } - - /* Search for an SROM on this bus */ - if (lp->bus_num != pb) { - lp->bus_num = pb; - srom_search(index); - } - - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + for (index=lastPCI+1; (pdev=pci_find_class(class, pdev))!=NULL; index++) { + dev_num = PCI_SLOT(pdev->devfn); + pb = pdev->bus->number; + if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue; + + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; - /* Set the device number information */ - lp->device = dev_num; + /* Search for an SROM on this bus */ + if (lp->bus_num != pb) { lp->bus_num = pb; - - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; + srom_search(pdev); + } - /* Get the board I/O address and IRQ */ -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,85) - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); - irq = tirq; -#else - iobase = pdev->base_address[0]; - irq = pdev->irq; -#endif - iobase &= CBIO_MASK; + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv); - if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; + + /* Set the chipset information */ + if (is_DC2114x) device |= (cfrv & CFRV_RN); + lp->chipset = device; + + /* Get the board I/O address (64 bits on sparc64) */ + iobase = pdev->base_address[0] & CBIO_MASK; - /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + /* Fetch the IRQ to be used */ + irq = pdev->irq; + if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; + + /* Check if I/O accesses and Bus Mastering are enabled */ + pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); #ifdef __powerpc__ - if (!(status & PCI_COMMAND_IO)) { - status |= PCI_COMMAND_IO; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } + if (!(status & PCI_COMMAND_IO)) { + status |= PCI_COMMAND_IO; + pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status); + pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); + } #endif /* __powerpc__ */ - if (!(status & PCI_COMMAND_IO)) continue; - - if (!(status & PCI_COMMAND_MASTER)) { - status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } - if (!(status & PCI_COMMAND_MASTER)) continue; + if (!(status & PCI_COMMAND_IO)) continue; - /* Check the latency timer for values >= 0x60 */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); - if (timer < 0x60) { - pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); - } + if (!(status & PCI_COMMAND_MASTER)) { + status |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status); + pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); + } + if (!(status & PCI_COMMAND_MASTER)) continue; + + /* Check the latency timer for values >= 0x60 */ + pcibios_read_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, &timer); + if (timer < 0x60) { + pcibios_write_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, 0x60); + } - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) { - link_modules(lastModule, dev); - lastPCI = index; - } - return; + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) { + link_modules(lastModule, dev); + lastPCI = index; } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, - iobase); + return; } + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, + iobase); } } @@ -2193,44 +2209,27 @@ ** For single port cards this is a time waster... */ __initfunc(static void -srom_search(int index)) +srom_search(struct pci_dev *pdev)) { - u_char pb, dev_fn; - u_short dev_id, dev_num, vendor, status; + u_char pb; + u_short vendor, status; u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; -#ifndef __sparc_v9__ - u_char tirq; - u_int tmp; -#endif - for (; - (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); - index++) { -#ifdef __sparc_v9__ - struct pci_dev *pdev; - for (pdev = pci_devices; pdev; pdev = pdev->next) { - if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break; - } -#endif - if (lp->bus_num != pb) return; - dev_num = PCI_SLOT(dev_fn); - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } + while ((pdev = pci_find_class(class, pdev))!= NULL) { + if (lp->bus_num != pdev->bus->number) return; + pb = pdev->bus->number; + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv); /* Set the device number information */ - lp->device = dev_num; + lp->device = PCI_SLOT(pdev->devfn); lp->bus_num = pb; /* Set the chipset information */ @@ -2238,25 +2237,14 @@ lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ -#ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; -#else - iobase = pdev->base_address[0]; -#endif - iobase &= CBIO_MASK; + iobase = pdev->base_address[0] & CBIO_MASK; /* Fetch the IRQ to be used */ -#ifndef __sparc_v9__ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); - irq = tirq; -#else irq = pdev->irq; -#endif if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); if (!(status & PCI_COMMAND_IO)) continue; /* Search for a valid SROM attached to this DECchip */ @@ -2709,9 +2697,9 @@ int ana, anlpa, cap, cr, slnk, sr; int next_tick = DE4X5_AUTOSENSE_MS; u_long imr, omr, iobase = dev->base_addr; - + switch(lp->media) { - case INIT: + case INIT: if (lp->timeout < 0) { DISABLE_IRQs; lp->tx_enable = FALSE; @@ -2757,9 +2745,9 @@ } break; - case ANS: + case ANS: switch (lp->local_state) { - case 0: + case 0: if (lp->timeout < 0) { mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); } @@ -2777,7 +2765,7 @@ } break; - case 1: + case 1: if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { next_tick = sr & ~TIMER_CB; } else { @@ -2805,7 +2793,7 @@ } break; - case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ + case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ if (lp->timeout < 0) { lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : (~gep_rd(dev) & GEP_LNP)); @@ -2825,7 +2813,7 @@ } break; - case _100Mb: /* Set 100Mb/s */ + case _100Mb: /* Set 100Mb/s */ next_tick = 3000; if (!lp->tx_enable) { SET_100Mb; @@ -2840,8 +2828,10 @@ } } break; - - case _10Mb: /* Set 10Mb/s */ + + case BNC: + case AUI: + case _10Mb: /* Set 10Mb/s */ next_tick = 3000; if (!lp->tx_enable) { SET_10Mb; @@ -2857,7 +2847,7 @@ } break; - case NC: + case NC: if (lp->media != lp->c_media) { de4x5_dbg_media(dev); lp->c_media = lp->media; @@ -2893,33 +2883,54 @@ int next_tick = DE4X5_AUTOSENSE_MS; switch (lp->media) { - case INIT: + case INIT: if (lp->timeout < 0) { DISABLE_IRQs; lp->tx_enable = FALSE; lp->linkOK = 0; lp->timeout = -1; - de4x5_save_skbs(dev); /* Save non transmitted skb's */ + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + if (lp->params.autosense & ~AUTO) { + srom_map_media(dev); /* Fixed media requested */ + if (lp->media != lp->params.autosense) { + lp->tcount++; + lp->media = INIT; + return next_tick; + } + lp->media = INIT; + } } if ((next_tick = de4x5_reset_phy(dev)) < 0) { next_tick &= ~TIMER_CB; } else { - lp->media = SPD_DET; - if ((lp->infoblock_media == ANS) && + if (lp->autosense == _100Mb) { + lp->media = _100Mb; + } else if (lp->autosense == _10Mb) { + lp->media = _10Mb; + } else if (lp->autosense == TP) { + lp->media = TP; + } else if (lp->autosense == BNC) { + lp->media = BNC; + } else if (lp->autosense == AUI) { + lp->media = AUI; + } else { + lp->media = SPD_DET; + if ((lp->infoblock_media == ANS) && ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM); mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); lp->media = ANS; + } } lp->local_state = 0; next_tick = dc2114x_autoconf(dev); } break; - case ANS: + case ANS: switch (lp->local_state) { - case 0: + case 0: if (lp->timeout < 0) { mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII); } @@ -2937,7 +2948,7 @@ } break; - case 1: + case 1: if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { next_tick = sr & ~TIMER_CB; } else { @@ -2959,15 +2970,15 @@ } } /* Auto Negotiation failed to finish */ next_tick = dc2114x_autoconf(dev); - } /* Auto Negotiation failed to start */ + } /* Auto Negotiation failed to start */ break; } break; - - case AUI: + + case AUI: if (!lp->tx_enable) { if (lp->timeout < 0) { - omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ + omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */ outl(omr & ~OMR_FDX, DE4X5_OMR); } irqs = 0; @@ -2990,13 +3001,13 @@ } break; - case AUI_SUSPECT: + case AUI_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf); break; - case BNC: + case BNC: switch (lp->local_state) { - case 0: + case 0: if (lp->timeout < 0) { omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */ outl(omr & ~OMR_FDX, DE4X5_OMR); @@ -3012,7 +3023,7 @@ } break; - case 1: + case 1: if (!lp->tx_enable) { if ((sts = ping_media(dev, 3000)) < 0) { next_tick = sts & ~TIMER_CB; @@ -3033,11 +3044,11 @@ } break; - case BNC_SUSPECT: + case BNC_SUSPECT: next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf); break; - case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ + case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ if (srom_map_media(dev) < 0) { lp->tcount++; lp->media = INIT; @@ -3053,9 +3064,17 @@ lp->media = SPD_DET; return PDET_LINK_WAIT; } - } - if (((lp->media == _100Mb) && is_100_up(dev)) || + } + if (lp->media == ANS) { /* Do MII parallel detection */ + if (is_spd_100(dev)) { + lp->media = _100Mb; + } else { + lp->media = _10Mb; + } + next_tick = dc2114x_autoconf(dev); + } else if (((lp->media == _100Mb) && is_100_up(dev)) || ((lp->media == _10Mb) && is_10_up(dev)) || + (lp->media == TP) || (lp->media == BNC) || (lp->media == AUI)) { next_tick = dc2114x_autoconf(dev); } else { @@ -3064,7 +3083,7 @@ } break; - case _10Mb: + case _10Mb: next_tick = 3000; if (!lp->tx_enable) { SET_10Mb; @@ -3080,7 +3099,7 @@ } break; - case _100Mb: + case _100Mb: next_tick = 3000; if (!lp->tx_enable) { SET_100Mb; @@ -3096,7 +3115,7 @@ } break; - default: + default: lp->tcount++; printk("Huh?: media:%02x\n", lp->media); lp->media = INIT; @@ -3466,7 +3485,7 @@ if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII)); } else if ((lp->chipset & ~0x00ff) == DC2114x) { - return (inl(DE4X5_SISR) & SISR_LPN) >> 11; + return (inl(DE4X5_SISR) & SISR_LPN) >> 12; } else { return 0; } @@ -4415,7 +4434,7 @@ while (count--) { gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? *p++ : TWIDDLE(w++)), dev); - mdelay(2); /* 2ms per action */ + mdelay(2); /* 2ms per action */ } if (lp->chipset != DC21140) { @@ -4645,6 +4664,7 @@ p += 2; if (lp->state == INITIALISED) { + lp->ibn = 1; lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); @@ -4724,6 +4744,7 @@ p += 2; if (lp->state == INITIALISED) { + lp->ibn = 3; lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1); @@ -5471,24 +5492,24 @@ } tmp; switch(ioc->cmd) { - case DE4X5_GET_HWADDR: /* Get the hardware address */ + 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; + break; for (i=0; idev_addr[i]; } copy_to_user(ioc->data, tmp.addr, ioc->len); break; - case DE4X5_SET_HWADDR: /* Set the hardware address */ + case DE4X5_SET_HWADDR: /* Set the hardware address */ status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN); if (status) - break; + break; status = -EPERM; if (!capable(CAP_NET_ADMIN)) - break; + break; status = 0; copy_from_user(tmp.addr, ioc->data, ETH_ALEN); for (i=0; itbusy) != 0); load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); + 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 */ + case DE4X5_SET_PROM: /* Set Promiscuous Mode */ if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr |= OMR_PR; @@ -5515,7 +5536,7 @@ } break; - case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ + case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr &= ~OMR_PR; @@ -5526,11 +5547,11 @@ } break; - case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */ + 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 */ + case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ if (capable(CAP_NET_ADMIN)) { omr = inl(DE4X5_OMR); omr |= OMR_PM; @@ -5540,18 +5561,18 @@ } break; - case DE4X5_GET_STATS: /* Get the driver statistics */ + 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; + break; cli(); copy_to_user(ioc->data, &lp->pktStats, ioc->len); sti(); break; - case DE4X5_CLR_STATS: /* Zero out the driver statistics */ + case DE4X5_CLR_STATS: /* Zero out the driver statistics */ if (capable(CAP_NET_ADMIN)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); @@ -5561,14 +5582,14 @@ } break; - case DE4X5_GET_OMR: /* Get the OMR Register contents */ + 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); } break; - case DE4X5_SET_OMR: /* Set the OMR Register contents */ + 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); @@ -5579,7 +5600,7 @@ } break; - case DE4X5_GET_REG: /* Get the DE4X5 Registers */ + case DE4X5_GET_REG: /* Get the DE4X5 Registers */ j = 0; tmp.lval[0] = inl(DE4X5_STS); j+=4; tmp.lval[1] = inl(DE4X5_BMR); j+=4; @@ -5687,7 +5708,7 @@ break; */ - default: + default: status = -EOPNOTSUPP; } @@ -5766,30 +5787,32 @@ static int count_adapters(void) { - int i, j; + int i, j=0; char name[DE4X5_STRLEN]; - u_char pb, dev_fn, dev_num; - u_short dev_id, vendor; + u_char pb, dev_fn; + u_short vendor; u_int class = DE4X5_CLASS_CODE; u_int device; + struct pci_dev *pdev; + #if !defined(__sparc_v9__) && !defined(__powerpc__) u_long iobase = 0x1000; - for (j=0, i=1; inext) { + if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; + } + + vendor = pdev->vendor; + device = pdev->device << 8; if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++; } diff -u --recursive --new-file v2.1.108/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.1.108/linux/drivers/net/de4x5.h Sun Dec 21 22:37:32 1997 +++ linux/drivers/net/de4x5.h Tue Jul 7 20:22:25 1998 @@ -811,7 +811,7 @@ ** Media / mode state machine definitions ** User selectable: */ -#define TP 0x0001 /* 10Base-T */ +#define TP 0x0040 /* 10Base-T (now equiv to _10Mb) */ #define TP_NW 0x0002 /* 10Base-T with Nway */ #define BNC 0x0004 /* Thinwire */ #define AUI 0x0008 /* Thickwire */ diff -u --recursive --new-file v2.1.108/linux/fs/ncpfs/Makefile linux/fs/ncpfs/Makefile --- v2.1.108/linux/fs/ncpfs/Makefile Tue Mar 17 22:18:15 1998 +++ linux/fs/ncpfs/Makefile Wed Jul 8 10:33:42 1998 @@ -1,11 +1,11 @@ # -# Makefile for the linux ncp-filesystem routines. +# Makefile for the linux ncp filesystem routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). +# unless it's something special (not a .c file). # -# Note 2! The CFLAGS definitions are now in the main makefile... +# Note 2! The CFLAGS definitions are now in the main makefile. O_TARGET := ncpfs.o O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \ diff -u --recursive --new-file v2.1.108/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h --- v2.1.108/linux/include/asm-i386/bugs.h Wed Jun 24 22:54:10 1998 +++ linux/include/asm-i386/bugs.h Wed Jul 8 21:00:16 1998 @@ -41,7 +41,7 @@ timer_table[COPRO_TIMER].expires = jiffies+100; timer_active |= 1<xds = seg; \ - regs->xes = seg; \ - regs->xss = seg; \ - regs->xcs = __USER_CS; \ - regs->eip = new_eip; \ - regs->esp = new_esp; \ +#define start_thread(regs, new_eip, new_esp) do { \ + __asm__("movl %w0,%%fs ; movl %w0,%%gs": :"r" (0)); \ + set_fs(USER_DS); \ + regs->xds = __USER_DS; \ + regs->xes = __USER_DS; \ + regs->xss = __USER_DS; \ + regs->xcs = __USER_CS; \ + regs->eip = new_eip; \ + regs->esp = new_esp; \ } while (0) /* Forward declaration, a strange C thing */ diff -u --recursive --new-file v2.1.108/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.1.108/linux/include/asm-i386/system.h Sat Apr 25 18:13:12 1998 +++ linux/include/asm-i386/system.h Tue Jul 7 17:12:49 1998 @@ -1,6 +1,7 @@ #ifndef __ASM_SYSTEM_H #define __ASM_SYSTEM_H +#include #include /* @@ -35,83 +36,34 @@ :"=a" (n) \ :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) -/* This special macro can be used to load a debugging register */ - -#define loaddebug(tsk,register) \ - __asm__("movl %0,%%db" #register \ - : /* no output */ \ - :"r" (tsk->debugreg[register])) - +struct task_struct; /* one of the stranger aspects of C forward declarations.. */ +extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); /* - * switch_to(n) should switch tasks to task nr n, first - * checking that n isn't the current task, in which case it does nothing. - * This also clears the TS-flag if the task we switched to has used - * the math co-processor latest. - * - * It also reloads the debug regs if necessary.. + * We do most of the task switching in C, but we need + * to do the EIP/ESP switch in assembly.. */ - - -#ifdef __SMP__ - /* - * Keep the lock depth straight. If we switch on an interrupt from - * kernel->user task we need to lose a depth, and if we switch the - * other way we need to gain a depth. Same layer switches come out - * the same. - * - * We spot a switch in user mode because the kernel counter is the - * same as the interrupt counter depth. (We never switch during the - * message/invalidate IPI). - * - * We fsave/fwait so that an exception goes off at the right time - * (as a call from the fsave or fwait in effect) rather than to - * the wrong process. - */ - -#define switch_to(prev,next) do { \ - if(prev->flags&PF_USEDFPU) \ - { \ - __asm__ __volatile__("fnsave %0":"=m" (prev->tss.i387.hard)); \ - __asm__ __volatile__("fwait"); \ - prev->flags&=~PF_USEDFPU; \ - } \ -__asm__("ljmp %0\n\t" \ - : /* no output */ \ - :"m" (*(((char *)&next->tss.tr)-4)), \ - "c" (next)); \ - /* Now maybe reload the debug registers */ \ - if(prev->debugreg[7]){ \ - loaddebug(prev,0); \ - loaddebug(prev,1); \ - loaddebug(prev,2); \ - loaddebug(prev,3); \ - loaddebug(prev,6); \ - loaddebug(prev,7); \ - } \ -} while (0) - -#else -#define switch_to(prev,next) do { \ -__asm__("ljmp %0\n\t" \ - "cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \ - "jne 1f\n\t" \ - "clts\n" \ - "1:" \ - : /* no outputs */ \ - :"m" (*(((char *)&next->tss.tr)-4)), \ - "r" (prev), "r" (next)); \ - /* Now maybe reload the debug registers */ \ - if(prev->debugreg[7]){ \ - loaddebug(prev,0); \ - loaddebug(prev,1); \ - loaddebug(prev,2); \ - loaddebug(prev,3); \ - loaddebug(prev,6); \ - loaddebug(prev,7); \ - } \ +#define switch_to(prev,next) do { \ + unsigned long eax, edx, ecx; \ + asm volatile("pushl %%edi\n\t" \ + "pushl %%esi\n\t" \ + "pushl %%ebp\n\t" \ + "pushl %%ebx\n\t" \ + "movl %%esp,%0\n\t" /* save ESP */ \ + "movl %5,%%esp\n\t" /* restore ESP */ \ + "movl $1f,%1\n\t" /* save EIP */ \ + "pushl %6\n\t" /* restore EIP */ \ + "jmp __switch_to\n" \ + "1:\t" \ + "popl %%ebx\n\t" \ + "popl %%ebp\n\t" \ + "popl %%esi\n\t" \ + "popl %%edi" \ + :"=m" (prev->tss.esp),"=m" (prev->tss.eip), \ + "=a" (eax), "=d" (edx), "=c" (ecx) \ + :"m" (next->tss.esp),"m" (next->tss.eip), \ + "a" (prev), "d" (next)); \ } while (0) -#endif #define _set_base(addr,base) \ __asm__("movw %%dx,%0\n\t" \ diff -u --recursive --new-file v2.1.108/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.108/linux/kernel/fork.c Wed Jun 24 22:54:12 1998 +++ linux/kernel/fork.c Tue Jul 7 10:37:07 1998 @@ -308,6 +308,10 @@ if (clone_flags & CLONE_VM) { mmget(current->mm); + /* + * Set up the LDT descriptor for the clone task. + */ + copy_segments(nr, tsk, NULL); SET_PAGE_DIR(tsk, current->mm->pgd); return 0; } diff -u --recursive --new-file v2.1.108/linux/kernel/printk.c linux/kernel/printk.c --- v2.1.108/linux/kernel/printk.c Thu May 7 22:51:55 1998 +++ linux/kernel/printk.c Tue Jul 7 16:11:10 1998 @@ -14,8 +14,6 @@ #include -#include - #include #include #include @@ -27,6 +25,7 @@ #include #include +#include #include #define LOG_BUF_LEN 8192 diff -u --recursive --new-file v2.1.108/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.108/linux/mm/filemap.c Wed Jul 1 19:38:57 1998 +++ linux/mm/filemap.c Fri Jul 3 08:50:14 1998 @@ -851,7 +851,7 @@ return written; } -asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, size_t count) +asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) { ssize_t retval; struct file * in_file, * out_file; @@ -900,16 +900,27 @@ retval = 0; if (count) { read_descriptor_t desc; + loff_t pos = 0, *ppos; + + retval = -EFAULT; + ppos = &in_file->f_pos; + if (offset) { + if (get_user(pos, offset)) + goto fput_out; + ppos = &pos; + } desc.written = 0; desc.count = count; desc.buf = (char *) out_file; desc.error = 0; - do_generic_file_read(in_file, &in_file->f_pos, &desc, file_send_actor); + do_generic_file_read(in_file, ppos, &desc, file_send_actor); retval = desc.written; if (!retval) retval = desc.error; + if (offset) + put_user(pos, offset); }