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
052a883c
Commit
052a883c
authored
May 17, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/fealnx
into redhat.com:/spare/repo/net-drivers-2.6
parents
bd7b6c43
b173de9e
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
272 additions
and
197 deletions
+272
-197
drivers/net/fealnx.c
drivers/net/fealnx.c
+272
-197
No files found.
drivers/net/fealnx.c
View file @
052a883c
...
...
@@ -84,6 +84,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <asm/processor.h>
/* Processor type for cache alignment. */
#include <asm/bitops.h>
...
...
@@ -233,15 +234,29 @@ enum intr_status_bits {
RxErr
=
0x00000002
,
/* receive error */
};
/* Bits in the NetworkConfig register. */
/* Bits in the NetworkConfig register, W for writing, R for reading */
/* FIXME: some names are invented by me. Marked with (name?) */
/* If you have docs and know bit names, please fix 'em */
enum
rx_mode_bits
{
RxModeMask
=
0xe0
,
PROM
=
0x80
,
/* promiscuous mode */
AB
=
0x40
,
/* accept broadcast */
AM
=
0x20
,
/* accept mutlicast */
ARP
=
0x08
,
/* receive runt pkt */
ALP
=
0x04
,
/* receive long pkt */
SEP
=
0x02
,
/* receive error pkt */
CR_W_ENH
=
0x02000000
,
/* enhanced mode (name?) */
CR_W_FD
=
0x00100000
,
/* full duplex */
CR_W_PS10
=
0x00080000
,
/* 10 mbit */
CR_W_TXEN
=
0x00040000
,
/* tx enable (name?) */
CR_W_PS1000
=
0x00010000
,
/* 1000 mbit */
/* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */
CR_W_RXMODEMASK
=
0x000000e0
,
CR_W_PROM
=
0x00000080
,
/* promiscuous mode */
CR_W_AB
=
0x00000040
,
/* accept broadcast */
CR_W_AM
=
0x00000020
,
/* accept mutlicast */
CR_W_ARP
=
0x00000008
,
/* receive runt pkt */
CR_W_ALP
=
0x00000004
,
/* receive long pkt */
CR_W_SEP
=
0x00000002
,
/* receive error pkt */
CR_W_RXEN
=
0x00000001
,
/* rx enable (unicast?) (name?) */
CR_R_TXSTOP
=
0x04000000
,
/* tx stopped (name?) */
CR_R_FD
=
0x00100000
,
/* full duplex detected */
CR_R_PS10
=
0x00080000
,
/* 10 mbit detected */
CR_R_RXSTOP
=
0x00008000
,
/* rx stopped (name?) */
};
/* The Tulip Rx and Tx buffer descriptors. */
...
...
@@ -375,10 +390,7 @@ enum tx_desc_control_bits {
#define LXT1000_Full 0x200
// 89/12/29 add, for phy specific status register, levelone phy, (end)
/* for 3-in-1 case */
#define PS10 0x00080000
#define FD 0x00100000
#define PS1000 0x00010000
/* for 3-in-1 case, BMCRSR register */
#define LinkIsUp2 0x00040000
/* for PHY */
...
...
@@ -400,6 +412,12 @@ struct netdev_private {
/* Media monitoring timer. */
struct
timer_list
timer
;
/* Reset timer */
struct
timer_list
reset_timer
;
int
reset_timer_armed
;
unsigned
long
crvalue_sv
;
unsigned
long
imrvalue_sv
;
/* Frequently used values: keep some adjacent for cache effect. */
int
flags
;
struct
pci_dev
*
pci_dev
;
...
...
@@ -435,49 +453,44 @@ static int netdev_open(struct net_device *dev);
static
void
getlinktype
(
struct
net_device
*
dev
);
static
void
getlinkstatus
(
struct
net_device
*
dev
);
static
void
netdev_timer
(
unsigned
long
data
);
static
void
reset_timer
(
unsigned
long
data
);
static
void
tx_timeout
(
struct
net_device
*
dev
);
static
void
init_ring
(
struct
net_device
*
dev
);
static
int
start_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
irqreturn_t
intr_handler
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
int
netdev_rx
(
struct
net_device
*
dev
);
static
void
set_rx_mode
(
struct
net_device
*
dev
);
static
void
__set_rx_mode
(
struct
net_device
*
dev
);
static
struct
net_device_stats
*
get_stats
(
struct
net_device
*
dev
);
static
int
mii_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
struct
ethtool_ops
netdev_ethtool_ops
;
static
int
netdev_close
(
struct
net_device
*
dev
);
static
void
reset_rx_descriptors
(
struct
net_device
*
dev
);
static
void
reset_tx_descriptors
(
struct
net_device
*
dev
);
void
stop_nic_t
x
(
long
ioaddr
,
long
crvalue
)
static
void
stop_nic_r
x
(
long
ioaddr
,
long
crvalue
)
{
writel
(
crvalue
&
(
~
0x40000
),
ioaddr
+
TCRRCR
);
/* wait for tx stop */
{
int
i
=
0
,
delay
=
0x1000
;
while
((
!
(
readl
(
ioaddr
+
TCRRCR
)
&
0x04000000
))
&&
(
i
<
delay
))
{
++
i
;
}
int
delay
=
0x1000
;
writel
(
crvalue
&
~
(
CR_W_RXEN
),
ioaddr
+
TCRRCR
);
while
(
--
delay
)
{
if
(
(
readl
(
ioaddr
+
TCRRCR
)
&
CR_R_RXSTOP
)
==
CR_R_RXSTOP
)
break
;
}
}
void
stop_nic_r
x
(
long
ioaddr
,
long
crvalue
)
static
void
stop_nic_rxt
x
(
long
ioaddr
,
long
crvalue
)
{
writel
(
crvalue
&
(
~
0x1
),
ioaddr
+
TCRRCR
);
/* wait for rx stop */
{
int
i
=
0
,
delay
=
0x1000
;
while
((
!
(
readl
(
ioaddr
+
TCRRCR
)
&
0x00008000
))
&&
(
i
<
delay
))
{
++
i
;
}
int
delay
=
0x1000
;
writel
(
crvalue
&
~
(
CR_W_RXEN
+
CR_W_TXEN
),
ioaddr
+
TCRRCR
);
while
(
--
delay
)
{
if
(
(
readl
(
ioaddr
+
TCRRCR
)
&
(
CR_R_RXSTOP
+
CR_R_TXSTOP
))
==
(
CR_R_RXSTOP
+
CR_R_TXSTOP
)
)
break
;
}
}
static
int
__devinit
fealnx_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
...
...
@@ -495,7 +508,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#ifndef MODULE
static
int
printed_version
;
if
(
!
printed_version
++
)
printk
(
version
);
printk
(
version
);
#endif
card_idx
++
;
...
...
@@ -622,7 +635,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np
->
phys
[
0
]
=
32
;
/* 89/6/23 add, (begin) */
/* get phy type */
if
(
readl
(
dev
->
base_
addr
+
PHYIDENTIFIER
)
==
MysonPHYID
)
if
(
readl
(
io
addr
+
PHYIDENTIFIER
)
==
MysonPHYID
)
np
->
PHYType
=
MysonPHY
;
else
np
->
PHYType
=
OtherPHY
;
...
...
@@ -657,7 +670,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if
(
np
->
flags
==
HAS_MII_XCVR
)
mdio_write
(
dev
,
np
->
phys
[
0
],
MII_ADVERTISE
,
ADVERTISE_FULL
);
else
writel
(
ADVERTISE_FULL
,
dev
->
base_
addr
+
ANARANLPAR
);
writel
(
ADVERTISE_FULL
,
io
addr
+
ANARANLPAR
);
np
->
mii
.
force_media
=
1
;
}
...
...
@@ -669,7 +682,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
dev
->
set_multicast_list
=
&
set_rx_mode
;
dev
->
do_ioctl
=
&
mii_ioctl
;
dev
->
ethtool_ops
=
&
netdev_ethtool_ops
;
dev
->
tx_timeout
=
tx_timeout
;
dev
->
tx_timeout
=
&
tx_timeout
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
err
=
register_netdev
(
dev
);
...
...
@@ -699,6 +712,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
return
err
;
}
static
void
__devexit
fealnx_remove_one
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
...
...
@@ -721,42 +735,6 @@ static void __devexit fealnx_remove_one(struct pci_dev *pdev)
printk
(
KERN_ERR
"fealnx: remove for unknown device
\n
"
);
}
unsigned
int
m80x_read_tick
(
void
)
/* function: Reads the Timer tick count register which decrements by 2 from */
/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. */
/* input : none. */
/* output : none. */
{
unsigned
char
tmp
;
int
value
;
writeb
((
char
)
0x06
,
0x43
);
// Command 8254 to latch T0's count
// now read the count.
tmp
=
(
unsigned
char
)
readb
(
0x40
);
value
=
((
int
)
tmp
)
<<
8
;
tmp
=
(
unsigned
char
)
readb
(
0x40
);
value
|=
(((
int
)
tmp
)
&
0xff
);
return
(
value
);
}
void
m80x_delay
(
unsigned
int
interval
)
/* function: to wait for a specified time. */
/* input : interval ... the specified time. */
/* output : none. */
{
unsigned
int
interval1
,
interval2
,
i
=
0
;
interval1
=
m80x_read_tick
();
// get initial value
do
{
interval2
=
m80x_read_tick
();
if
(
interval1
<
interval2
)
interval1
=
interval2
;
++
i
;
}
while
(((
interval1
-
interval2
)
<
(
ushort
)
interval
)
&&
(
i
<
65535
));
}
static
ulong
m80x_send_cmd_to_phy
(
long
miiport
,
int
opcode
,
int
phyad
,
int
regad
)
{
...
...
@@ -796,7 +774,7 @@ static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad
/* high MDC */
miir
|=
MASK_MIIR_MII_MDC
;
writel
(
miir
,
miiport
);
m80x_
delay
(
30
);
u
delay
(
30
);
/* next */
mask
>>=
1
;
...
...
@@ -831,7 +809,7 @@ static int mdio_read(struct net_device *dev, int phyad, int regad)
/* high MDC, and wait */
miir
|=
MASK_MIIR_MII_MDC
;
writel
(
miir
,
miiport
);
m80x_delay
((
int
)
30
);
udelay
(
30
);
/* next */
mask
>>=
1
;
...
...
@@ -873,8 +851,6 @@ static void mdio_write(struct net_device *dev, int phyad, int regad, int data)
/* low MDC */
miir
&=
~
MASK_MIIR_MII_MDC
;
writel
(
miir
,
miiport
);
return
;
}
...
...
@@ -949,7 +925,7 @@ static int netdev_open(struct net_device *dev)
np
->
imrvalue
=
TUNF
|
CNTOVF
|
RBU
|
TI
|
RI
;
if
(
np
->
pci_dev
->
device
==
0x891
)
{
np
->
bcrvalue
|=
0x200
;
/* set PROG bit */
np
->
crvalue
|=
0x02000000
;
/* set enhanced bit */
np
->
crvalue
|=
CR_W_ENH
;
/* set enhanced bit */
np
->
imrvalue
|=
ETI
;
}
writel
(
np
->
bcrvalue
,
ioaddr
+
BCR
);
...
...
@@ -957,7 +933,7 @@ static int netdev_open(struct net_device *dev)
if
(
dev
->
if_port
==
0
)
dev
->
if_port
=
np
->
default_port
;
writel
(
0
,
dev
->
base_
addr
+
RXPDR
);
writel
(
0
,
io
addr
+
RXPDR
);
// 89/9/1 modify,
// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */
np
->
crvalue
|=
0x00e40001
;
/* tx store and forward, tx/rx enable */
...
...
@@ -965,7 +941,7 @@ static int netdev_open(struct net_device *dev)
getlinkstatus
(
dev
);
if
(
np
->
linkok
)
getlinktype
(
dev
);
set_rx_mode
(
dev
);
__
set_rx_mode
(
dev
);
netif_start_queue
(
dev
);
...
...
@@ -985,6 +961,11 @@ static int netdev_open(struct net_device *dev)
/* timer handler */
add_timer
(
&
np
->
timer
);
init_timer
(
&
np
->
reset_timer
);
np
->
reset_timer
.
data
=
(
unsigned
long
)
dev
;
np
->
reset_timer
.
function
=
&
reset_timer
;
np
->
reset_timer_armed
=
0
;
return
0
;
}
...
...
@@ -1005,8 +986,7 @@ static void getlinkstatus(struct net_device *dev)
np
->
linkok
=
1
;
return
;
}
// delay
m80x_delay
(
100
);
udelay
(
100
);
}
}
else
{
for
(
i
=
0
;
i
<
DelayTime
;
++
i
)
{
...
...
@@ -1014,8 +994,7 @@ static void getlinkstatus(struct net_device *dev)
np
->
linkok
=
1
;
return
;
}
// delay
m80x_delay
(
100
);
udelay
(
100
);
}
}
}
...
...
@@ -1026,11 +1005,11 @@ static void getlinktype(struct net_device *dev)
struct
netdev_private
*
np
=
dev
->
priv
;
if
(
np
->
PHYType
==
MysonPHY
)
{
/* 3-in-1 case */
if
(
readl
(
dev
->
base_addr
+
TCRRCR
)
&
FD
)
if
(
readl
(
dev
->
base_addr
+
TCRRCR
)
&
CR_R_
FD
)
np
->
duplexmode
=
2
;
/* full duplex */
else
np
->
duplexmode
=
1
;
/* half duplex */
if
(
readl
(
dev
->
base_addr
+
TCRRCR
)
&
PS10
)
if
(
readl
(
dev
->
base_addr
+
TCRRCR
)
&
CR_R_
PS10
)
np
->
line_speed
=
1
;
/* 10M */
else
np
->
line_speed
=
2
;
/* 100M */
...
...
@@ -1112,19 +1091,18 @@ static void getlinktype(struct net_device *dev)
else
np
->
line_speed
=
1
;
/* 10M */
}
// chage crvalue
// np->crvalue&=(~PS10)&(~FD);
np
->
crvalue
&=
(
~
PS10
)
&
(
~
FD
)
&
(
~
PS1000
);
np
->
crvalue
&=
(
~
CR_W_PS10
)
&
(
~
CR_W_FD
)
&
(
~
CR_W_PS1000
);
if
(
np
->
line_speed
==
1
)
np
->
crvalue
|=
PS10
;
np
->
crvalue
|=
CR_W_
PS10
;
else
if
(
np
->
line_speed
==
3
)
np
->
crvalue
|=
PS1000
;
np
->
crvalue
|=
CR_W_
PS1000
;
if
(
np
->
duplexmode
==
2
)
np
->
crvalue
|=
FD
;
np
->
crvalue
|=
CR_W_
FD
;
}
}
/* Take lock before calling this */
static
void
allocate_rx_buffers
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
...
...
@@ -1134,15 +1112,17 @@ static void allocate_rx_buffers(struct net_device *dev)
struct
sk_buff
*
skb
;
skb
=
dev_alloc_skb
(
np
->
rx_buf_sz
);
np
->
lack_rxbuf
->
skbuff
=
skb
;
if
(
skb
==
NULL
)
break
;
/* Better luck next round. */
while
(
np
->
lack_rxbuf
->
skbuff
)
np
->
lack_rxbuf
=
np
->
lack_rxbuf
->
next_desc_logical
;
skb
->
dev
=
dev
;
/* Mark as being used by this device. */
np
->
lack_rxbuf
->
skbuff
=
skb
;
np
->
lack_rxbuf
->
buffer
=
pci_map_single
(
np
->
pci_dev
,
skb
->
tail
,
np
->
rx_buf_sz
,
PCI_DMA_FROMDEVICE
);
np
->
lack_rxbuf
=
np
->
lack_rxbuf
->
next_desc_logical
;
np
->
lack_rxbuf
->
status
=
RXOWN
;
++
np
->
really_rx_count
;
}
}
...
...
@@ -1153,22 +1133,23 @@ static void netdev_timer(unsigned long data)
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
int
next_tick
=
10
*
HZ
;
int
old_crvalue
=
np
->
crvalue
;
unsigned
int
old_linkok
=
np
->
linkok
;
unsigned
long
flags
;
if
(
debug
)
printk
(
KERN_DEBUG
"%s: Media selection timer tick, status %8.8x "
"config %8.8x.
\n
"
,
dev
->
name
,
readl
(
ioaddr
+
ISR
),
readl
(
ioaddr
+
TCRRCR
));
spin_lock_irqsave
(
&
np
->
lock
,
flags
);
if
(
np
->
flags
==
HAS_MII_XCVR
)
{
getlinkstatus
(
dev
);
if
((
old_linkok
==
0
)
&&
(
np
->
linkok
==
1
))
{
/* we need to detect the media type again */
getlinktype
(
dev
);
if
(
np
->
crvalue
!=
old_crvalue
)
{
stop_nic_tx
(
ioaddr
,
np
->
crvalue
);
stop_nic_rx
(
ioaddr
,
np
->
crvalue
&
(
~
0x40000
));
stop_nic_rxtx
(
ioaddr
,
np
->
crvalue
);
writel
(
np
->
crvalue
,
ioaddr
+
TCRRCR
);
}
}
...
...
@@ -1176,69 +1157,120 @@ static void netdev_timer(unsigned long data)
allocate_rx_buffers
(
dev
);
np
->
timer
.
expires
=
RUN_AT
(
next_tick
);
spin_unlock_irqrestore
(
&
np
->
lock
,
flags
);
np
->
timer
.
expires
=
RUN_AT
(
10
*
HZ
);
add_timer
(
&
np
->
timer
);
}
static
void
tx_timeout
(
struct
net_device
*
dev
)
/* Take lock before calling */
/* Reset chip and disable rx, tx and interrupts */
static
void
reset_and_disable_rxtx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
int
i
;
printk
(
KERN_WARNING
"%s: Transmit timed out, status %8.8x,"
" resetting...
\n
"
,
dev
->
name
,
readl
(
ioaddr
+
ISR
));
{
printk
(
KERN_DEBUG
" Rx ring %p: "
,
np
->
rx_ring
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
printk
(
" %8.8x"
,
(
unsigned
int
)
np
->
rx_ring
[
i
].
status
);
printk
(
"
\n
"
KERN_DEBUG
" Tx ring %p: "
,
np
->
tx_ring
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
printk
(
" %4.4x"
,
np
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
}
/* Reinit. Gross */
int
delay
=
51
;
/* Reset the chip's Tx and Rx processes. */
stop_nic_tx
(
ioaddr
,
0
);
reset_rx_descriptors
(
dev
);
stop_nic_rxtx
(
ioaddr
,
0
);
/* Disable interrupts by clearing the interrupt mask. */
writel
(
0
x0000
,
ioaddr
+
IMR
);
writel
(
0
,
ioaddr
+
IMR
);
/* Reset the chip to erase previous misconfiguration. */
writel
(
0x00000001
,
ioaddr
+
BCR
);
/* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
We surely wait too long (address+data phase). Who cares
? */
for
(
i
=
0
;
i
<
50
;
i
++
)
{
We surely wait too long (address+data phase). Who cares? */
while
(
--
delay
)
{
readl
(
ioaddr
+
BCR
);
rmb
();
}
}
/* Take lock before calling */
/* Restore chip after reset */
static
void
enable_rxtx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
writel
((
np
->
cur_tx
-
np
->
tx_ring
)
*
sizeof
(
struct
fealnx_desc
)
+
np
->
tx_ring_dma
,
ioaddr
+
TXLBA
);
writel
((
np
->
cur_rx
-
np
->
rx_ring
)
*
sizeof
(
struct
fealnx_desc
)
+
np
->
rx_ring_dma
,
ioaddr
+
RXLBA
);
reset_rx_descriptors
(
dev
);
writel
(
np
->
tx_ring_dma
+
((
char
*
)
np
->
cur_tx
-
(
char
*
)
np
->
tx_ring
),
ioaddr
+
TXLBA
);
writel
(
np
->
rx_ring_dma
+
((
char
*
)
np
->
cur_rx
-
(
char
*
)
np
->
rx_ring
),
ioaddr
+
RXLBA
);
writel
(
np
->
bcrvalue
,
ioaddr
+
BCR
);
writel
(
0
,
dev
->
base_addr
+
RXPDR
);
set_rx_mode
(
dev
);
writel
(
0
,
ioaddr
+
RXPDR
);
__set_rx_mode
(
dev
);
/* changes np->crvalue, writes it into TCRRCR */
/* Clear and Enable interrupts by setting the interrupt mask. */
writel
(
FBE
|
TUNF
|
CNTOVF
|
RBU
|
TI
|
RI
,
ioaddr
+
ISR
);
writel
(
np
->
imrvalue
,
ioaddr
+
IMR
);
writel
(
0
,
dev
->
base_addr
+
TXPDR
);
writel
(
0
,
ioaddr
+
TXPDR
);
}
static
void
reset_timer
(
unsigned
long
data
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
netdev_private
*
np
=
dev
->
priv
;
unsigned
long
flags
;
printk
(
KERN_WARNING
"%s: resetting tx and rx machinery
\n
"
,
dev
->
name
);
spin_lock_irqsave
(
&
np
->
lock
,
flags
);
np
->
crvalue
=
np
->
crvalue_sv
;
np
->
imrvalue
=
np
->
imrvalue_sv
;
reset_and_disable_rxtx
(
dev
);
/* works for me without this:
reset_tx_descriptors(dev); */
enable_rxtx
(
dev
);
netif_start_queue
(
dev
);
/* FIXME: or netif_wake_queue(dev); ? */
np
->
reset_timer_armed
=
0
;
spin_unlock_irqrestore
(
&
np
->
lock
,
flags
);
}
static
void
tx_timeout
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
unsigned
long
flags
;
int
i
;
printk
(
KERN_WARNING
"%s: Transmit timed out, status %8.8x,"
" resetting...
\n
"
,
dev
->
name
,
readl
(
ioaddr
+
ISR
));
{
printk
(
KERN_DEBUG
" Rx ring %p: "
,
np
->
rx_ring
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
printk
(
" %8.8x"
,
(
unsigned
int
)
np
->
rx_ring
[
i
].
status
);
printk
(
"
\n
"
KERN_DEBUG
" Tx ring %p: "
,
np
->
tx_ring
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
printk
(
" %4.4x"
,
np
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
}
spin_lock_irqsave
(
&
np
->
lock
,
flags
);
reset_and_disable_rxtx
(
dev
);
reset_tx_descriptors
(
dev
);
enable_rxtx
(
dev
);
spin_unlock_irqrestore
(
&
np
->
lock
,
flags
);
dev
->
trans_start
=
jiffies
;
np
->
stats
.
tx_errors
++
;
return
;
netif_wake_queue
(
dev
);
/* or .._start_.. ?? */
}
...
...
@@ -1251,7 +1283,7 @@ static void init_ring(struct net_device *dev)
/* initialize rx variables */
np
->
rx_buf_sz
=
(
dev
->
mtu
<=
1500
?
PKT_BUF_SZ
:
dev
->
mtu
+
32
);
np
->
cur_rx
=
&
np
->
rx_ring
[
0
];
np
->
lack_rxbuf
=
NULL
;
np
->
lack_rxbuf
=
np
->
rx_ring
;
np
->
really_rx_count
=
0
;
/* initial rx descriptors. */
...
...
@@ -1294,6 +1326,7 @@ static void init_ring(struct net_device *dev)
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
np
->
tx_ring
[
i
].
status
=
0
;
/* do we need np->tx_ring[i].control = XXX; ?? */
np
->
tx_ring
[
i
].
next_desc
=
np
->
tx_ring_dma
+
(
i
+
1
)
*
sizeof
(
struct
fealnx_desc
);
np
->
tx_ring
[
i
].
next_desc_logical
=
&
np
->
tx_ring
[
i
+
1
];
...
...
@@ -1341,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np
->
cur_tx_copy
->
control
|=
(
BPT
<<
TBSShift
);
/* buffer size */
/* for the last descriptor */
next
=
(
struct
fealnx
*
)
np
->
cur_tx_copy
.
next_desc_logical
;
next
=
np
->
cur_tx_copy
->
next_desc_logical
;
next
->
skbuff
=
skb
;
next
->
control
=
TXIC
|
TXLD
|
CRCEnable
|
PADEnable
;
next
->
control
|=
(
skb
->
len
<<
PKTSShift
);
/* pkt size */
...
...
@@ -1383,35 +1416,59 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
void
free_one_rx_descriptor
(
struct
netdev_private
*
np
)
/* Take lock before calling */
/* Chip probably hosed tx ring. Clean up. */
static
void
reset_tx_descriptors
(
struct
net_device
*
dev
)
{
if
(
np
->
really_rx_count
==
RX_RING_SIZE
)
np
->
cur_rx
->
status
=
RXOWN
;
else
{
np
->
lack_rxbuf
->
skbuff
=
np
->
cur_rx
->
skbuff
;
np
->
lack_rxbuf
->
buffer
=
np
->
cur_rx
->
buffer
;
np
->
lack_rxbuf
->
status
=
RXOWN
;
++
np
->
really_rx_count
;
np
->
lack_rxbuf
=
np
->
lack_rxbuf
->
next_desc_logical
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
fealnx_desc
*
cur
;
int
i
;
/* initialize tx variables */
np
->
cur_tx
=
&
np
->
tx_ring
[
0
];
np
->
cur_tx_copy
=
&
np
->
tx_ring
[
0
];
np
->
really_tx_count
=
0
;
np
->
free_tx_count
=
TX_RING_SIZE
;
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
cur
=
&
np
->
tx_ring
[
i
];
if
(
cur
->
skbuff
)
{
pci_unmap_single
(
np
->
pci_dev
,
cur
->
buffer
,
cur
->
skbuff
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb
(
cur
->
skbuff
);
/* or dev_kfree_skb_irq(cur->skbuff); ? */
cur
->
skbuff
=
NULL
;
}
cur
->
status
=
0
;
cur
->
control
=
0
;
/* needed? */
/* probably not needed. We do it for purely paranoid reasons */
cur
->
next_desc
=
np
->
tx_ring_dma
+
(
i
+
1
)
*
sizeof
(
struct
fealnx_desc
);
cur
->
next_desc_logical
=
&
np
->
tx_ring
[
i
+
1
];
}
np
->
cur_rx
=
np
->
cur_rx
->
next_desc_logical
;
/* for the last tx descriptor */
np
->
tx_ring
[
TX_RING_SIZE
-
1
].
next_desc
=
np
->
tx_ring_dma
;
np
->
tx_ring
[
TX_RING_SIZE
-
1
].
next_desc_logical
=
&
np
->
tx_ring
[
0
];
}
void
reset_rx_descriptors
(
struct
net_device
*
dev
)
/* Take lock and stop rx before calling this */
static
void
reset_rx_descriptors
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
stop_nic_rx
(
dev
->
base_addr
,
np
->
crvalue
);
while
(
!
(
np
->
cur_rx
->
status
&
RXOWN
))
free_one_rx_descriptor
(
np
);
struct
fealnx_desc
*
cur
=
np
->
cur_rx
;
int
i
;
allocate_rx_buffers
(
dev
);
writel
(
np
->
rx_ring_dma
+
(
np
->
cur_rx
-
np
->
rx_ring
),
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
if
(
cur
->
skbuff
)
cur
->
status
=
RXOWN
;
cur
=
cur
->
next_desc_logical
;
}
writel
(
np
->
rx_ring_dma
+
((
char
*
)
np
->
cur_rx
-
(
char
*
)
np
->
rx_ring
),
dev
->
base_addr
+
RXLBA
);
writel
(
np
->
crvalue
,
dev
->
base_addr
+
TCRRCR
);
}
...
...
@@ -1421,16 +1478,14 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
,
boguscnt
=
max_interrupt_work
;
long
ioaddr
=
dev
->
base_addr
;
long
boguscnt
=
max_interrupt_work
;
unsigned
int
num_tx
=
0
;
int
handled
=
0
;
spin_lock
(
&
np
->
lock
);
writel
(
0
,
dev
->
base_addr
+
IMR
);
ioaddr
=
dev
->
base_addr
;
np
=
dev
->
priv
;
writel
(
0
,
ioaddr
+
IMR
);
do
{
u32
intr_status
=
readl
(
ioaddr
+
ISR
);
...
...
@@ -1471,8 +1526,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if
(
intr_status
&
(
RI
|
RBU
))
{
if
(
intr_status
&
RI
)
netdev_rx
(
dev
);
else
else
{
stop_nic_rx
(
ioaddr
,
np
->
crvalue
);
reset_rx_descriptors
(
dev
);
writel
(
np
->
crvalue
,
ioaddr
+
TCRRCR
);
}
}
while
(
np
->
really_tx_count
)
{
...
...
@@ -1490,7 +1548,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if
(
tx_status
&
TXOWN
)
break
;
if
(
!
(
np
->
crvalue
&
0x02000000
))
{
if
(
!
(
np
->
crvalue
&
CR_W_ENH
))
{
if
(
tx_status
&
(
CSL
|
LC
|
EC
|
UDF
|
HF
))
{
np
->
stats
.
tx_errors
++
;
if
(
tx_status
&
EC
)
...
...
@@ -1539,7 +1597,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
netif_wake_queue
(
dev
);
/* read transmit status for enhanced mode only */
if
(
np
->
crvalue
&
0x02000000
)
{
if
(
np
->
crvalue
&
CR_W_ENH
)
{
long
data
;
data
=
readl
(
ioaddr
+
TSR
);
...
...
@@ -1552,6 +1610,20 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if
(
--
boguscnt
<
0
)
{
printk
(
KERN_WARNING
"%s: Too much work at interrupt, "
"status=0x%4.4x.
\n
"
,
dev
->
name
,
intr_status
);
if
(
!
np
->
reset_timer_armed
)
{
np
->
reset_timer_armed
=
1
;
np
->
reset_timer
.
expires
=
RUN_AT
(
HZ
/
2
);
add_timer
(
&
np
->
reset_timer
);
stop_nic_rxtx
(
ioaddr
,
0
);
netif_stop_queue
(
dev
);
/* or netif_tx_disable(dev); ?? */
/* Prevent other paths from enabling tx,rx,intrs */
np
->
crvalue_sv
=
np
->
crvalue
;
np
->
imrvalue_sv
=
np
->
imrvalue
;
np
->
crvalue
&=
~
(
CR_W_TXEN
|
CR_W_RXEN
);
/* or simply = 0? */
np
->
imrvalue
=
0
;
}
break
;
}
}
while
(
1
);
...
...
@@ -1580,9 +1652,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
static
int
netdev_rx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
/* If EOP is set on the next entry, it's a new packet. Send it up. */
while
(
!
(
np
->
cur_rx
->
status
&
RXOWN
))
{
while
(
!
(
np
->
cur_rx
->
status
&
RXOWN
)
&&
np
->
cur_rx
->
skbuff
)
{
s32
rx_status
=
np
->
cur_rx
->
status
;
if
(
np
->
really_rx_count
==
0
)
...
...
@@ -1634,11 +1707,20 @@ static int netdev_rx(struct net_device *dev)
np
->
stats
.
rx_length_errors
++
;
/* free all rx descriptors related this long pkt */
for
(
i
=
0
;
i
<
desno
;
++
i
)
free_one_rx_descriptor
(
np
);
for
(
i
=
0
;
i
<
desno
;
++
i
)
{
if
(
!
np
->
cur_rx
->
skbuff
)
{
printk
(
KERN_DEBUG
"%s: I'm scared
\n
"
,
dev
->
name
);
break
;
}
np
->
cur_rx
->
status
=
RXOWN
;
np
->
cur_rx
=
np
->
cur_rx
->
next_desc_logical
;
}
continue
;
}
else
{
/* something error, need to reset this chip */
}
else
{
/* rx error, need to reset this chip */
stop_nic_rx
(
ioaddr
,
np
->
crvalue
);
reset_rx_descriptors
(
dev
);
writel
(
np
->
crvalue
,
ioaddr
+
TCRRCR
);
}
break
;
/* exit the while loop */
}
...
...
@@ -1685,8 +1767,6 @@ static int netdev_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE
);
skb_put
(
skb
=
np
->
cur_rx
->
skbuff
,
pkt_len
);
np
->
cur_rx
->
skbuff
=
NULL
;
if
(
np
->
really_rx_count
==
RX_RING_SIZE
)
np
->
lack_rxbuf
=
np
->
cur_rx
;
--
np
->
really_rx_count
;
}
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
...
...
@@ -1696,24 +1776,7 @@ static int netdev_rx(struct net_device *dev)
np
->
stats
.
rx_bytes
+=
pkt_len
;
}
if
(
np
->
cur_rx
->
skbuff
==
NULL
)
{
struct
sk_buff
*
skb
;
skb
=
dev_alloc_skb
(
np
->
rx_buf_sz
);
if
(
skb
!=
NULL
)
{
skb
->
dev
=
dev
;
/* Mark as being used by this device. */
np
->
cur_rx
->
buffer
=
pci_map_single
(
np
->
pci_dev
,
skb
->
tail
,
np
->
rx_buf_sz
,
PCI_DMA_FROMDEVICE
);
np
->
cur_rx
->
skbuff
=
skb
;
++
np
->
really_rx_count
;
}
}
if
(
np
->
cur_rx
->
skbuff
!=
NULL
)
free_one_rx_descriptor
(
np
);
np
->
cur_rx
=
np
->
cur_rx
->
next_desc_logical
;
}
/* end of while loop */
/* allocate skb for rx buffers */
...
...
@@ -1737,7 +1800,20 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return
&
np
->
stats
;
}
/* for dev->set_multicast_list */
static
void
set_rx_mode
(
struct
net_device
*
dev
)
{
spinlock_t
*
lp
=
&
((
struct
netdev_private
*
)
dev
->
priv
)
->
lock
;
unsigned
long
flags
;
spin_lock_irqsave
(
lp
,
flags
);
__set_rx_mode
(
dev
);
spin_unlock_irqrestore
(
&
lp
,
flags
);
}
/* Take lock before calling */
static
void
__set_rx_mode
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
...
...
@@ -1748,12 +1824,12 @@ static void set_rx_mode(struct net_device *dev)
/* Unconditionally log net taps. */
printk
(
KERN_NOTICE
"%s: Promiscuous mode enabled.
\n
"
,
dev
->
name
);
memset
(
mc_filter
,
0xff
,
sizeof
(
mc_filter
));
rx_mode
=
PROM
|
AB
|
AM
;
rx_mode
=
CR_W_PROM
|
CR_W_AB
|
CR_W_
AM
;
}
else
if
((
dev
->
mc_count
>
multicast_filter_limit
)
||
(
dev
->
flags
&
IFF_ALLMULTI
))
{
/* Too many to match, or accept all multicasts. */
memset
(
mc_filter
,
0xff
,
sizeof
(
mc_filter
));
rx_mode
=
AB
|
AM
;
rx_mode
=
CR_W_AB
|
CR_W_
AM
;
}
else
{
struct
dev_mc_list
*
mclist
;
int
i
;
...
...
@@ -1765,26 +1841,25 @@ static void set_rx_mode(struct net_device *dev)
bit
=
(
ether_crc
(
ETH_ALEN
,
mclist
->
dmi_addr
)
>>
26
)
^
0x3F
;
mc_filter
[
bit
>>
5
]
|=
(
1
<<
bit
);
}
rx_mode
=
AB
|
AM
;
rx_mode
=
CR_W_AB
|
CR_W_
AM
;
}
stop_nic_tx
(
ioaddr
,
np
->
crvalue
);
stop_nic_rx
(
ioaddr
,
np
->
crvalue
&
(
~
0x40000
));
stop_nic_rxtx
(
ioaddr
,
np
->
crvalue
);
writel
(
mc_filter
[
0
],
ioaddr
+
MAR0
);
writel
(
mc_filter
[
1
],
ioaddr
+
MAR1
);
np
->
crvalue
&=
~
RxModeMask
;
np
->
crvalue
&=
~
CR_W_RXMODEMASK
;
np
->
crvalue
|=
rx_mode
;
writel
(
np
->
crvalue
,
ioaddr
+
TCRRCR
);
}
static
void
netdev_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
static
void
netdev_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
version
,
DRV_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
np
->
pci_dev
));
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
version
,
DRV_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
np
->
pci_dev
));
}
static
int
netdev_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
...
...
@@ -1874,10 +1949,10 @@ static int netdev_close(struct net_device *dev)
writel
(
0x0000
,
ioaddr
+
IMR
);
/* Stop the chip's Tx and Rx processes. */
stop_nic_tx
(
ioaddr
,
0
);
stop_nic_rx
(
ioaddr
,
0
);
stop_nic_rxtx
(
ioaddr
,
0
);
del_timer_sync
(
&
np
->
timer
);
del_timer_sync
(
&
np
->
reset_timer
);
free_irq
(
dev
->
irq
,
dev
);
...
...
@@ -1928,7 +2003,7 @@ static int __init fealnx_init(void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
printk
(
version
);
printk
(
version
);
#endif
return
pci_module_init
(
&
fealnx_driver
);
...
...
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