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
d0051184
Commit
d0051184
authored
Nov 07, 2002
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/home/jgarzik/repo/linus-2.5
into redhat.com:/home/jgarzik/repo/net-drivers-2.5
parents
56c32f41
51449c8c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
370 additions
and
120 deletions
+370
-120
drivers/net/dl2k.c
drivers/net/dl2k.c
+200
-38
drivers/net/dl2k.h
drivers/net/dl2k.h
+2
-0
drivers/net/sundance.c
drivers/net/sundance.c
+168
-82
No files found.
drivers/net/dl2k.c
View file @
d0051184
...
...
@@ -30,17 +30,32 @@
1.09 2002/03/07 Move rx-poll-now to re-fill loop.
Added rio_timer() to watch rx buffers.
1.10 2002/04/16 Fixed miscount of carrier error.
1.11 2002/05/23 Added ISR schedule scheme
.
1.11 2002/05/23 Added ISR schedule scheme
Fixed miscount of rx frame error for DGE-550SX.
Fixed VLAN bug.
1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
*/
1.13 2002/08/13 1. Fix disconnection (many tx:carrier/rx:frame
errs) with some mainboards.
2. Use definition "DRV_NAME" "DRV_VERSION"
"DRV_RELDATE" for flexibility.
1.14 2002/08/14 Support ethtool.
1.15 2002/08/27 Changed the default media to Auto-Negotiation
for the fiber devices.
1.16 2002/09/04 More power down time for fiber devices auto-
negotiation.
Fix disconnect bug after ifup and ifdown.
1.17 2002/10/03 Fix RMON statistics overflow.
Always use I/O mapping to access eeprom,
avoid system freezing with some chipsets.
*/
#define DRV_NAME "D-Link DL2000-based linux driver"
#define DRV_VERSION "v1.17"
#define DRV_RELDATE "2002/10/04"
#include "dl2k.h"
static
char
version
[]
__devinitdata
=
KERN_INFO
"D-Link DL2000-based linux driver v1.12 2002/06/13
\n
"
;
KERN_INFO
DRV_NAME
" "
DRV_VERSION
" "
DRV_RELDATE
"
\n
"
;
#define MAX_UNITS 8
static
int
mtu
[
MAX_UNITS
];
static
int
vlan
[
MAX_UNITS
];
...
...
@@ -92,6 +107,7 @@ static int change_mtu (struct net_device *dev, int new_mtu);
static
void
set_multicast
(
struct
net_device
*
dev
);
static
struct
net_device_stats
*
get_stats
(
struct
net_device
*
dev
);
static
int
clear_stats
(
struct
net_device
*
dev
);
static
int
rio_ethtool_ioctl
(
struct
net_device
*
dev
,
void
*
useraddr
);
static
int
rio_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
int
rio_close
(
struct
net_device
*
dev
);
static
int
find_miiphy
(
struct
net_device
*
dev
);
...
...
@@ -257,12 +273,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np
->
link_status
=
0
;
/* Set media and reset PHY */
if
(
np
->
phy_media
)
{
/* default 1000mbps_fd for fiber deivices */
if
(
np
->
an_enable
==
1
)
{
np
->
an_enable
=
0
;
np
->
speed
=
1000
;
np
->
full_duplex
=
1
;
}
else
if
(
np
->
an_enable
==
2
)
{
/* default Auto-Negotiation for fiber deivices */
if
(
np
->
an_enable
==
2
)
{
np
->
an_enable
=
1
;
}
mii_set_media_pcs
(
dev
);
...
...
@@ -275,10 +287,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
}
pci_read_config_byte
(
pdev
,
PCI_REVISION_ID
,
&
np
->
pci_rev_id
);
/* Reset all logic functions */
writew
(
GlobalReset
|
DMAReset
|
FIFOReset
|
NetworkReset
|
HostReset
,
ioaddr
+
ASICCtrl
+
2
);
err
=
register_netdev
(
dev
);
if
(
err
)
goto
err_out_unmap_rx
;
...
...
@@ -357,11 +365,16 @@ parse_eeprom (struct net_device *dev)
int
cid
,
next
;
#ifdef MEM_MAPPING
ioaddr
=
pci_resource_start
(
np
->
pdev
,
0
);
#endif
/* Read eeprom */
for
(
i
=
0
;
i
<
128
;
i
++
)
{
((
u16
*
)
sromdata
)[
i
]
=
le16_to_cpu
(
read_eeprom
(
ioaddr
,
i
));
}
#ifdef MEM_MAPPING
ioaddr
=
dev
->
base_addr
;
#endif
/* Check CRC */
crc
=
~
ether_crc_le
(
256
-
4
,
sromdata
);
if
(
psrom
->
crc
!=
crc
)
{
...
...
@@ -421,10 +434,17 @@ rio_open (struct net_device *dev)
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
int
i
;
u16
macctrl
;
i
=
request_irq
(
dev
->
irq
,
&
rio_interrupt
,
SA_SHIRQ
,
dev
->
name
,
dev
);
if
(
i
)
return
i
;
/* Reset all logic functions */
writew
(
GlobalReset
|
DMAReset
|
FIFOReset
|
NetworkReset
|
HostReset
,
ioaddr
+
ASICCtrl
+
2
);
mdelay
(
10
);
/* DebugCtrl bit 4, 5, 9 must set */
writel
(
readl
(
ioaddr
+
DebugCtrl
)
|
0x0230
,
ioaddr
+
DebugCtrl
);
...
...
@@ -448,7 +468,7 @@ rio_open (struct net_device *dev)
writeb
(
0xff
,
ioaddr
+
TxDMAPollPeriod
);
writeb
(
0x30
,
ioaddr
+
RxDMABurstThresh
);
writeb
(
0x30
,
ioaddr
+
RxDMAUrgentThresh
);
writel
(
0x0007ffff
,
ioaddr
+
RmonStatMask
);
/* clear statistics */
clear_stats
(
dev
);
...
...
@@ -467,9 +487,6 @@ rio_open (struct net_device *dev)
ioaddr
+
MACCtrl
);
}
/* Enable default interrupts */
EnableInt
();
init_timer
(
&
np
->
timer
);
np
->
timer
.
expires
=
jiffies
+
1
*
HZ
;
np
->
timer
.
data
=
(
unsigned
long
)
dev
;
...
...
@@ -479,8 +496,18 @@ rio_open (struct net_device *dev)
/* Start Tx/Rx */
writel
(
readl
(
ioaddr
+
MACCtrl
)
|
StatsEnable
|
RxEnable
|
TxEnable
,
ioaddr
+
MACCtrl
);
macctrl
=
0
;
macctrl
|=
(
np
->
vlan
)
?
AutoVLANuntagging
:
0
;
macctrl
|=
(
np
->
full_duplex
)
?
DuplexSelect
:
0
;
macctrl
|=
(
np
->
tx_flow
)
?
TxFlowControlEnable
:
0
;
macctrl
|=
(
np
->
rx_flow
)
?
RxFlowControlEnable
:
0
;
writew
(
macctrl
,
ioaddr
+
MACCtrl
);
netif_start_queue
(
dev
);
/* Enable default interrupts */
EnableInt
();
return
0
;
}
...
...
@@ -626,7 +653,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
}
#endif
if
(
np
->
vlan
)
{
t
xdesc
->
status
|
=
t
fc_vlan_tag
=
cpu_to_le64
(
VLANTagInsert
)
|
(
cpu_to_le64
(
np
->
vlan
)
<<
32
)
|
(
cpu_to_le64
(
skb
->
priority
)
<<
45
);
...
...
@@ -720,9 +747,10 @@ rio_free_tx (struct net_device *dev, int irq)
long
flag
=
0
;
if
(
irq
)
spin_lock_irqsave
(
&
np
->
tx_lock
,
flag
);
else
spin_lock
(
&
np
->
tx_lock
);
else
spin_lock_irqsave
(
&
np
->
tx_lock
,
flag
);
/* Free used tx skbuffs */
while
(
entry
!=
np
->
cur_tx
)
{
struct
sk_buff
*
skb
;
...
...
@@ -743,9 +771,9 @@ rio_free_tx (struct net_device *dev, int irq)
tx_use
++
;
}
if
(
irq
)
spin_unlock_irqrestore
(
&
np
->
tx_lock
,
flag
);
else
spin_unlock
(
&
np
->
tx_lock
);
else
spin_unlock_irqrestore
(
&
np
->
tx_lock
,
flag
);
np
->
old_tx
=
entry
;
/* If the ring is no longer full, clear tx_full and
...
...
@@ -809,8 +837,13 @@ tx_error (struct net_device *dev, int tx_status)
/* Let TxStartThresh stay default value */
}
/* Maximum Collisions */
#ifdef ETHER_STATS
if
(
tx_status
&
0x08
)
np
->
stats
.
collisions16
++
;
#else
if
(
tx_status
&
0x08
)
np
->
stats
.
collisions
++
;
#endif
/* Restart the Tx */
writel
(
readw
(
dev
->
base_addr
+
MACCtrl
)
|
TxEnable
,
ioaddr
+
MACCtrl
);
}
...
...
@@ -1103,6 +1136,7 @@ set_multicast (struct net_device *dev)
u16
rx_mode
=
0
;
int
i
;
int
bit
;
int
index
,
crc
;
struct
dev_mc_list
*
mclist
;
struct
netdev_private
*
np
=
dev
->
priv
;
...
...
@@ -1122,17 +1156,16 @@ set_multicast (struct net_device *dev)
rx_mode
=
ReceiveBroadcast
|
ReceiveMulticastHash
|
ReceiveUnicast
;
for
(
i
=
0
,
mclist
=
dev
->
mc_list
;
mclist
&&
i
<
dev
->
mc_count
;
i
++
,
mclist
=
mclist
->
next
)
{
int
index
=
0
;
int
crc
=
ether_crc_le
(
ETH_ALEN
,
mclist
->
dmi_addr
);
i
++
,
mclist
=
mclist
->
next
)
{
crc
=
ether_crc_le
(
ETH_ALEN
,
mclist
->
dmi_addr
);
/* The inverted high significant 6 bits of CRC are
used as an index to hashtable */
for
(
bit
=
0
;
bit
<
6
;
bit
++
)
if
(
crc
&
(
1
<<
(
31
-
bit
)))
index
|=
(
1
<<
bit
);
for
(
index
=
0
,
bit
=
0
;
bit
<
6
;
bit
++
)
{
if
(
test_bit
(
31
-
bit
,
&
crc
))
{
set_bit
(
bit
,
&
index
);
}
}
hash_table
[
index
/
32
]
|=
(
1
<<
(
index
%
32
));
}
}
else
{
...
...
@@ -1148,6 +1181,132 @@ set_multicast (struct net_device *dev)
writew
(
rx_mode
,
ioaddr
+
ReceiveMode
);
}
static
int
rio_ethtool_ioctl
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
u32
ethcmd
;
if
(
copy_from_user
(
&
ethcmd
,
useraddr
,
sizeof
(
ethcmd
)))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GDRVINFO
:
{
struct
ethtool_drvinfo
info
=
{
ETHTOOL_GDRVINFO
};
strcpy
(
info
.
driver
,
"DL2K"
);
strcpy
(
info
.
version
,
DRV_VERSION
);
strcpy
(
info
.
bus_info
,
np
->
pdev
->
slot_name
);
memset
(
&
info
.
fw_version
,
0
,
sizeof
(
info
.
fw_version
));
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_GSET
:
{
struct
ethtool_cmd
cmd
=
{
ETHTOOL_GSET
};
if
(
np
->
phy_media
)
{
/* fiber device */
cmd
.
supported
=
SUPPORTED_Autoneg
|
SUPPORTED_FIBRE
;
cmd
.
advertising
=
ADVERTISED_Autoneg
|
ADVERTISED_FIBRE
;
cmd
.
port
=
PORT_FIBRE
;
cmd
.
transceiver
=
XCVR_INTERNAL
;
}
else
{
/* copper device */
cmd
.
supported
=
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_1000baseT_Full
|
SUPPORTED_Autoneg
|
SUPPORTED_MII
;
cmd
.
advertising
=
ADVERTISED_10baseT_Half
|
ADVERTISED_10baseT_Full
|
ADVERTISED_100baseT_Half
|
ADVERTISED_100baseT_Full
|
ADVERTISED_1000baseT_Full
|
ADVERTISED_Autoneg
|
ADVERTISED_MII
;
cmd
.
port
=
PORT_MII
;
cmd
.
transceiver
=
XCVR_INTERNAL
;
}
if
(
np
->
link_status
)
{
cmd
.
speed
=
np
->
speed
;
cmd
.
duplex
=
np
->
full_duplex
?
DUPLEX_FULL
:
DUPLEX_HALF
;
}
else
{
cmd
.
speed
=
-
1
;
cmd
.
duplex
=
-
1
;
}
if
(
np
->
an_enable
)
cmd
.
autoneg
=
AUTONEG_ENABLE
;
else
cmd
.
autoneg
=
AUTONEG_DISABLE
;
cmd
.
phy_address
=
np
->
phy_addr
;
if
(
copy_to_user
(
useraddr
,
&
cmd
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SSET
:
{
struct
ethtool_cmd
cmd
;
if
(
copy_from_user
(
&
cmd
,
useraddr
,
sizeof
(
cmd
)))
return
-
EFAULT
;
netif_carrier_off
(
dev
);
if
(
cmd
.
autoneg
==
AUTONEG_ENABLE
)
{
if
(
np
->
an_enable
)
return
0
;
else
{
np
->
an_enable
=
1
;
mii_set_media
(
dev
);
return
0
;
}
}
else
{
np
->
an_enable
=
0
;
if
(
np
->
speed
==
1000
){
cmd
.
speed
=
SPEED_100
;
cmd
.
duplex
=
DUPLEX_FULL
;
printk
(
"Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.
\n
"
);
}
switch
(
cmd
.
speed
+
cmd
.
duplex
){
case
SPEED_10
+
DUPLEX_HALF
:
np
->
speed
=
10
;
np
->
full_duplex
=
0
;
break
;
case
SPEED_10
+
DUPLEX_FULL
:
np
->
speed
=
10
;
np
->
full_duplex
=
1
;
break
;
case
SPEED_100
+
DUPLEX_HALF
:
np
->
speed
=
100
;
np
->
full_duplex
=
0
;
break
;
case
SPEED_100
+
DUPLEX_FULL
:
np
->
speed
=
100
;
np
->
full_duplex
=
1
;
break
;
case
SPEED_1000
+
DUPLEX_HALF
:
/* not supported */
case
SPEED_1000
+
DUPLEX_FULL
:
/* not supported */
default:
return
-
EINVAL
;
}
mii_set_media
(
dev
);
}
return
0
;
}
#ifdef ETHTOOL_GLINK
case
ETHTOOL_GLINK
:{
struct
ethtool_value
link
=
{
ETHTOOL_GLINK
};
link
.
data
=
np
->
link_status
;
if
(
copy_to_user
(
useraddr
,
&
link
,
sizeof
(
link
)))
return
-
EFAULT
;
return
0
;
}
#endif
default:
return
-
EOPNOTSUPP
;
}
}
static
int
rio_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
...
...
@@ -1160,6 +1319,8 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
phy_addr
=
np
->
phy_addr
;
switch
(
cmd
)
{
case
SIOCETHTOOL
:
return
rio_ethtool_ioctl
(
dev
,
(
void
*
)
rq
->
ifr_data
);
case
SIOCDEVPRIVATE
:
break
;
...
...
@@ -1210,14 +1371,15 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
#define EEP_READ 0x0200
#define EEP_BUSY 0x8000
/* Read the EEPROM word */
/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
int
read_eeprom
(
long
ioaddr
,
int
eep_addr
)
{
int
i
=
1000
;
write
w
(
EEP_READ
|
(
eep_addr
&
0xff
),
ioaddr
+
EepromCtrl
);
out
w
(
EEP_READ
|
(
eep_addr
&
0xff
),
ioaddr
+
EepromCtrl
);
while
(
i
--
>
0
)
{
if
(
!
(
read
w
(
ioaddr
+
EepromCtrl
)
&
EEP_BUSY
))
{
return
read
w
(
ioaddr
+
EepromData
);
if
(
!
(
in
w
(
ioaddr
+
EepromCtrl
)
&
EEP_BUSY
))
{
return
in
w
(
ioaddr
+
EepromData
);
}
}
return
0
;
...
...
@@ -1464,7 +1626,7 @@ mii_set_media (struct net_device *dev)
/* 3) Power Down */
bmcr
.
image
=
0x1940
;
/* must be 0x1940 */
mii_write
(
dev
,
phy_addr
,
MII_BMCR
,
bmcr
.
image
);
mdelay
(
10
);
/* wait a certain time */
mdelay
(
10
0
);
/* wait a certain time */
/* 4) Advertise nothing */
mii_write
(
dev
,
phy_addr
,
MII_ANAR
,
0
);
...
...
drivers/net/dl2k.h
View file @
d0051184
...
...
@@ -27,9 +27,11 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <asm/processor.h>
/* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/time.h>
...
...
drivers/net/sundance.c
View file @
d0051184
...
...
@@ -63,14 +63,20 @@
- Better rx buf size calculation (Donald Becker)
Version LK1.05 (D-Link):
- fix DFE-580TX packet drop issue
- fix reset_tx logic
- Fix DFE-580TX packet drop issue (for DL10050C)
- Fix reset_tx logic
Version LK1.06 (D-Link):
- Fix crash while unloading driver
Versin LK1.06b (D-Link):
- New tx scheme, adaptive tx_coalesce
*/
#define DRV_NAME "sundance"
#define DRV_VERSION "1.01+LK1.0
5
"
#define DRV_RELDATE "
28-Sep
-2002"
#define DRV_VERSION "1.01+LK1.0
6b
"
#define DRV_RELDATE "
6-Nov
-2002"
/* The user-configurable values.
...
...
@@ -87,7 +93,6 @@ static int multicast_filter_limit = 32;
This chip can receive into offset buffers, so the Alpha does not
need a copy-align. */
static
int
rx_copybreak
;
static
int
tx_coalesce
=
1
;
static
int
flowctrl
=
1
;
/* media[] specifies the media type the NIC operates at.
...
...
@@ -114,7 +119,7 @@ static char *media[MAX_UNITS];
bonding and packet priority, and more than 128 requires modifying the
Tx error recovery.
Large receive rings merely waste memory. */
#define TX_RING_SIZE
64
#define TX_RING_SIZE
32
#define TX_QUEUE_LEN (TX_RING_SIZE - 1)
/* Limit ring entries actually used. */
#define RX_RING_SIZE 64
#define RX_BUDGET 32
...
...
@@ -459,7 +464,9 @@ struct netdev_private {
unsigned
int
an_enable
:
1
;
unsigned
int
speed
;
struct
tasklet_struct
rx_tasklet
;
struct
tasklet_struct
tx_tasklet
;
int
budget
;
int
cur_task
;
/* Multicast and receive mode. */
spinlock_t
mcastlock
;
/* SMP lock multicast updates. */
u16
mcast_filter
[
4
];
...
...
@@ -468,6 +475,7 @@ struct netdev_private {
int
mii_preamble_required
;
unsigned
char
phys
[
MII_CNT
];
/* MII device addresses, only first one used. */
struct
pci_dev
*
pci_dev
;
unsigned
char
pci_rev_id
;
};
/* The station address location in the EEPROM. */
...
...
@@ -489,6 +497,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev);
static
int
reset_tx
(
struct
net_device
*
dev
);
static
void
intr_handler
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
void
rx_poll
(
unsigned
long
data
);
static
void
tx_poll
(
unsigned
long
data
);
static
void
refill_rx
(
struct
net_device
*
dev
);
static
void
netdev_error
(
struct
net_device
*
dev
,
int
intr_status
);
static
void
netdev_error
(
struct
net_device
*
dev
,
int
intr_status
);
...
...
@@ -557,6 +566,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np
->
msg_enable
=
(
1
<<
debug
)
-
1
;
spin_lock_init
(
&
np
->
lock
);
tasklet_init
(
&
np
->
rx_tasklet
,
rx_poll
,
(
unsigned
long
)
dev
);
tasklet_init
(
&
np
->
tx_tasklet
,
tx_poll
,
(
unsigned
long
)
dev
);
ring_space
=
pci_alloc_consistent
(
pdev
,
TX_TOTAL_SIZE
,
&
ring_dma
);
if
(
!
ring_space
)
...
...
@@ -588,6 +598,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev
->
change_mtu
=
&
change_mtu
;
pci_set_drvdata
(
pdev
,
dev
);
pci_read_config_byte
(
pdev
,
PCI_REVISION_ID
,
&
np
->
pci_rev_id
);
i
=
register_netdev
(
dev
);
if
(
i
)
goto
err_out_unmap_rx
;
...
...
@@ -650,10 +662,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np
->
an_enable
=
1
;
}
}
if
(
tx_coalesce
<
1
)
tx_coalesce
=
1
;
else
if
(
tx_coalesce
>
TX_QUEUE_LEN
-
1
)
tx_coalesce
=
TX_QUEUE_LEN
-
1
;
if
(
flowctrl
==
0
)
np
->
flowctrl
=
0
;
}
...
...
@@ -867,7 +875,8 @@ static int netdev_open(struct net_device *dev)
writeb
(
100
,
ioaddr
+
RxDMAPollPeriod
);
writeb
(
127
,
ioaddr
+
TxDMAPollPeriod
);
/* Fix DFE-580TX packet drop issue */
writeb
(
0x01
,
ioaddr
+
DebugCtrl1
);
if
(
np
->
pci_rev_id
>=
0x14
)
writeb
(
0x01
,
ioaddr
+
DebugCtrl1
);
netif_start_queue
(
dev
);
writew
(
StatsEnable
|
RxEnable
|
TxEnable
,
ioaddr
+
MACCtrl1
);
...
...
@@ -943,7 +952,9 @@ static void tx_timeout(struct net_device *dev)
struct
netdev_private
*
np
=
dev
->
priv
;
long
ioaddr
=
dev
->
base_addr
;
long
flag
;
netif_stop_queue
(
dev
);
tasklet_disable
(
&
np
->
tx_tasklet
);
writew
(
0
,
ioaddr
+
IntrEnable
);
printk
(
KERN_WARNING
"%s: Transmit timed out, TxStatus %2.2x "
"TxFrameId %2.2x,"
...
...
@@ -952,31 +963,39 @@ static void tx_timeout(struct net_device *dev)
{
int
i
;
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
(
" %8.8x"
,
np
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
printk
(
KERN_DEBUG
"cur_tx=%d dirty_tx=%d
\n
"
,
np
->
cur_tx
,
np
->
dirty_tx
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
printk
(
KERN_DEBUG
"%02x %08x %08x %08x(%02x) %08x %08x
\n
"
,
i
,
np
->
tx_ring_dma
+
i
*
sizeof
(
*
np
->
tx_ring
),
np
->
tx_ring
[
i
].
next_desc
,
np
->
tx_ring
[
i
].
status
,
(
np
->
tx_ring
[
i
].
status
>>
2
)
&
0xff
,
np
->
tx_ring
[
i
].
frag
[
0
].
addr
,
np
->
tx_ring
[
i
].
frag
[
0
].
length
);
}
printk
(
KERN_DEBUG
"TxListPtr=%08x netif_queue_stopped=%d
\n
"
,
readl
(
dev
->
base_addr
+
TxListPtr
),
netif_queue_stopped
(
dev
));
printk
(
KERN_DEBUG
"cur_tx=%d(%02x) dirty_tx=%d(%02x)
\n
"
,
np
->
cur_tx
,
np
->
cur_tx
%
TX_RING_SIZE
,
np
->
dirty_tx
,
np
->
dirty_tx
%
TX_RING_SIZE
);
printk
(
KERN_DEBUG
"cur_rx=%d dirty_rx=%d
\n
"
,
np
->
cur_rx
,
np
->
dirty_rx
);
printk
(
KERN_DEBUG
"cur_task=%d
\n
"
,
np
->
cur_task
);
}
spin_lock_irqsave
(
&
np
->
lock
,
flag
);
/* Stop and restart the chip's Tx processes . */
reset_tx
(
dev
);
spin_unlock_irqrestore
(
&
np
->
lock
,
flag
);
/* Perhaps we should reinitialize the hardware here. */
dev
->
if_port
=
0
;
/* Stop and restart the chip's Tx processes . */
/* Trigger an immediate transmit demand. */
writew
(
DEFAULT_INTR
,
ioaddr
+
IntrEnable
);
dev
->
trans_start
=
jiffies
;
np
->
stats
.
tx_errors
++
;
if
(
!
netif_queue_stopped
(
dev
))
if
(
np
->
cur_tx
-
np
->
dirty_tx
<
TX_QUEUE_LEN
-
4
)
{
netif_wake_queue
(
dev
);
}
writew
(
DEFAULT_INTR
,
ioaddr
+
IntrEnable
);
tasklet_enable
(
&
np
->
tx_tasklet
);
}
...
...
@@ -988,6 +1007,7 @@ static void init_ring(struct net_device *dev)
np
->
cur_rx
=
np
->
cur_tx
=
0
;
np
->
dirty_rx
=
np
->
dirty_tx
=
0
;
np
->
cur_task
=
0
;
np
->
rx_buf_sz
=
(
dev
->
mtu
<=
1520
?
PKT_BUF_SZ
:
dev
->
mtu
+
16
);
...
...
@@ -1022,39 +1042,57 @@ static void init_ring(struct net_device *dev)
return
;
}
static
void
tx_poll
(
unsigned
long
data
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
netdev_private
*
np
=
dev
->
priv
;
unsigned
head
=
np
->
cur_task
%
TX_RING_SIZE
;
struct
netdev_desc
*
txdesc
=
&
np
->
tx_ring
[(
np
->
cur_tx
-
1
)
%
TX_RING_SIZE
];
/* Chain the next pointer */
for
(;
np
->
cur_tx
-
np
->
cur_task
>
0
;
np
->
cur_task
++
)
{
int
entry
=
np
->
cur_task
%
TX_RING_SIZE
;
txdesc
=
&
np
->
tx_ring
[
entry
];
if
(
np
->
last_tx
)
{
np
->
last_tx
->
next_desc
=
cpu_to_le32
(
np
->
tx_ring_dma
+
entry
*
sizeof
(
struct
netdev_desc
));
}
np
->
last_tx
=
txdesc
;
}
/* Indicate the latest descriptor of tx ring */
txdesc
->
status
|=
cpu_to_le32
(
DescIntrOnTx
);
if
(
readl
(
dev
->
base_addr
+
TxListPtr
)
==
0
)
writel
(
np
->
tx_ring_dma
+
head
*
sizeof
(
struct
netdev_desc
),
dev
->
base_addr
+
TxListPtr
);
return
;
}
static
int
start_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_desc
*
txdesc
;
unsigned
entry
;
long
ioaddr
=
dev
->
base_addr
;
/* Note: Ordering is important here, set the field with the
"ownership" bit last, and only then increment cur_tx. */
/* Calculate the next Tx descriptor entry. */
entry
=
np
->
cur_tx
%
TX_RING_SIZE
;
np
->
tx_skbuff
[
entry
]
=
skb
;
txdesc
=
&
np
->
tx_ring
[
entry
];
txdesc
->
next_desc
=
0
;
/* Note: disable the interrupt generation here before releasing. */
if
(
entry
%
tx_coalesce
==
0
)
{
txdesc
->
status
=
cpu_to_le32
((
entry
<<
2
)
|
DescIntrOnTx
|
DisableAlign
);
}
else
{
txdesc
->
status
=
cpu_to_le32
((
entry
<<
2
)
|
DisableAlign
);
}
txdesc
->
status
=
cpu_to_le32
((
entry
<<
2
)
|
DisableAlign
);
txdesc
->
frag
[
0
].
addr
=
cpu_to_le32
(
pci_map_single
(
np
->
pci_dev
,
skb
->
data
,
skb
->
len
,
PCI_DMA_TODEVICE
));
txdesc
->
frag
[
0
].
length
=
cpu_to_le32
(
skb
->
len
|
LastFrag
);
if
(
np
->
last_tx
)
np
->
last_tx
->
next_desc
=
cpu_to_le32
(
np
->
tx_ring_dma
+
entry
*
sizeof
(
struct
netdev_desc
));
np
->
last_tx
=
txdesc
;
/* Increment cur_tx before tasklet_schedule() */
np
->
cur_tx
++
;
mb
();
/* Schedule a tx_poll() task */
tasklet_schedule
(
&
np
->
tx_tasklet
);
/* On some architectures: explicitly flush cache lines here. */
if
(
np
->
cur_tx
-
np
->
dirty_tx
<
TX_QUEUE_LEN
-
1
...
...
@@ -1063,23 +1101,16 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
}
else
{
netif_stop_queue
(
dev
);
}
/* Side effect: The read wakes the potentially-idle transmit channel. */
if
(
readl
(
dev
->
base_addr
+
TxListPtr
)
==
0
)
writel
(
np
->
tx_ring_dma
+
entry
*
sizeof
(
*
np
->
tx_ring
),
dev
->
base_addr
+
TxListPtr
);
dev
->
trans_start
=
jiffies
;
if
(
netif_msg_tx_queued
(
np
))
{
printk
(
KERN_DEBUG
"%s: Transmit frame #%d queued in slot %d.
\n
"
,
dev
->
name
,
np
->
cur_tx
,
entry
);
}
if
(
tx_coalesce
>
1
)
writel
(
1000
,
ioaddr
+
DownCounter
);
return
0
;
}
/* Reset hardware tx and reset TxListPtr to TxFrameId */
/* Reset hardware tx and free all of tx buffers */
static
int
reset_tx
(
struct
net_device
*
dev
)
{
...
...
@@ -1089,8 +1120,8 @@ reset_tx (struct net_device *dev)
int
i
;
int
irq
=
in_interrupt
();
/*
reset tx logic
*/
write
l
(
0
,
dev
->
base_addr
+
TxListPtr
);
/*
Reset tx logic, TxListPtr will be cleaned
*/
write
w
(
TxDisable
,
ioaddr
+
MACCtrl1
);
writew
(
TxReset
|
DMAReset
|
FIFOReset
|
NetworkReset
,
ioaddr
+
ASICCtrl
+
2
);
for
(
i
=
50
;
i
>
0
;
i
--
)
{
...
...
@@ -1114,11 +1145,13 @@ reset_tx (struct net_device *dev)
}
}
np
->
cur_tx
=
np
->
dirty_tx
=
0
;
np
->
cur_task
=
0
;
writew
(
StatsEnable
|
RxEnable
|
TxEnable
,
ioaddr
+
MACCtrl1
);
return
0
;
}
/* The interrupt handler
does all of the Rx thread work and cleans up
a
fter the Tx thread.
*/
/* The interrupt handler
cleans up after the Tx thread,
a
nd schedule a Rx thread work
*/
static
void
intr_handler
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
rgs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
...
...
@@ -1126,6 +1159,8 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
long
ioaddr
;
int
boguscnt
=
max_interrupt_work
;
int
hw_frame_id
;
int
tx_cnt
;
int
tx_status
;
ioaddr
=
dev
->
base_addr
;
np
=
dev
->
priv
;
...
...
@@ -1148,15 +1183,13 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
np
->
budget
=
RX_BUDGET
;
tasklet_schedule
(
&
np
->
rx_tasklet
);
}
if
(
intr_status
&
(
IntrTxDone
|
IntrDrvRqst
))
{
int
boguscnt
=
32
;
int
tx_status
=
readw
(
ioaddr
+
TxStatus
);
while
(
tx_status
&
0x80
)
{
tx_status
=
readw
(
ioaddr
+
TxStatus
);
for
(
tx_cnt
=
32
;
tx_status
&
0x80
;
--
tx_cnt
)
{
if
(
netif_msg_tx_done
(
np
))
printk
(
"%s: Transmit status is %2.2x.
\n
"
,
dev
->
name
,
tx_status
);
dev
->
name
,
tx_status
);
if
(
tx_status
&
0x1e
)
{
np
->
stats
.
tx_errors
++
;
if
(
tx_status
&
0x10
)
...
...
@@ -1179,35 +1212,62 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
/* Yup, this is a documentation bug. It cost me *hours*. */
writew
(
0
,
ioaddr
+
TxStatus
);
tx_status
=
readw
(
ioaddr
+
TxStatus
);
if
(
--
bogus
cnt
<
0
)
if
(
tx_
cnt
<
0
)
break
;
}
hw_frame_id
=
(
tx_status
>>
8
)
&
0xff
;
}
else
{
hw_frame_id
=
readb
(
ioaddr
+
TxFrameId
);
}
spin_lock
(
&
np
->
lock
);
hw_frame_id
=
readb
(
ioaddr
+
TxFrameId
);
for
(;
np
->
cur_tx
-
np
->
dirty_tx
>
0
;
np
->
dirty_tx
++
)
{
int
entry
=
np
->
dirty_tx
%
TX_RING_SIZE
;
struct
sk_buff
*
skb
;
int
sw_frame_id
;
sw_frame_id
=
(
np
->
tx_ring
[
entry
].
status
>>
2
)
&
0xff
;
if
(
sw_frame_id
==
hw_frame_id
)
break
;
skb
=
np
->
tx_skbuff
[
entry
];
/* Free the original skb. */
pci_unmap_single
(
np
->
pci_dev
,
np
->
tx_ring
[
entry
].
frag
[
0
].
addr
,
skb
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_irq
(
np
->
tx_skbuff
[
entry
]);
np
->
tx_skbuff
[
entry
]
=
0
;
if
(
np
->
pci_rev_id
>=
0x14
)
{
spin_lock
(
&
np
->
lock
);
for
(;
np
->
cur_tx
-
np
->
dirty_tx
>
0
;
np
->
dirty_tx
++
)
{
int
entry
=
np
->
dirty_tx
%
TX_RING_SIZE
;
struct
sk_buff
*
skb
;
int
sw_frame_id
;
sw_frame_id
=
(
np
->
tx_ring
[
entry
].
status
>>
2
)
&
0xff
;
if
(
sw_frame_id
==
hw_frame_id
&&
!
(
np
->
tx_ring
[
entry
].
status
&
0x00010000
))
break
;
if
(
sw_frame_id
==
(
hw_frame_id
+
1
)
%
TX_RING_SIZE
)
break
;
skb
=
np
->
tx_skbuff
[
entry
];
/* Free the original skb. */
pci_unmap_single
(
np
->
pci_dev
,
np
->
tx_ring
[
entry
].
frag
[
0
].
addr
,
skb
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_irq
(
np
->
tx_skbuff
[
entry
]);
np
->
tx_skbuff
[
entry
]
=
0
;
np
->
tx_ring
[
entry
].
frag
[
0
].
addr
=
0
;
np
->
tx_ring
[
entry
].
frag
[
0
].
length
=
0
;
}
spin_unlock
(
&
np
->
lock
);
}
else
{
spin_lock
(
&
np
->
lock
);
for
(;
np
->
cur_tx
-
np
->
dirty_tx
>
0
;
np
->
dirty_tx
++
)
{
int
entry
=
np
->
dirty_tx
%
TX_RING_SIZE
;
struct
sk_buff
*
skb
;
if
(
!
(
np
->
tx_ring
[
entry
].
status
&
0x00010000
))
break
;
skb
=
np
->
tx_skbuff
[
entry
];
/* Free the original skb. */
pci_unmap_single
(
np
->
pci_dev
,
np
->
tx_ring
[
entry
].
frag
[
0
].
addr
,
skb
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_irq
(
np
->
tx_skbuff
[
entry
]);
np
->
tx_skbuff
[
entry
]
=
0
;
np
->
tx_ring
[
entry
].
frag
[
0
].
addr
=
0
;
np
->
tx_ring
[
entry
].
frag
[
0
].
length
=
0
;
}
spin_unlock
(
&
np
->
lock
);
}
spin_unlock
(
&
np
->
lock
);
if
(
netif_queue_stopped
(
dev
)
&&
np
->
cur_tx
-
np
->
dirty_tx
<
TX_QUEUE_LEN
-
4
)
{
/* The ring is no longer full, clear
tbusy
. */
/* The ring is no longer full, clear
busy flag
. */
netif_wake_queue
(
dev
);
}
/* Abnormal error summary/uncommon events handlers. */
if
(
intr_status
&
(
IntrPCIErr
|
LinkChange
|
StatsMax
))
netdev_error
(
dev
,
intr_status
);
...
...
@@ -1223,8 +1283,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
if
(
netif_msg_intr
(
np
))
printk
(
KERN_DEBUG
"%s: exiting interrupt, status=%#4.4x.
\n
"
,
dev
->
name
,
readw
(
ioaddr
+
IntrStatus
));
if
(
np
->
cur_tx
-
np
->
dirty_tx
>
0
&&
tx_coalesce
>
1
)
writel
(
100
,
ioaddr
+
DownCounter
);
writel
(
5000
,
ioaddr
+
DownCounter
);
}
...
...
@@ -1246,7 +1305,7 @@ static void rx_poll(unsigned long data)
if
(
--
boguscnt
<
0
)
{
goto
not_done
;
}
if
(
!
(
desc
->
status
&
DescOwn
))
if
(
!
(
frame_
status
&
DescOwn
))
break
;
pkt_len
=
frame_status
&
0x1fff
;
/* Chip omits the CRC. */
if
(
netif_msg_rx_status
(
np
))
...
...
@@ -1555,6 +1614,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
struct
netdev_private
*
np
=
dev
->
priv
;
struct
mii_ioctl_data
*
data
=
(
struct
mii_ioctl_data
*
)
&
rq
->
ifr_data
;
int
rc
;
int
i
;
if
(
!
netif_running
(
dev
))
return
-
EINVAL
;
...
...
@@ -1567,6 +1627,28 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc
=
generic_mii_ioctl
(
&
np
->
mii_if
,
data
,
cmd
,
NULL
);
spin_unlock_irq
(
&
np
->
lock
);
}
switch
(
cmd
)
{
case
SIOCDEVPRIVATE
:
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
printk
(
KERN_DEBUG
"%02x %08x %08x %08x(%02x) %08x %08x
\n
"
,
i
,
np
->
tx_ring_dma
+
i
*
sizeof
(
*
np
->
tx_ring
),
np
->
tx_ring
[
i
].
next_desc
,
np
->
tx_ring
[
i
].
status
,
(
np
->
tx_ring
[
i
].
status
>>
2
)
&
0xff
,
np
->
tx_ring
[
i
].
frag
[
0
].
addr
,
np
->
tx_ring
[
i
].
frag
[
0
].
length
);
}
printk
(
KERN_DEBUG
"TxListPtr=%08x netif_queue_stopped=%d
\n
"
,
readl
(
dev
->
base_addr
+
TxListPtr
),
netif_queue_stopped
(
dev
));
printk
(
KERN_DEBUG
"cur_tx=%d(%02x) dirty_tx=%d(%02x)
\n
"
,
np
->
cur_tx
,
np
->
cur_tx
%
TX_RING_SIZE
,
np
->
dirty_tx
,
np
->
dirty_tx
%
TX_RING_SIZE
);
printk
(
KERN_DEBUG
"cur_rx=%d dirty_rx=%d
\n
"
,
np
->
cur_rx
,
np
->
dirty_rx
);
printk
(
KERN_DEBUG
"cur_task=%d
\n
"
,
np
->
cur_task
);
return
0
;
}
return
rc
;
}
...
...
@@ -1595,6 +1677,10 @@ static int netdev_close(struct net_device *dev)
/* Stop the chip's Tx and Rx processes. */
writew
(
TxDisable
|
RxDisable
|
StatsDisable
,
ioaddr
+
MACCtrl1
);
/* Wait and kill tasklet */
tasklet_kill
(
&
np
->
rx_tasklet
);
tasklet_kill
(
&
np
->
tx_tasklet
);
#ifdef __i386__
if
(
netif_msg_hw
(
np
))
{
printk
(
"
\n
"
KERN_DEBUG
" Tx ring at %8.8x:
\n
"
,
...
...
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