Commit ab92dab4 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.109pre1

parent 7eaba1c7
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 @@ W: http://www.inconnect.com/~andersen
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 @@ W: http://www.zytor.com/~hpa/
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 @@ E: aycock@cpsc.ucalgary.ca
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 @@ S: Germany
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: Device driver hacking
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 @@ E: braam@cs.cmu.edu
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 @@ E: chihjen@iis.sinica.edu.tw
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 @@ S: Germany
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 @@ S: USA
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 @@ E: fizban@tin.it
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 @@ S: Hungary
N: Jrgen 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: Schulstrae 18
S: 26506 Norden
S: Germany
......@@ -493,7 +498,7 @@ D: Improved mmap and munmap handling
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: Initial GPL'd Frame Relay driver
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: prctl() syscall
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 @@ E: gpg109@rsphy1.anu.edu.au
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 @@ S: USA
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 @@ W: http://www.torque.net/linux-pp.html
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 @@ S: Germany
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 @@ N: Kenji Tsutomu Hollis
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 @@ P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A 40 E3 FB 71 D1 C8 0B 56
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 @@ S: Germany
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 @@ E: ikluft@thunder.sbay.org
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 @@ S: Australia
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 @@ N: Achim Leubner
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 @@ S: United Kingdom
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 @@ S: Australia
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 @@ E: mike.mclagan@linux.org
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: New Linux-Activists maintainer
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 @@ N: David Mosberger-Tang
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 @@ W: http://www.crynwr.com/~nelson
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 @@ E: quinlan@pathname.com
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 @@ D: Developed Generic IP Firewalling Chains with Michael Neuling.
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: Random Linux Hacker, Linux Promoter
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 @@ 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
......@@ -1681,14 +1688,14 @@ D: Author of several small utilities
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 Trmper
E: winni@xpilot.org
......@@ -1720,7 +1727,8 @@ E: tsusheng@scf.usc.edu
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 @@ D: Turtle Beach MultiSound sound driver
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 @@ S: Finland
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/)
......
......@@ -94,18 +94,31 @@ ENOSYS = 38
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; \
......
......@@ -35,21 +35,29 @@ static int read_ldt(void * ptr, unsigned long bytecount)
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,
......@@ -62,60 +70,97 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
* 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;
}
......@@ -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 show_regs(struct pt_regs * regs)
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 release_segments(struct mm_struct *mm)
*/
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 @@ 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
......@@ -535,12 +568,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
*/
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 dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
{
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,&current->tss.i387.hard,sizeof(*fpu));
} else {
memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
}
fpvalid = current->used_math;
if (fpvalid) {
unlazy_fpu(current);
asm volatile("fwait");
memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
}
return fpvalid;
......@@ -597,8 +622,8 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
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;
......@@ -609,6 +634,89 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
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;
......
......@@ -624,14 +624,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
#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 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
#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,
......
......@@ -153,17 +153,10 @@ struct rt_sigframe
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(&current->tss.i387.hard, buf, sizeof(*buf));
}
......@@ -315,20 +308,12 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
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, &current->tss.i387.hard, sizeof(*buf)))
return -1;
......
......@@ -66,23 +66,6 @@ out: \
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 @@ int kstack_depth_to_print = 24;
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 @@ static void show_registers(struct pt_regs *regs)
esp = (unsigned long) &regs->esp;
ss = __KERNEL_DS;
if (regs->xcs & 3) {
in_kernel = 0;
esp = regs->esp;
ss = regs->xss & 0xffff;
}
......@@ -138,53 +123,59 @@ static void show_registers(struct pt_regs *regs)
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 @@ void die_if_kernel(const char * str, struct pt_regs * regs, long err)
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_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, 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)
......@@ -224,17 +221,34 @@ asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
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 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
__asm__("movl %0,%%db7"
: /* no output */
: "r" (0));
goto out;
}
die_if_kernel("debug",regs,error_code);
out:
unlock_kernel();
}
......@@ -313,16 +325,7 @@ void math_error(void)
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 @@ void math_error(void)
force_sig(SIGFPE, task);
task->tss.trap_no = 16;
task->tss.error_code = 0;
#ifndef __SMP__
out:
#endif
unlock_kernel();
}
......@@ -373,15 +373,6 @@ asmlinkage void math_state_restore(void)
* 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));
......
......@@ -22,7 +22,7 @@
#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..
......@@ -101,7 +101,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
__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 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
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();
}
......@@ -27,7 +27,6 @@
#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)
......
......@@ -2316,7 +2316,6 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
{
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 @@ __initfunc(unsigned long con_init(unsigned long 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",
......
......@@ -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 <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>
......@@ -933,7 +958,7 @@ static int test_bad_enet(struct device *dev, int status);
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 int loading_module = 0;
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 @@ static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
#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 @@ de4x5_probe(struct device *dev))
#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 @@ de4x5_hw_init(struct device *dev, u_long iobase))
/*
** 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 @@ de4x5_open(struct device *dev)
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 @@ de4x5_sw_reset(struct device *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)
......@@ -1542,12 +1564,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ de4x5_local_stats(struct device *dev, char *buf, int pkt_len)
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 @@ eisa_probe(struct device *dev, u_long ioaddr))
return;
}
#endif /* !(__sparc_v9__) */
#endif /* !(__sparc_v9__) && !(__powerpc__) */
/*
** PCI bus I/O device probe
......@@ -2057,22 +2089,25 @@ eisa_probe(struct device *dev, u_long ioaddr))
** 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 @@ pci_probe(struct device *dev, u_long ioaddr))
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);
}
}
......@@ -2193,44 +2209,27 @@ pci_probe(struct device *dev, u_long ioaddr))
** 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 @@ srom_search(int index))
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 @@ dc21140m_autoconf(struct device *dev)
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 @@ dc21140m_autoconf(struct device *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);
}
......@@ -2777,7 +2765,7 @@ dc21140m_autoconf(struct device *dev)
}
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 @@ dc21140m_autoconf(struct device *dev)
}
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 @@ dc21140m_autoconf(struct device *dev)
}
break;
case _100Mb: /* Set 100Mb/s */
case _100Mb: /* Set 100Mb/s */
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
......@@ -2840,8 +2828,10 @@ dc21140m_autoconf(struct device *dev)
}
}
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 @@ dc21140m_autoconf(struct device *dev)
}
break;
case NC:
case NC:
if (lp->media != lp->c_media) {
de4x5_dbg_media(dev);
lp->c_media = lp->media;
......@@ -2893,33 +2883,54 @@ dc2114x_autoconf(struct device *dev)
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 @@ dc2114x_autoconf(struct device *dev)
}
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 @@ dc2114x_autoconf(struct device *dev)
}
} /* 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 @@ dc2114x_autoconf(struct device *dev)
}
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 @@ dc2114x_autoconf(struct device *dev)
}
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 @@ dc2114x_autoconf(struct device *dev)
}
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 @@ dc2114x_autoconf(struct device *dev)
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 @@ dc2114x_autoconf(struct device *dev)
}
break;
case _10Mb:
case _10Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_10Mb;
......@@ -3080,7 +3099,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
case _100Mb:
case _100Mb:
next_tick = 3000;
if (!lp->tx_enable) {
SET_100Mb;
......@@ -3096,7 +3115,7 @@ dc2114x_autoconf(struct device *dev)
}
break;
default:
default:
lp->tcount++;
printk("Huh?: media:%02x\n", lp->media);
lp->media = INIT;
......@@ -3466,7 +3485,7 @@ is_anc_capable(struct device *dev)
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 @@ srom_exec(struct device *dev, u_char *p)
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 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
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 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
} 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++) {
......@@ -5498,13 +5519,13 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
/* 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;
......@@ -5515,7 +5536,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
}
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 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
break;
*/
default:
default:
status = -EOPNOTSUPP;
}
......@@ -5766,30 +5787,32 @@ unlink_modules(struct device *p)
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++;
}
......
......@@ -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 */
......
#
# 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 \
......
......@@ -41,7 +41,7 @@ __initfunc(static void copro_timeout(void))
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);
}
......@@ -156,7 +156,7 @@ __initfunc(static void check_popad(void))
* 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
......@@ -202,7 +202,7 @@ __initfunc(static void check_amd_k6(void))
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");
}
}
......
......@@ -74,9 +74,6 @@ extern unsigned int machine_id;
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).
*/
......@@ -166,33 +163,34 @@ struct thread_struct {
#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>
/*
......@@ -35,84 +36,35 @@ __asm__("str %%ax\n\t" \
:"=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" \
......
......@@ -308,6 +308,10 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
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;
}
......
......@@ -14,8 +14,6 @@
#include <stdarg.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......@@ -27,6 +25,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define LOG_BUF_LEN 8192
......
......@@ -851,7 +851,7 @@ static int file_send_actor(read_descriptor_t * desc, const char *area, unsigned
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 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, size_t count)
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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment