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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
-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.
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/)
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; \
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;
+ goto out;
+ error = -EFAULT;
+ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+ goto out;
- mm = current->mm;
+ 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,
* 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 ; i<NR_TASKS ; i++) {
- if (task[i] == current) {
- if (!(mm->segments = (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;
}
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
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);
*/
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)
/*
* 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
*/
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;
}
{
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;
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;
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)
{
int ret;
#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,
#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,
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));
}
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;
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);
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;
esp = (unsigned long) ®s->esp;
ss = __KERNEL_DS;
if (regs->xcs & 3) {
+ in_kernel = 0;
esp = regs->esp;
ss = regs->xss & 0xffff;
}
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);
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)
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)
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)
__asm__("movl %0,%%db7"
: /* no output */
: "r" (0));
- goto out;
}
- die_if_kernel("debug",regs,error_code);
out:
unlock_kernel();
}
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
*/
force_sig(SIGFPE, task);
task->tss.trap_no = 16;
task->tss.error_code = 0;
-#ifndef __SMP__
-out:
-#endif
unlock_kernel();
}
* 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));
#include <asm/pgtable.h>
#include <asm/hardirq.h>
-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..
__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;
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();
}
#include <asm/pgtable.h>
#include <asm/dma.h>
-extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
void __bad_pte_kernel(pmd_t *pmd)
{
const char *display_desc = NULL;
unsigned int currcons = 0;
- char q[2] = { 0, 1 };
if (conswitchp)
kmem_start = conswitchp->con_startup(kmem_start,
#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",
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:
------
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 <lma@varesearch.com>
+ 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 <delchini@lpnp09.in2p3.fr>
+ Add MII parallel detection to 2114x_autoconf() for
+ case where no autonegotiation partner exists from
+ problem report by <mlapsley@ndirect.co.uk>.
+ Add ability to force connection type directly even
+ when using SROM control from problem report by
+ <earl@exis.net>.
+ Updated the PCI interface to conform with the latest
+ version. I hope nothing is broken...
+ Add TX done interrupt modification from suggestion
+ by <Austin.Donnelly@cl.cam.ac.uk>.
+ Fix is_anc_capable() bug reported by
+ <Austin.Donnelly@cl.cam.ac.uk>.
+ Fix type[13]_infoblock() bug: during MII search, PHY
+ lp->rst not run because lp->ibn not initialised -
+ from report & fix by <paubert@iram.es>.
+ Fix probe bug with EISA & PCI cards present from
+ report by <eirik@netcom.com>.
=========================================================================
*/
-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 <linux/config.h>
#include <linux/module.h>
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);
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;
#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 */\
}
\f
#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);
}
/*
** 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);
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)) {
}
/*
-** 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)
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 */
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();
return;
}
-#endif /* !(__sparc_v9__) */
+#endif /* !(__sparc_v9__) && !(__powerpc__) */
/*
** PCI bus I/O device probe
** 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! */
}
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);
- }
+ 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;
- /* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
- /* Set the device number information */
- lp->device = dev_num;
+ /* Search for an SROM on this bus */
+ if (lp->bus_num != pb) {
lp->bus_num = pb;
-
- /* 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);
+
+ /* 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;
- if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+ /* 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_IO)) continue;
- if (!(status & PCI_COMMAND_MASTER)) {
- status |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
- if (!(status & PCI_COMMAND_MASTER)) continue;
+ if (!(status & PCI_COMMAND_MASTER)) {
+ status |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pb, 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, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
- if (timer < 0x60) {
- pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
- }
+ /* Check the latency timer for values >= 0x60 */
+ pcibios_read_config_byte(pb, 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);
}
}
** 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 */
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 */
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;
}
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);
}
}
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 {
}
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));
}
break;
- case _100Mb: /* Set 100Mb/s */
+ case _100Mb: /* Set 100Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
}
}
break;
-
- case _10Mb: /* Set 10Mb/s */
+
+ case BNC:
+ case AUI:
+ case _10Mb: /* Set 10Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
SET_10Mb;
}
break;
- case NC:
+ case NC:
if (lp->media != lp->c_media) {
de4x5_dbg_media(dev);
lp->c_media = lp->media;
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);
}
}
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 {
}
} /* 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;
}
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);
}
break;
- case 1:
+ case 1:
if (!lp->tx_enable) {
if ((sts = ping_media(dev, 3000)) < 0) {
next_tick = sts & ~TIMER_CB;
}
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;
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 {
}
break;
- case _10Mb:
+ case _10Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_10Mb;
}
break;
- case _100Mb:
+ case _100Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
}
break;
- default:
+ default:
lp->tcount++;
printk("Huh?: media:%02x\n", lp->media);
lp->media = INIT;
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;
}
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) {
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);
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);
} 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; i<ETH_ALEN; i++) {
tmp.addr[i] = dev->dev_addr[i];
}
copy_to_user(ioc->data, tmp.addr, ioc->len);
break;
- case DE4X5_SET_HWADDR: /* Set the hardware address */
+ 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; i<ETH_ALEN; i++) {
/* Set up the descriptor and give ownership to the card */
while (test_and_set_bit(0, (void *)&dev->tbusy) != 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;
}
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;
}
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;
}
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));
}
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);
}
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;
break;
*/
- default:
+ default:
status = -EOPNOTSUPP;
}
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; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+ for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID)) j++;
}
#endif
- if (!pci_present()) return j;
+ if (!pcibios_present()) return j;
for (i=0;
(pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
i++) {
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+ }
+
+ vendor = pdev->vendor;
+ device = pdev->device << 8;
if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
}
** 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 */
#
-# 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 \
timer_table[COPRO_TIMER].expires = jiffies+100;
timer_active |= 1<<COPRO_TIMER;
printk(KERN_ERR "387 failed: trying to reset\n");
- send_sig(SIGFPE, last_task_used_math, 1);
+ send_sig(SIGFPE, current, 1);
outb_p(0,0xf1);
outb_p(0,0xf0);
}
* misexecution of code under Linux. Owners of such processors should
* contact AMD for precise details and a CPU swap.
*
- * See http://www.chorus.com/~poulot/k6bug.html
+ * See http://www.mygale.com/~poulot/k6bug.html
* http://www.amd.com/K6/k6docs/revgd.html
*
* The following test is erm.. interesting. AMD neglected to up
printk("system stability may be impaired when more than 32 MB are used.\n");
else
printk("probably OK (after B9730xxxx).\n");
- printk(KERN_INFO "Please see http://www.chorus.com/poulot/k6bug.html\n");
+ printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
}
}
extern unsigned int machine_submodel_id;
extern unsigned int BIOS_revision;
-/* Lazy FPU handling on uni-processor */
-extern struct task_struct *last_task_used_math;
-
/*
* User space process size: 3GB (default).
*/
#define INIT_MMAP \
{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-#define INIT_TSS { \
- 0,0, \
- sizeof(init_stack) + (long) &init_stack, \
- __KERNEL_DS, 0, \
- 0,0,0,0,0,0, \
- (long) &swapper_pg_dir - PAGE_OFFSET, \
- 0,0,0,0,0,0,0,0,0,0, \
- __USER_DS,0,__USER_DS,0,__USER_DS,0, \
- __USER_DS,0,__USER_DS,0,__USER_DS,0, \
- _LDT(0),0, \
- 0, 0x8000, \
- {~0, }, /* ioperm */ \
- _TSS(0), 0, 0, 0, (mm_segment_t) { 0 } /* obsolete */ , \
- { { 0, }, }, /* 387 state */ \
- NULL, 0, 0, 0, 0, 0 /* vm86_info */, \
+#define INIT_TSS { \
+ 0,0, /* back_link, __blh */ \
+ sizeof(init_stack) + (long) &init_stack, /* esp0 */ \
+ __KERNEL_DS, 0, /* ss0 */ \
+ 0,0,0,0,0,0, /* stack1, stack2 */ \
+ (long) &swapper_pg_dir - PAGE_OFFSET, /* cr3 */ \
+ 0,0, /* eip,eflags */ \
+ 0,0,0,0, /* eax,ecx,edx,ebx */ \
+ 0,0,0,0, /* esp,ebp,esi,edi */ \
+ 0,0,0,0,0,0, /* es,cs,ss */ \
+ 0,0,0,0,0,0, /* ds,fs,gs */ \
+ _LDT(0),0, /* ldt */ \
+ 0, 0x8000, /* tace, bitmap */ \
+ {~0, }, /* ioperm */ \
+ _TSS(0), 0, 0, 0, (mm_segment_t) { 0 }, /* obsolete */ \
+ { { 0, }, }, /* 387 state */ \
+ NULL, 0, 0, 0, 0, 0, /* vm86_info */ \
}
-#define start_thread(regs, new_eip, new_esp) do {\
- unsigned long seg = __USER_DS; \
- __asm__("movl %w0,%%fs ; movl %w0,%%gs":"=r" (seg) :"0" (seg)); \
- set_fs(USER_DS); \
- regs->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 */
#ifndef __ASM_SYSTEM_H
#define __ASM_SYSTEM_H
+#include <linux/kernel.h>
#include <asm/segment.h>
/*
:"=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); \
- } \
+#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)
-#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); \
- } \
-} while (0)
-#endif
-
#define _set_base(addr,base) \
__asm__("movw %%dx,%0\n\t" \
"rorl $16,%%edx\n\t" \
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;
}
#include <stdarg.h>
-#include <asm/system.h>
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <asm/system.h>
#include <asm/uaccess.h>
#define LOG_BUF_LEN 8192
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;
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);
}