Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
48ccae24
Commit
48ccae24
authored
Oct 27, 2002
by
Alan Cox
Committed by
Linus Torvalds
Oct 27, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] ressurrect the 3c515 driver
parent
0bd4095a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
62 additions
and
89 deletions
+62
-89
drivers/net/3c515.c
drivers/net/3c515.c
+62
-89
No files found.
drivers/net/3c515.c
View file @
48ccae24
/* 3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux. */
/*
Written 1997-1998 by Donald Becker.
...
...
@@ -13,17 +13,19 @@
Annapolis MD 21403
2
/2/00
- Added support for kernel-level ISAPnP
2
000/2/2
- Added support for kernel-level ISAPnP
by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
11/17/2001 - Added ethtool support (jgarzik)
2001/11/17 - Added ethtool support (jgarzik)
2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
*/
#define DRV_NAME "3c515"
#define DRV_VERSION "0.99t"
#define DRV_RELDATE "
17-Nov-2001
"
#define DRV_VERSION "0.99t
-ac
"
#define DRV_RELDATE "
28-Oct-2002
"
static
char
*
version
=
DRV_NAME
".c:v"
DRV_VERSION
" "
DRV_RELDATE
" becker@scyld.com and others
\n
"
;
...
...
@@ -84,12 +86,6 @@ static int max_interrupt_work = 20;
#define NEW_MULTICAST
#include <linux/delay.h>
/* Kernel version compatibility functions. */
#define RUN_AT(x) (jiffies + (x))
#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
MODULE_AUTHOR
(
"Donald Becker <becker@scyld.com>"
);
MODULE_DESCRIPTION
(
"3Com 3c515 Corkscrew driver"
);
MODULE_LICENSE
(
"GPL"
);
...
...
@@ -202,16 +198,13 @@ of 1.5K, but the changes to support 4.5K are minimal.
enum
corkscrew_cmd
{
TotalReset
=
0
<<
11
,
SelectWindow
=
1
<<
11
,
StartCoax
=
2
<<
11
,
RxDisable
=
3
<<
11
,
RxEnable
=
4
<<
11
,
RxReset
=
5
<<
11
,
UpStall
=
6
<<
11
,
UpUnstall
=
(
6
<<
11
)
+
1
,
DownStall
=
(
6
<<
11
)
+
2
,
DownUnstall
=
(
6
<<
11
)
+
3
,
RxDiscard
=
8
<<
11
,
TxEnable
=
9
<<
11
,
TxDisable
=
10
<<
11
,
TxReset
=
11
<<
11
,
FakeIntr
=
12
<<
11
,
AckIntr
=
13
<<
11
,
SetIntrEnb
=
14
<<
11
,
SetStatusEnb
=
15
<<
11
,
SetRxFilter
=
16
<<
11
,
SetRxThreshold
=
17
<<
11
,
SetTxThreshold
=
18
<<
11
,
SetTxStart
=
19
<<
11
,
StartDMAUp
=
20
<<
11
,
StartDMADown
=
(
20
<<
11
)
+
1
,
StatsEnable
=
21
<<
11
,
UpStall
=
6
<<
11
,
UpUnstall
=
(
6
<<
11
)
+
1
,
DownStall
=
(
6
<<
11
)
+
2
,
DownUnstall
=
(
6
<<
11
)
+
3
,
RxDiscard
=
8
<<
11
,
TxEnable
=
9
<<
11
,
TxDisable
=
10
<<
11
,
TxReset
=
11
<<
11
,
FakeIntr
=
12
<<
11
,
AckIntr
=
13
<<
11
,
SetIntrEnb
=
14
<<
11
,
SetStatusEnb
=
15
<<
11
,
SetRxFilter
=
16
<<
11
,
SetRxThreshold
=
17
<<
11
,
SetTxThreshold
=
18
<<
11
,
SetTxStart
=
19
<<
11
,
StartDMAUp
=
20
<<
11
,
StartDMADown
=
(
20
<<
11
)
+
1
,
StatsEnable
=
21
<<
11
,
StatsDisable
=
22
<<
11
,
StopCoax
=
23
<<
11
,
};
...
...
@@ -265,11 +258,9 @@ enum Window3 { /* Window 3: MAC/config bits. */
union
wn3_config
{
int
i
;
struct
w3_config_fields
{
unsigned
int
ram_size
:
3
,
ram_width
:
1
,
ram_speed
:
2
,
rom_size:
2
;
unsigned
int
ram_size
:
3
,
ram_width
:
1
,
ram_speed
:
2
,
rom_size
:
2
;
int
pad8
:
8
;
unsigned
int
ram_split
:
2
,
pad18
:
2
,
xcvr
:
3
,
pad21
:
1
,
autoselect:
1
;
unsigned
int
ram_split
:
2
,
pad18
:
2
,
xcvr
:
3
,
pad21
:
1
,
autoselect
:
1
;
int
pad24
:
7
;
}
u
;
};
...
...
@@ -340,14 +331,14 @@ struct corkscrew_private {
full_duplex:
1
,
autoselect
:
1
,
bus_master
:
1
,
/* Vortex can only do a fragment bus-m. */
full_bus_master_tx:
1
,
full_bus_master_rx
:
1
,
/* Boomerang */
tx_full:
1
;
spinlock_t
lock
;
};
/* The action to take with a media selection timer tick.
Note that we deviate from the 3Com order by checking 10base2 before AUI.
*/
enum
xcvr_types
{
XCVR_10baseT
=
0
,
XCVR_AUI
,
XCVR_10baseTOnly
,
XCVR_10base2
,
XCVR_100baseTx
,
XCVR_10baseT
=
0
,
XCVR_AUI
,
XCVR_10baseTOnly
,
XCVR_10base2
,
XCVR_100baseTx
,
XCVR_100baseFx
,
XCVR_MII
=
6
,
XCVR_Default
=
8
,
};
...
...
@@ -577,27 +568,23 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
#ifdef MODULE
/* Allocate and fill new device structure. */
int
dev_size
=
sizeof
(
struct
net_device
)
+
sizeof
(
struct
corkscrew_private
)
+
15
;
/* Pad for alignment */
int
dev_size
=
sizeof
(
struct
net_device
)
+
sizeof
(
struct
corkscrew_private
)
+
15
;
/* Pad for alignment */
dev
=
(
struct
net_device
*
)
kmalloc
(
dev_size
,
GFP_KERNEL
);
if
(
!
dev
)
return
NULL
;
memset
(
dev
,
0
,
dev_size
);
/* Align the Rx and Tx ring entries. */
dev
->
priv
=
(
void
*
)
(((
long
)
dev
+
sizeof
(
struct
net_device
)
+
15
)
&
~
15
);
dev
->
priv
=
(
void
*
)
(((
long
)
dev
+
sizeof
(
struct
net_device
)
+
15
)
&
~
15
);
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
dev
->
base_addr
=
ioaddr
;
dev
->
irq
=
irq
;
dev
->
dma
=
(
product_index
==
CORKSCREW_ID
?
inw
(
ioaddr
+
0x2000
)
&
7
:
0
);
dev
->
dma
=
(
product_index
==
CORKSCREW_ID
?
inw
(
ioaddr
+
0x2000
)
&
7
:
0
);
dev
->
init
=
corkscrew_probe1
;
vp
->
product_name
=
"3c515"
;
vp
->
options
=
options
;
if
(
options
>=
0
)
{
vp
->
media_override
=
((
options
&
7
)
==
2
)
?
0
:
options
&
7
;
vp
->
media_override
=
((
options
&
7
)
==
2
)
?
0
:
options
&
7
;
vp
->
full_duplex
=
(
options
&
8
)
?
1
:
0
;
vp
->
bus_master
=
(
options
&
16
)
?
1
:
0
;
}
else
{
...
...
@@ -615,22 +602,19 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
}
#else
/* not a MODULE */
/* Caution: quad-word alignment required for rings! */
dev
->
priv
=
kmalloc
(
sizeof
(
struct
corkscrew_private
),
GFP_KERNEL
);
dev
->
priv
=
kmalloc
(
sizeof
(
struct
corkscrew_private
),
GFP_KERNEL
);
if
(
!
dev
->
priv
)
return
NULL
;
memset
(
dev
->
priv
,
0
,
sizeof
(
struct
corkscrew_private
));
dev
=
init_etherdev
(
dev
,
sizeof
(
struct
corkscrew_private
));
dev
->
base_addr
=
ioaddr
;
dev
->
irq
=
irq
;
dev
->
dma
=
(
product_index
==
CORKSCREW_ID
?
inw
(
ioaddr
+
0x2000
)
&
7
:
0
);
dev
->
dma
=
(
product_index
==
CORKSCREW_ID
?
inw
(
ioaddr
+
0x2000
)
&
7
:
0
);
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
vp
->
product_name
=
"3c515"
;
vp
->
options
=
options
;
if
(
options
>=
0
)
{
vp
->
media_override
=
((
options
&
7
)
==
2
)
?
0
:
options
&
7
;
vp
->
media_override
=
((
options
&
7
)
==
2
)
?
0
:
options
&
7
;
vp
->
full_duplex
=
(
options
&
8
)
?
1
:
0
;
vp
->
bus_master
=
(
options
&
16
)
?
1
:
0
;
}
else
{
...
...
@@ -647,14 +631,14 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
static
int
corkscrew_probe1
(
struct
net_device
*
dev
)
{
int
ioaddr
=
dev
->
base_addr
;
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
unsigned
int
eeprom
[
0x40
],
checksum
=
0
;
/* EEPROM contents */
int
i
;
printk
(
KERN_INFO
"%s: 3Com %s at %#3x,"
,
dev
->
name
,
vp
->
product_name
,
ioaddr
);
printk
(
KERN_INFO
"%s: 3Com %s at %#3x,"
,
dev
->
name
,
vp
->
product_name
,
ioaddr
);
spin_lock_init
(
&
vp
->
lock
);
/* Read the station address from the EEPROM. */
EL3WINDOW
(
0
);
for
(
i
=
0
;
i
<
0x18
;
i
++
)
{
...
...
@@ -769,7 +753,7 @@ static int corkscrew_open(struct net_device *dev)
dev
->
name
,
media_tbl
[
dev
->
if_port
].
name
);
init_timer
(
&
vp
->
timer
);
vp
->
timer
.
expires
=
RUN_AT
(
media_tbl
[
dev
->
if_port
].
wait
)
;
vp
->
timer
.
expires
=
jiffies
+
media_tbl
[
dev
->
if_port
].
wait
;
vp
->
timer
.
data
=
(
unsigned
long
)
dev
;
vp
->
timer
.
function
=
&
corkscrew_timer
;
/* timer handler */
add_timer
(
&
vp
->
timer
);
...
...
@@ -907,8 +891,7 @@ static void corkscrew_timer(unsigned long data)
{
#ifdef AUTOMEDIA
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
int
ioaddr
=
dev
->
base_addr
;
unsigned
long
flags
;
int
ok
=
0
;
...
...
@@ -917,8 +900,9 @@ static void corkscrew_timer(unsigned long data)
printk
(
"%s: Media selection timer tick happened, %s.
\n
"
,
dev
->
name
,
media_tbl
[
dev
->
if_port
].
name
);
save_flags
(
flags
);
cli
();
{
spin_lock_irqsave
(
&
vp
->
lock
,
flags
);
{
int
old_window
=
inw
(
ioaddr
+
EL3_CMD
)
>>
13
;
int
media_status
;
EL3WINDOW
(
4
);
...
...
@@ -969,7 +953,7 @@ static void corkscrew_timer(unsigned long data)
printk
(
"%s: Media selection failed, now trying %s port.
\n
"
,
dev
->
name
,
media_tbl
[
dev
->
if_port
].
name
);
vp
->
timer
.
expires
=
RUN_AT
(
media_tbl
[
dev
->
if_port
].
wait
)
;
vp
->
timer
.
expires
=
jiffies
+
media_tbl
[
dev
->
if_port
].
wait
;
add_timer
(
&
vp
->
timer
);
}
outw
((
media_status
&
~
(
Media_10TP
|
Media_SQE
))
|
...
...
@@ -986,7 +970,8 @@ static void corkscrew_timer(unsigned long data)
}
EL3WINDOW
(
old_window
);
}
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
vp
->
lock
,
flags
);
if
(
corkscrew_debug
>
1
)
printk
(
"%s: Media selection timer finished, %s.
\n
"
,
dev
->
name
,
media_tbl
[
dev
->
if_port
].
name
);
...
...
@@ -1055,8 +1040,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
if
(
vp
->
tx_full
)
/* No room to transmit with */
return
1
;
if
(
vp
->
cur_tx
!=
0
)
prev_entry
=
&
vp
->
tx_ring
[(
vp
->
cur_tx
-
1
)
%
TX_RING_SIZE
];
prev_entry
=
&
vp
->
tx_ring
[(
vp
->
cur_tx
-
1
)
%
TX_RING_SIZE
];
else
prev_entry
=
NULL
;
if
(
corkscrew_debug
>
3
)
...
...
@@ -1069,23 +1053,21 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
vp
->
tx_ring
[
entry
].
length
=
skb
->
len
|
0x80000000
;
vp
->
tx_ring
[
entry
].
status
=
skb
->
len
|
0x80000000
;
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
vp
->
lock
,
flags
);
outw
(
DownStall
,
ioaddr
+
EL3_CMD
);
/* Wait for the stall to complete. */
for
(
i
=
20
;
i
>=
0
;
i
--
)
if
((
inw
(
ioaddr
+
EL3_STATUS
)
&
CmdInProgress
)
==
0
)
break
;
if
((
inw
(
ioaddr
+
EL3_STATUS
)
&
CmdInProgress
)
==
0
)
break
;
if
(
prev_entry
)
prev_entry
->
next
=
isa_virt_to_bus
(
&
vp
->
tx_ring
[
entry
]);
prev_entry
->
next
=
isa_virt_to_bus
(
&
vp
->
tx_ring
[
entry
]);
if
(
inl
(
ioaddr
+
DownListPtr
)
==
0
)
{
outl
(
isa_virt_to_bus
(
&
vp
->
tx_ring
[
entry
]),
ioaddr
+
DownListPtr
);
queued_packet
++
;
}
outw
(
DownUnstall
,
ioaddr
+
EL3_CMD
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
vp
->
lock
,
flags
);
vp
->
cur_tx
++
;
if
(
vp
->
cur_tx
-
vp
->
dirty_tx
>
TX_RING_SIZE
-
1
)
...
...
@@ -1179,6 +1161,8 @@ static void corkscrew_interrupt(int irq, void *dev_id,
latency
=
inb
(
ioaddr
+
Timer
);
lp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
spin_lock
(
&
lp
->
lock
);
status
=
inw
(
ioaddr
+
EL3_STATUS
);
if
(
corkscrew_debug
>
4
)
...
...
@@ -1193,6 +1177,7 @@ static void corkscrew_interrupt(int irq, void *dev_id,
printk
(
KERN_ERR
"%s: Bogus interrupt, bailing. Status %4.4x, start=%d.
\n
"
,
dev
->
name
,
status
,
netif_running
(
dev
));
free_irq
(
dev
->
irq
,
dev
);
dev
->
irq
=
-
1
;
}
}
...
...
@@ -1205,8 +1190,7 @@ static void corkscrew_interrupt(int irq, void *dev_id,
if
(
status
&
TxAvailable
)
{
if
(
corkscrew_debug
>
5
)
printk
(
" TX room bit was handled.
\n
"
);
printk
(
" TX room bit was handled.
\n
"
);
/* There's room in the FIFO for a full-sized packet. */
outw
(
AckIntr
|
TxAvailable
,
ioaddr
+
EL3_CMD
);
netif_wake_queue
(
dev
);
...
...
@@ -1216,21 +1200,17 @@ static void corkscrew_interrupt(int irq, void *dev_id,
while
(
lp
->
cur_tx
-
dirty_tx
>
0
)
{
int
entry
=
dirty_tx
%
TX_RING_SIZE
;
if
(
inl
(
ioaddr
+
DownListPtr
)
==
isa_virt_to_bus
(
&
lp
->
tx_ring
[
entry
]))
if
(
inl
(
ioaddr
+
DownListPtr
)
==
isa_virt_to_bus
(
&
lp
->
tx_ring
[
entry
]))
break
;
/* It still hasn't been processed. */
if
(
lp
->
tx_skbuff
[
entry
])
{
dev_kfree_skb_irq
(
lp
->
tx_skbuff
[
entry
]);
dev_kfree_skb_irq
(
lp
->
tx_skbuff
[
entry
]);
lp
->
tx_skbuff
[
entry
]
=
0
;
}
dirty_tx
++
;
}
lp
->
dirty_tx
=
dirty_tx
;
outw
(
AckIntr
|
DownComplete
,
ioaddr
+
EL3_CMD
);
if
(
lp
->
tx_full
&&
(
lp
->
cur_tx
-
dirty_tx
<=
TX_RING_SIZE
-
1
))
{
if
(
lp
->
tx_full
&&
(
lp
->
cur_tx
-
dirty_tx
<=
TX_RING_SIZE
-
1
))
{
lp
->
tx_full
=
0
;
netif_wake_queue
(
dev
);
}
...
...
@@ -1255,23 +1235,19 @@ static void corkscrew_interrupt(int irq, void *dev_id,
if
(
status
&
StatsFull
)
{
/* Empty statistics. */
static
int
DoneDidThat
;
if
(
corkscrew_debug
>
4
)
printk
(
"%s: Updating stats.
\n
"
,
dev
->
name
);
printk
(
"%s: Updating stats.
\n
"
,
dev
->
name
);
update_stats
(
ioaddr
,
dev
);
/* DEBUG HACK: Disable statistics as an interrupt source. */
/* This occurs when we have the wrong media type! */
if
(
DoneDidThat
==
0
&&
inw
(
ioaddr
+
EL3_STATUS
)
&
StatsFull
)
{
if
(
DoneDidThat
==
0
&&
inw
(
ioaddr
+
EL3_STATUS
)
&
StatsFull
)
{
int
win
,
reg
;
printk
(
"%s: Updating stats failed, disabling stats as an"
" interrupt source.
\n
"
,
dev
->
name
);
" interrupt source.
\n
"
,
dev
->
name
);
for
(
win
=
0
;
win
<
8
;
win
++
)
{
EL3WINDOW
(
win
);
printk
(
"
\n
Vortex window %d:"
,
win
);
for
(
reg
=
0
;
reg
<
16
;
reg
++
)
printk
(
" %2.2x"
,
inb
(
ioaddr
+
reg
));
printk
(
" %2.2x"
,
inb
(
ioaddr
+
reg
));
}
EL3WINDOW
(
7
);
outw
(
SetIntrEnb
|
TxAvailable
|
...
...
@@ -1297,20 +1273,19 @@ static void corkscrew_interrupt(int irq, void *dev_id,
"Disabling functions (%4.4x).
\n
"
,
dev
->
name
,
status
,
SetStatusEnb
|
((
~
status
)
&
0x7FE
));
/* Disable all pending interrupts. */
outw
(
SetStatusEnb
|
((
~
status
)
&
0x7FE
),
ioaddr
+
EL3_CMD
);
outw
(
SetStatusEnb
|
((
~
status
)
&
0x7FE
),
ioaddr
+
EL3_CMD
);
outw
(
AckIntr
|
0x7FF
,
ioaddr
+
EL3_CMD
);
break
;
}
/* Acknowledge the IRQ. */
outw
(
AckIntr
|
IntReq
|
IntLatch
,
ioaddr
+
EL3_CMD
);
}
while
((
status
=
inw
(
ioaddr
+
EL3_STATUS
))
&
(
IntLatch
|
RxComplete
));
}
while
((
status
=
inw
(
ioaddr
+
EL3_STATUS
))
&
(
IntLatch
|
RxComplete
));
spin_unlock
(
&
lp
->
lock
);
if
(
corkscrew_debug
>
4
)
printk
(
"%s: exiting interrupt, status %4.4x.
\n
"
,
dev
->
name
,
status
);
printk
(
"%s: exiting interrupt, status %4.4x.
\n
"
,
dev
->
name
,
status
);
}
static
int
corkscrew_rx
(
struct
net_device
*
dev
)
...
...
@@ -1529,15 +1504,13 @@ static int corkscrew_close(struct net_device *dev)
static
struct
net_device_stats
*
corkscrew_get_stats
(
struct
net_device
*
dev
)
{
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
struct
corkscrew_private
*
vp
=
(
struct
corkscrew_private
*
)
dev
->
priv
;
unsigned
long
flags
;
if
(
netif_running
(
dev
))
{
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
vp
->
lock
,
flags
);
update_stats
(
dev
->
base_addr
,
dev
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
vp
->
lock
,
flags
);
}
return
&
vp
->
stats
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment