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
nexedi
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