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
5ef7ab1c
Commit
5ef7ab1c
authored
Feb 24, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/pcnet32
into redhat.com:/spare/repo/net-drivers-2.5
parents
9e6b8ac3
62d90976
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
602 additions
and
339 deletions
+602
-339
drivers/net/pcnet32.c
drivers/net/pcnet32.c
+602
-339
No files found.
drivers/net/pcnet32.c
View file @
5ef7ab1c
/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
/*
* Copyright 1996-1999 Thomas Bogendoerfer
*
*
* Derived from the lance driver written 1993,1994,1995 by Donald Becker.
*
*
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency.
*
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
...
...
@@ -22,8 +22,8 @@
*************************************************************************/
#define DRV_NAME "pcnet32"
#define DRV_VERSION "1.2
7b
"
#define DRV_RELDATE "0
1.10.2002
"
#define DRV_VERSION "1.2
8
"
#define DRV_RELDATE "0
2.20.2004
"
#define PFX DRV_NAME ": "
static
const
char
*
version
=
...
...
@@ -58,6 +58,12 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
static
struct
pci_device_id
pcnet32_pci_tbl
[]
=
{
{
PCI_VENDOR_ID_AMD
,
PCI_DEVICE_ID_AMD_LANCE_HOME
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
{
PCI_VENDOR_ID_AMD
,
PCI_DEVICE_ID_AMD_LANCE
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
{
PCI_VENDOR_ID_TRIDENT
,
PCI_DEVICE_ID_AMD_LANCE
,
PCI_ANY_ID
,
PCI_ANY_ID
,
PCI_CLASS_NETWORK_ETHERNET
<<
8
,
0xffff00
,
0
},
{
0
,
}
};
...
...
@@ -65,15 +71,15 @@ MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
int
cards_found
__initdata
;
/*
* VLB I/O addresses
/*
* VLB I/O addresses
*/
static
unsigned
int
pcnet32_portlist
[]
__initdata
=
static
unsigned
int
pcnet32_portlist
[]
__initdata
=
{
0x300
,
0x320
,
0x340
,
0x360
,
0
};
static
int
pcnet32_debug
=
1
;
static
int
pcnet32_debug
=
0
;
static
int
tx_start
=
1
;
/* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
static
int
pcnet32vlb
;
/* check for VLB cards ? */
...
...
@@ -103,7 +109,7 @@ static int rx_copybreak = 200;
static
unsigned
char
options_mapping
[]
=
{
PCNET32_PORT_ASEL
,
/* 0 Auto-select */
PCNET32_PORT_AUI
,
/* 1 BNC/AUI */
PCNET32_PORT_AUI
,
/* 2 AUI/BNC */
PCNET32_PORT_AUI
,
/* 2 AUI/BNC */
PCNET32_PORT_ASEL
,
/* 3 not supported */
PCNET32_PORT_10BT
|
PCNET32_PORT_FD
,
/* 4 10baseT-FD */
PCNET32_PORT_ASEL
,
/* 5 not supported */
...
...
@@ -119,20 +125,25 @@ static unsigned char options_mapping[] = {
PCNET32_PORT_ASEL
/* 15 not supported */
};
static
const
char
pcnet32_gstrings_test
[][
ETH_GSTRING_LEN
]
=
{
"Loopback test (offline)"
};
#define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN)
#define MAX_UNITS 8
/* More are supported, limit only on options */
static
int
options
[
MAX_UNITS
];
static
int
full_duplex
[
MAX_UNITS
];
/*
* Theory of Operation
*
*
* This driver uses the same software structure as the normal lance
* driver. So look for a verbose description in lance.c. The differences
* to the normal lance driver is the use of the 32bit mode of PCnet32
* and PCnetPCI chips. Because these chips are 32bit chips, there is no
* 16MB limitation and we don't need bounce buffers.
*/
/*
* History:
* v0.01: Initial version
...
...
@@ -186,7 +197,7 @@ static int full_duplex[MAX_UNITS];
* v1.22: changed pci scanning code to make PPC people happy
* fixed switching to 32bit mode in pcnet32_open() (thanks
* to Michael Richard <mcr@solidum.com> for noticing this one)
* added sub vendor/device id matching (thanks again to
* added sub vendor/device id matching (thanks again to
* Michael Richard <mcr@solidum.com>)
* added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
* v1.23 fixed small bug, when manual selecting MII speed/duplex
...
...
@@ -204,7 +215,7 @@ static int full_duplex[MAX_UNITS];
* v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
* v1.27 improved CSR/PROM address detection, lots of cleanups,
* new pcnet32vlb module option, HP-PARISC support,
* added module parameter descriptions,
* added module parameter descriptions,
* initial ethtool support - Helge Deller <deller@gmx.de>
* v1.27a Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
* use alloc_etherdev and register_netdev
...
...
@@ -213,6 +224,11 @@ static int full_duplex[MAX_UNITS];
* clean up and using new mii module
* v1.27b Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
* Added timer for cable connection state changes.
* v1.28 20 Feb 2004 Don Fry <brazilnut@us.ibm.com>
* Jon Lewis <jonmason@us.ibm.com>, Chinmay Albal <albal@in.ibm.com>
* Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl.
* Fixes bogus 'Bus master arbitration failure', pci_[un]map_single
* length errors, and transmit hangs. Cleans up after errors in open.
*/
...
...
@@ -253,11 +269,11 @@ static int full_duplex[MAX_UNITS];
struct
pcnet32_rx_head
{
u32
base
;
s16
buf_length
;
s16
status
;
s16
status
;
u32
msg_length
;
u32
reserved
;
};
struct
pcnet32_tx_head
{
u32
base
;
s16
length
;
...
...
@@ -273,7 +289,7 @@ struct pcnet32_init_block {
u8
phys_addr
[
6
];
u16
reserved
;
u32
filter
[
2
];
/* Receive and transmit ring base, along with extra bits. */
/* Receive and transmit ring base, along with extra bits. */
u32
rx_ring
;
u32
tx_ring
;
};
...
...
@@ -290,7 +306,7 @@ struct pcnet32_access {
};
/*
* The first three fields of pcnet32_private are read by the ethernet device
* The first three fields of pcnet32_private are read by the ethernet device
* so we allocate the structure should be allocated by pci_alloc_consistent().
*/
struct
pcnet32_private
{
...
...
@@ -298,16 +314,18 @@ struct pcnet32_private {
struct
pcnet32_rx_head
rx_ring
[
RX_RING_SIZE
];
struct
pcnet32_tx_head
tx_ring
[
TX_RING_SIZE
];
struct
pcnet32_init_block
init_block
;
dma_addr_t
dma_addr
;
/* DMA address of beginning of this object,
returned by pci_alloc_consistent */
struct
pci_dev
*
pci_dev
;
/* Pointer to the associated pci device structure */
dma_addr_t
dma_addr
;
/* DMA address of beginning of this
object, returned by
pci_alloc_consistent */
struct
pci_dev
*
pci_dev
;
/* Pointer to the associated pci device
structure */
const
char
*
name
;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct
sk_buff
*
tx_skbuff
[
TX_RING_SIZE
];
struct
sk_buff
*
rx_skbuff
[
RX_RING_SIZE
];
dma_addr_t
tx_dma_addr
[
TX_RING_SIZE
];
dma_addr_t
rx_dma_addr
[
RX_RING_SIZE
];
struct
pcnet32_access
a
;
struct
pcnet32_access
a
;
spinlock_t
lock
;
/* Guard lock */
unsigned
int
cur_rx
,
cur_tx
;
/* The next free ring entry */
unsigned
int
dirty_rx
,
dirty_tx
;
/* The ring entries to be free()ed. */
...
...
@@ -319,8 +337,9 @@ struct pcnet32_private {
dxsuflo:
1
,
/* disable transmit stop on uflo */
mii:
1
;
/* mii port available */
struct
net_device
*
next
;
struct
mii_if_info
mii_if
;
struct
mii_if_info
mii_if
;
struct
timer_list
watchdog_timer
;
u32
msg_enable
;
/* debug message level */
};
static
void
pcnet32_probe_vlbus
(
void
);
...
...
@@ -339,6 +358,10 @@ static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);
static
void
pcnet32_watchdog
(
struct
net_device
*
);
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
);
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
,
int
val
);
static
void
pcnet32_restart
(
struct
net_device
*
dev
,
unsigned
int
csr0_bits
);
static
void
pcnet32_ethtool_test
(
struct
net_device
*
dev
,
struct
ethtool_test
*
eth_test
,
u64
*
data
);
static
int
pcnet32_loopback_test
(
struct
net_device
*
dev
,
uint64_t
*
data1
);
enum
pci_flags_bit
{
PCI_USES_IO
=
1
,
PCI_USES_MEM
=
2
,
PCI_USES_MASTER
=
4
,
...
...
@@ -458,23 +481,290 @@ static struct pcnet32_access pcnet32_dwio = {
/* only probes for non-PCI devices, the rest are handled by
static
int
pcnet32_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
flags
;
int
r
=
-
EOPNOTSUPP
;
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
mii_ethtool_gset
(
&
lp
->
mii_if
,
cmd
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
r
=
0
;
}
return
r
;
}
static
int
pcnet32_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
flags
;
int
r
=
-
EOPNOTSUPP
;
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
r
=
mii_ethtool_sset
(
&
lp
->
mii_if
,
cmd
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
}
return
r
;
}
static
void
pcnet32_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
version
,
DRV_VERSION
);
if
(
lp
->
pci_dev
)
strcpy
(
info
->
bus_info
,
pci_name
(
lp
->
pci_dev
));
else
sprintf
(
info
->
bus_info
,
"VLB 0x%lx"
,
dev
->
base_addr
);
}
static
u32
pcnet32_get_link
(
struct
net_device
*
dev
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
flags
;
int
r
=
1
;
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
r
=
mii_link_ok
(
&
lp
->
mii_if
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
}
return
r
;
}
static
u32
pcnet32_get_msglevel
(
struct
net_device
*
dev
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
return
lp
->
msg_enable
;
}
static
void
pcnet32_set_msglevel
(
struct
net_device
*
dev
,
u32
value
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
lp
->
msg_enable
=
value
;
}
static
int
pcnet32_nway_reset
(
struct
net_device
*
dev
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
flags
;
int
r
=
-
EOPNOTSUPP
;
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
r
=
mii_nway_restart
(
&
lp
->
mii_if
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
}
return
r
;
}
static
void
pcnet32_get_ringparam
(
struct
net_device
*
dev
,
struct
ethtool_ringparam
*
ering
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
ering
->
tx_max_pending
=
TX_RING_SIZE
-
1
;
ering
->
tx_pending
=
lp
->
cur_tx
-
lp
->
dirty_tx
;
ering
->
rx_max_pending
=
RX_RING_SIZE
-
1
;
ering
->
rx_pending
=
lp
->
cur_rx
&
RX_RING_MOD_MASK
;
}
static
void
pcnet32_get_strings
(
struct
net_device
*
dev
,
u32
stringset
,
u8
*
data
)
{
memcpy
(
data
,
pcnet32_gstrings_test
,
sizeof
(
pcnet32_gstrings_test
));
}
static
int
pcnet32_self_test_count
(
struct
net_device
*
dev
)
{
return
PCNET32_TEST_LEN
;
}
static
void
pcnet32_ethtool_test
(
struct
net_device
*
dev
,
struct
ethtool_test
*
test
,
u64
*
data
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
int
rc
;
if
(
test
->
flags
==
ETH_TEST_FL_OFFLINE
)
{
rc
=
pcnet32_loopback_test
(
dev
,
data
);
if
(
rc
)
{
if
(
netif_msg_hw
(
lp
))
printk
(
KERN_DEBUG
"%s: Loopback test failed.
\n
"
,
dev
->
name
);
test
->
flags
|=
ETH_TEST_FL_FAILED
;
}
else
if
(
netif_msg_hw
(
lp
))
printk
(
KERN_DEBUG
"%s: Loopback test passed.
\n
"
,
dev
->
name
);
}
else
printk
(
KERN_DEBUG
"%s: No tests to run (specify 'Offline' on ethtool)."
,
dev
->
name
);
}
/* end pcnet32_ethtool_test */
static
int
pcnet32_loopback_test
(
struct
net_device
*
dev
,
uint64_t
*
data1
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_access
*
a
=
&
lp
->
a
;
/* access to registers */
ulong
ioaddr
=
dev
->
base_addr
;
/* card base I/O address */
struct
sk_buff
*
skb
;
/* sk buff */
int
x
,
y
,
i
;
/* counters */
int
numbuffs
=
4
;
/* number of TX/RX buffers and descs */
u16
status
=
0x8300
;
/* TX ring status */
int
rc
;
/* return code */
int
size
;
/* size of packets */
unsigned
char
*
packet
;
/* source packet data */
static
int
data_len
=
60
;
/* length of source packets */
unsigned
long
flags
;
*
data1
=
1
;
/* status of test, default to fail */
rc
=
1
;
/* default to fail */
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x7904
);
del_timer_sync
(
&
lp
->
watchdog_timer
);
netif_stop_queue
(
dev
);
/* purge & init rings but don't actually restart */
pcnet32_restart
(
dev
,
0x0000
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/* Set STOP bit */
x
=
a
->
read_bcr
(
ioaddr
,
32
);
/* set internal loopback in BSR32 */
x
=
x
|
0x00000002
;
a
->
write_bcr
(
ioaddr
,
32
,
x
);
/* Initialize Transmit buffers. */
size
=
data_len
+
15
;
for
(
x
=
0
;
x
<
numbuffs
;
x
++
)
{
if
(
!
(
skb
=
dev_alloc_skb
(
size
)))
{
if
(
netif_msg_hw
(
lp
))
printk
(
KERN_DEBUG
"%s: Cannot allocate skb at line: %d!
\n
"
,
dev
->
name
,
__LINE__
);
goto
clean_up
;
}
else
{
packet
=
skb
->
data
;
skb_put
(
skb
,
size
);
/* create space for data */
lp
->
tx_skbuff
[
x
]
=
skb
;
lp
->
tx_ring
[
x
].
length
=
le16_to_cpu
(
-
skb
->
len
);
lp
->
tx_ring
[
x
].
misc
=
0x00000000
;
/* put DA and SA into the skb */
for
(
i
=
0
;
i
<
12
;
i
++
)
*
packet
++
=
0xff
;
/* type */
*
packet
++
=
0x08
;
*
packet
++
=
0x06
;
/* packet number */
*
packet
++
=
x
;
/* fill packet with data */
for
(
y
=
0
;
y
<
data_len
;
y
++
)
*
packet
++
=
y
;
lp
->
tx_dma_addr
[
x
]
=
pci_map_single
(
lp
->
pci_dev
,
skb
->
data
,
skb
->
len
,
PCI_DMA_TODEVICE
);
lp
->
tx_ring
[
x
].
base
=
(
u32
)
le32_to_cpu
(
lp
->
tx_dma_addr
[
x
]);
wmb
();
/* Make sure owner changes after all others are visible */
lp
->
tx_ring
[
x
].
status
=
le16_to_cpu
(
status
);
}
}
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0002
);
/* Set STRT bit */
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
mdelay
(
50
);
/* wait a bit */
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/* Set STOP bit */
if
(
netif_msg_hw
(
lp
)
&&
netif_msg_pktdata
(
lp
))
{
printk
(
KERN_DEBUG
"%s: RX loopback packets:
\n
"
,
dev
->
name
);
for
(
x
=
0
;
x
<
numbuffs
;
x
++
)
{
printk
(
KERN_DEBUG
"%s: Packet %d:
\n
"
,
dev
->
name
,
x
);
skb
=
lp
->
rx_skbuff
[
x
];
for
(
i
=
0
;
i
<
size
;
i
++
)
{
printk
(
"%02x "
,
*
(
skb
->
data
+
i
));
}
printk
(
"
\n
"
);
}
}
x
=
0
;
rc
=
0
;
while
(
x
<
numbuffs
&&
!
rc
)
{
skb
=
lp
->
rx_skbuff
[
x
];
packet
=
lp
->
tx_skbuff
[
x
]
->
data
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
if
(
*
(
skb
->
data
+
i
)
!=
packet
[
i
])
{
if
(
netif_msg_hw
(
lp
))
printk
(
KERN_DEBUG
"%s: Error in compare! %2x - %02x %02x
\n
"
,
dev
->
name
,
i
,
*
(
skb
->
data
+
i
),
packet
[
i
]);
rc
=
1
;
break
;
}
}
x
++
;
}
if
(
!
rc
)
{
*
data1
=
0
;
}
clean_up:
x
=
a
->
read_csr
(
ioaddr
,
15
)
&
0xFFFF
;
a
->
write_csr
(
ioaddr
,
15
,
(
x
&
~
0x0044
));
/* reset bits 6 and 2 */
x
=
a
->
read_bcr
(
ioaddr
,
32
);
/* reset internal loopback */
x
=
x
&
~
0x00000002
;
a
->
write_bcr
(
ioaddr
,
32
,
x
);
pcnet32_restart
(
dev
,
0x0042
);
/* resume normal operation */
netif_wake_queue
(
dev
);
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
/* Clear interrupts, and set interrupt enable. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x7940
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
return
(
rc
);
}
/* end pcnet32_loopback_test */
static
struct
ethtool_ops
pcnet32_ethtool_ops
=
{
.
get_settings
=
pcnet32_get_settings
,
.
set_settings
=
pcnet32_set_settings
,
.
get_drvinfo
=
pcnet32_get_drvinfo
,
.
get_msglevel
=
pcnet32_get_msglevel
,
.
set_msglevel
=
pcnet32_set_msglevel
,
.
nway_reset
=
pcnet32_nway_reset
,
.
get_link
=
pcnet32_get_link
,
.
get_ringparam
=
pcnet32_get_ringparam
,
.
get_tx_csum
=
ethtool_op_get_tx_csum
,
.
get_sg
=
ethtool_op_get_sg
,
.
get_tso
=
ethtool_op_get_tso
,
.
get_strings
=
pcnet32_get_strings
,
.
self_test_count
=
pcnet32_self_test_count
,
.
self_test
=
pcnet32_ethtool_test
,
};
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
static
void
__devinit
pcnet32_probe_vlbus
(
void
)
{
unsigned
int
*
port
,
ioaddr
;
/* search for PCnet32 VLB cards at known addresses */
for
(
port
=
pcnet32_portlist
;
(
ioaddr
=
*
port
);
port
++
)
{
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_vlbus"
))
{
/* check if there is really a pcnet chip on that ioaddr */
if
((
inb
(
ioaddr
+
14
)
==
0x57
)
&&
(
inb
(
ioaddr
+
15
)
==
0x57
))
{
pcnet32_probe1
(
ioaddr
,
0
,
0
,
NULL
);
}
else
{
release_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
);
}
/* check if there is really a pcnet chip on that ioaddr */
if
((
inb
(
ioaddr
+
14
)
==
0x57
)
&&
(
inb
(
ioaddr
+
15
)
==
0x57
))
{
pcnet32_probe1
(
ioaddr
,
0
,
0
,
NULL
);
}
else
{
release_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
);
}
}
}
}
...
...
@@ -495,25 +785,25 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr
=
pci_resource_start
(
pdev
,
0
);
if
(
!
ioaddr
)
{
printk
(
KERN_ERR
PFX
"card has no PCI IO resources, aborting
\n
"
);
return
-
ENODEV
;
printk
(
KERN_ERR
PFX
"card has no PCI IO resources, aborting
\n
"
);
return
-
ENODEV
;
}
if
(
!
pci_dma_supported
(
pdev
,
PCNET32_DMA_MASK
))
{
printk
(
KERN_ERR
PFX
"architecture does not support 32bit PCI busmaster DMA
\n
"
);
return
-
ENODEV
;
}
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_pci"
)
==
NULL
)
{
printk
(
KERN_ERR
PFX
"io address range already allocated
\n
"
);
return
-
EBUSY
;
printk
(
KERN_ERR
PFX
"io address range already allocated
\n
"
);
return
-
EBUSY
;
}
return
pcnet32_probe1
(
ioaddr
,
pdev
->
irq
,
1
,
pdev
);
}
/* pcnet32_probe1
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
/* pcnet32_probe1
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
* pdev will be NULL when called from pcnet32_probe_vlbus.
*/
static
int
__devinit
...
...
@@ -546,11 +836,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
}
chip_version
=
a
->
read_csr
(
ioaddr
,
88
)
|
(
a
->
read_csr
(
ioaddr
,
89
)
<<
16
);
if
(
pcnet32_debug
>
2
)
if
(
pcnet32_debug
&
NETIF_MSG_PROBE
)
printk
(
KERN_INFO
" PCnet chip version is %#x.
\n
"
,
chip_version
);
if
((
chip_version
&
0xfff
)
!=
0x003
)
goto
err_release_region
;
if
((
chip_version
&
0xfff
)
!=
0x003
)
{
printk
(
KERN_INFO
PFX
"Unsupported chip version.
\n
"
);
goto
err_release_region
;
}
/* initialize variables */
fdx
=
mii
=
fset
=
dxsuflo
=
ltint
=
0
;
chip_version
=
(
chip_version
>>
12
)
&
0xffff
;
...
...
@@ -585,7 +877,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
case
0x2626
:
chipname
=
"PCnet/Home 79C978"
;
/* PCI */
fdx
=
1
;
/*
/*
* This is based on specs published at www.amd.com. This section
* assumes that a card with a 79C978 wants to go into 1Mb HomePNA
* mode. The 79C978 can also go into standard ethernet, and there
...
...
@@ -594,13 +886,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
*/
/* switch to home wiring mode */
media
=
a
->
read_bcr
(
ioaddr
,
49
);
#if 0
if (pcnet32_debug > 2)
printk(KERN_DEBUG PFX "media value %#x.\n", media);
media &= ~3;
media |= 1;
#endif
if
(
pcnet32_debug
>
2
)
if
(
pcnet32_debug
&
NETIF_MSG_PROBE
)
printk
(
KERN_DEBUG
PFX
"media reset to %#x.
\n
"
,
media
);
a
->
write_bcr
(
ioaddr
,
49
,
media
);
break
;
...
...
@@ -610,29 +896,29 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
break
;
default:
printk
(
KERN_INFO
PFX
"PCnet version %#x, no PCnet32 chip.
\n
"
,
chip_version
);
chip_version
);
goto
err_release_region
;
}
/*
* On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
* starting until the packet is loaded. Strike one for reliability, lose
* one for latency - although on PCI this isnt a big loss. Older chips
* one for latency - although on PCI this isnt a big loss. Older chips
* have FIFO's smaller than a packet, so you can't do this.
*/
if
(
fset
)
{
if
(
fset
)
{
a
->
write_bcr
(
ioaddr
,
18
,
(
a
->
read_bcr
(
ioaddr
,
18
)
|
0x0800
));
a
->
write_csr
(
ioaddr
,
80
,
(
a
->
read_csr
(
ioaddr
,
80
)
&
0x0C00
)
|
0x0c00
);
dxsuflo
=
1
;
ltint
=
1
;
}
dev
=
alloc_etherdev
(
0
);
if
(
!
dev
)
{
ret
=
-
ENOMEM
;
goto
err_release_region
;
if
(
!
dev
)
{
printk
(
KERN_ERR
PFX
"Memory allocation failed.
\n
"
);
ret
=
-
ENOMEM
;
goto
err_release_region
;
}
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
...
...
@@ -656,13 +942,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
/* read PROM address and compare with CSR address */
for
(
i
=
0
;
i
<
6
;
i
++
)
promaddr
[
i
]
=
inb
(
ioaddr
+
i
);
if
(
memcmp
(
promaddr
,
dev
->
dev_addr
,
6
)
||
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
{
if
(
memcmp
(
promaddr
,
dev
->
dev_addr
,
6
)
||
!
is_valid_ether_addr
(
dev
->
dev_addr
))
{
#ifndef __powerpc__
if
(
is_valid_ether_addr
(
promaddr
)
)
{
if
(
is_valid_ether_addr
(
promaddr
))
{
#else
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
&&
is_valid_ether_addr
(
promaddr
))
{
#endif
printk
(
" warning: CSR address invalid,
\n
"
);
...
...
@@ -672,13 +958,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
}
/* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
memset
(
dev
->
dev_addr
,
0
,
sizeof
(
dev
->
dev_addr
));
for
(
i
=
0
;
i
<
6
;
i
++
)
printk
(
" %2.2x"
,
dev
->
dev_addr
[
i
]
);
if
(((
chip_version
+
1
)
&
0xfffe
)
==
0x2624
)
{
/* Version 0x2623
or
0x2624 */
if
(((
chip_version
+
1
)
&
0xfffe
)
==
0x2624
)
{
/* Version 0x2623
-
0x2624 */
i
=
a
->
read_csr
(
ioaddr
,
80
)
&
0x0C00
;
/* Check tx_start_pt */
printk
(
"
\n
"
KERN_INFO
" tx_start_pt(0x%04x):"
,
i
);
switch
(
i
>>
10
)
{
...
...
@@ -704,6 +990,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
dev
->
base_addr
=
ioaddr
;
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
if
((
lp
=
pci_alloc_consistent
(
pdev
,
sizeof
(
*
lp
),
&
lp_dma_addr
))
==
NULL
)
{
printk
(
KERN_ERR
PFX
"Consistent memory allocation failed.
\n
"
);
ret
=
-
ENOMEM
;
goto
err_free_netdev
;
}
...
...
@@ -713,7 +1000,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
pci_dev
=
pdev
;
spin_lock_init
(
&
lp
->
lock
);
SET_MODULE_OWNER
(
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
dev
->
priv
=
lp
;
...
...
@@ -725,6 +1012,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
dxsuflo
=
dxsuflo
;
lp
->
ltint
=
ltint
;
lp
->
mii
=
mii
;
lp
->
msg_enable
=
pcnet32_debug
;
if
((
cards_found
>=
MAX_UNITS
)
||
(
options
[
cards_found
]
>
sizeof
(
options_mapping
)))
lp
->
options
=
PCNET32_PORT_ASEL
;
else
...
...
@@ -732,46 +1020,51 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
mii_if
.
dev
=
dev
;
lp
->
mii_if
.
mdio_read
=
mdio_read
;
lp
->
mii_if
.
mdio_write
=
mdio_write
;
if
(
fdx
&&
!
(
lp
->
options
&
PCNET32_PORT_ASEL
)
&&
if
(
fdx
&&
!
(
lp
->
options
&
PCNET32_PORT_ASEL
)
&&
((
cards_found
>=
MAX_UNITS
)
||
full_duplex
[
cards_found
]))
lp
->
options
|=
PCNET32_PORT_FD
;
if
(
!
a
)
{
printk
(
KERN_ERR
PFX
"No access methods
\n
"
);
ret
=
-
ENODEV
;
goto
err_free_consistent
;
printk
(
KERN_ERR
PFX
"No access methods
\n
"
);
ret
=
-
ENODEV
;
goto
err_free_consistent
;
}
lp
->
a
=
*
a
;
/* detect special T1/E1 WAN card by checking for MAC address */
if
(
dev
->
dev_addr
[
0
]
==
0x00
&&
dev
->
dev_addr
[
1
]
==
0xe0
&&
dev
->
dev_addr
[
2
]
==
0x75
)
if
(
dev
->
dev_addr
[
0
]
==
0x00
&&
dev
->
dev_addr
[
1
]
==
0xe0
&&
dev
->
dev_addr
[
2
]
==
0x75
)
lp
->
options
=
PCNET32_PORT_FD
|
PCNET32_PORT_GPSI
;
lp
->
init_block
.
mode
=
le16_to_cpu
(
0x0003
);
/* Disable Rx and Tx. */
lp
->
init_block
.
tlen_rlen
=
le16_to_cpu
(
TX_RING_LEN_BITS
|
RX_RING_LEN_BITS
);
lp
->
init_block
.
tlen_rlen
=
le16_to_cpu
(
TX_RING_LEN_BITS
|
RX_RING_LEN_BITS
);
for
(
i
=
0
;
i
<
6
;
i
++
)
lp
->
init_block
.
phys_addr
[
i
]
=
dev
->
dev_addr
[
i
];
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
1
]
=
0x00000000
;
lp
->
init_block
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
rx_ring
));
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
lp
->
init_block
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
rx_ring
));
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
/* switch pcnet32 to 32bit mode */
a
->
write_bcr
(
ioaddr
,
20
,
2
);
a
->
write_bcr
(
ioaddr
,
20
,
2
);
a
->
write_csr
(
ioaddr
,
1
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
&
0xffff
);
a
->
write_csr
(
ioaddr
,
2
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
>>
16
);
a
->
write_csr
(
ioaddr
,
1
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
&
0xffff
);
a
->
write_csr
(
ioaddr
,
2
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
>>
16
);
if
(
irq_line
)
{
dev
->
irq
=
irq_line
;
}
if
(
dev
->
irq
>=
2
)
printk
(
" assigned IRQ %d.
\n
"
,
dev
->
irq
);
else
{
unsigned
long
irq_mask
=
probe_irq_on
();
/*
* To auto-IRQ we enable the initialization-done and DMA error
* interrupts. For ISA boards we get a DMA error, but VLB and PCI
...
...
@@ -780,7 +1073,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
/* Trigger an initialization just for the interrupt. */
a
->
write_csr
(
ioaddr
,
0
,
0x41
);
mdelay
(
1
);
dev
->
irq
=
probe_irq_off
(
irq_mask
);
if
(
!
dev
->
irq
)
{
printk
(
", failed to detect IRQ line.
\n
"
);
...
...
@@ -797,7 +1090,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
init_timer
(
&
lp
->
watchdog_timer
);
lp
->
watchdog_timer
.
data
=
(
unsigned
long
)
dev
;
lp
->
watchdog_timer
.
function
=
(
void
*
)
&
pcnet32_watchdog
;
/* The PCNET32-specific entries in the device structure. */
dev
->
open
=
&
pcnet32_open
;
dev
->
hard_start_xmit
=
&
pcnet32_start_xmit
;
...
...
@@ -805,6 +1098,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
dev
->
get_stats
=
&
pcnet32_get_stats
;
dev
->
set_multicast_list
=
&
pcnet32_set_multicast_list
;
dev
->
do_ioctl
=
&
pcnet32_ioctl
;
dev
->
ethtool_ops
=
&
pcnet32_ethtool_ops
;
dev
->
tx_timeout
=
pcnet32_tx_timeout
;
dev
->
watchdog_timeo
=
(
5
*
HZ
);
...
...
@@ -812,8 +1106,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
if
(
register_netdev
(
dev
))
goto
err_free_consistent
;
lp
->
next
=
pcnet32_dev
;
pcnet32_dev
=
dev
;
if
(
pdev
)
{
pci_set_drvdata
(
pdev
,
dev
);
}
else
{
lp
->
next
=
pcnet32_dev
;
pcnet32_dev
=
dev
;
}
printk
(
KERN_INFO
"%s: registered as %s
\n
"
,
dev
->
name
,
lp
->
name
);
cards_found
++
;
return
0
;
...
...
@@ -835,6 +1134,7 @@ pcnet32_open(struct net_device *dev)
unsigned
long
ioaddr
=
dev
->
base_addr
;
u16
val
;
int
i
;
int
rc
;
if
(
dev
->
irq
==
0
||
request_irq
(
dev
->
irq
,
&
pcnet32_interrupt
,
...
...
@@ -843,8 +1143,10 @@ pcnet32_open(struct net_device *dev)
}
/* Check for a valid station address */
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
return
-
EINVAL
;
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
))
{
rc
=
-
EINVAL
;
goto
err_free_irq
;
}
/* Reset the PCNET32 */
lp
->
a
.
reset
(
ioaddr
);
...
...
@@ -852,19 +1154,19 @@ pcnet32_open(struct net_device *dev)
/* switch pcnet32 to 32bit mode */
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
2
);
if
(
pcnet32_debug
>
1
)
if
(
netif_msg_ifup
(
lp
)
)
printk
(
KERN_DEBUG
"%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.
\n
"
,
dev
->
name
,
dev
->
irq
,
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
)),
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
rx_ring
)),
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
)));
/* set/reset autoselect bit */
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
2
)
&
~
2
;
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
val
|=
2
;
lp
->
a
.
write_bcr
(
ioaddr
,
2
,
val
);
/* handle full duplex setting */
if
(
lp
->
mii_if
.
full_duplex
)
{
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
9
)
&
~
3
;
...
...
@@ -874,34 +1176,38 @@ pcnet32_open(struct net_device *dev)
val
|=
2
;
}
else
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
/* workaround of xSeries250, turn on for 79C975 only */
i
=
((
lp
->
a
.
read_csr
(
ioaddr
,
88
)
|
(
lp
->
a
.
read_csr
(
ioaddr
,
89
)
<<
16
))
>>
12
)
&
0xffff
;
if
(
i
==
0x2627
)
val
|=
3
;
i
=
((
lp
->
a
.
read_csr
(
ioaddr
,
88
)
|
(
lp
->
a
.
read_csr
(
ioaddr
,
89
)
<<
16
))
>>
12
)
&
0xffff
;
if
(
i
==
0x2627
)
val
|=
3
;
}
lp
->
a
.
write_bcr
(
ioaddr
,
9
,
val
);
}
/* set/reset GPSI bit in test register */
val
=
lp
->
a
.
read_csr
(
ioaddr
,
124
)
&
~
0x10
;
if
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
==
PCNET32_PORT_GPSI
)
val
|=
0x10
;
lp
->
a
.
write_csr
(
ioaddr
,
124
,
val
);
if
(
lp
->
mii
&&
!
(
lp
->
options
&
PCNET32_PORT_ASEL
))
{
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x38
;
/* disable Auto Negotiation, set 10Mpbs, HD */
/* disable Auto Negotiation, set 10Mpbs, HD */
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x38
;
if
(
lp
->
options
&
PCNET32_PORT_FD
)
val
|=
0x10
;
if
(
lp
->
options
&
PCNET32_PORT_100
)
val
|=
0x08
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
}
else
{
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
/* enable auto negotiate, setup, disable fd */
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x98
;
val
|=
0x20
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
/* enable auto negotiate, setup, disable fd */
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x98
;
val
|=
0x20
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
}
}
#ifdef DO_DXSUFLO
#ifdef DO_DXSUFLO
if
(
lp
->
dxsuflo
)
{
/* Disable transmit stop on underflow */
val
=
lp
->
a
.
read_csr
(
ioaddr
,
3
);
val
|=
0x40
;
...
...
@@ -914,16 +1220,20 @@ pcnet32_open(struct net_device *dev)
val
|=
(
1
<<
14
);
lp
->
a
.
write_csr
(
ioaddr
,
5
,
val
);
}
lp
->
init_block
.
mode
=
le16_to_cpu
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
<<
7
);
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
1
]
=
0x00000000
;
if
(
pcnet32_init_ring
(
dev
))
return
-
ENOMEM
;
if
(
pcnet32_init_ring
(
dev
))
{
rc
=
-
ENOMEM
;
goto
err_free_ring
;
}
/* Re-initialize the PCNET32, and start it when done. */
lp
->
a
.
write_csr
(
ioaddr
,
1
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
&
0xffff
);
lp
->
a
.
write_csr
(
ioaddr
,
2
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
>>
16
);
lp
->
a
.
write_csr
(
ioaddr
,
1
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
&
0xffff
);
lp
->
a
.
write_csr
(
ioaddr
,
2
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
>>
16
);
lp
->
a
.
write_csr
(
ioaddr
,
4
,
0x0915
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0001
);
...
...
@@ -935,24 +1245,47 @@ pcnet32_open(struct net_device *dev)
mii_check_media
(
&
lp
->
mii_if
,
1
,
1
);
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
}
i
=
0
;
while
(
i
++
<
100
)
if
(
lp
->
a
.
read_csr
(
ioaddr
,
0
)
&
0x0100
)
break
;
/*
/*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0042
);
if
(
pcnet32_debug
>
2
)
if
(
netif_msg_ifup
(
lp
)
)
printk
(
KERN_DEBUG
"%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.
\n
"
,
dev
->
name
,
i
,
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
)),
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
i
,
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
)),
lp
->
a
.
read_csr
(
ioaddr
,
0
));
return
0
;
/* Always succeed */
err_free_ring:
/* free any allocated skbuffs */
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
lp
->
rx_ring
[
i
].
status
=
0
;
if
(
lp
->
rx_skbuff
[
i
])
{
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
i
],
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
dev_kfree_skb
(
lp
->
rx_skbuff
[
i
]);
}
lp
->
rx_skbuff
[
i
]
=
NULL
;
lp
->
rx_dma_addr
[
i
]
=
0
;
}
/*
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
*/
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
4
);
err_free_irq:
free_irq
(
dev
->
irq
,
dev
);
return
rc
;
}
/*
...
...
@@ -968,7 +1301,7 @@ pcnet32_open(struct net_device *dev)
* restarting the chip, but I'm too lazy to do so right now. dplatt@3do.com
*/
static
void
static
void
pcnet32_purge_tx_ring
(
struct
net_device
*
dev
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
...
...
@@ -976,10 +1309,11 @@ pcnet32_purge_tx_ring(struct net_device *dev)
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
if
(
lp
->
tx_skbuff
[
i
])
{
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
i
],
lp
->
tx_skbuff
[
i
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_any
(
lp
->
tx_skbuff
[
i
]);
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
i
],
lp
->
tx_skbuff
[
i
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_any
(
lp
->
tx_skbuff
[
i
]);
lp
->
tx_skbuff
[
i
]
=
NULL
;
lp
->
tx_dma_addr
[
i
]
=
0
;
lp
->
tx_dma_addr
[
i
]
=
0
;
}
}
}
...
...
@@ -997,36 +1331,40 @@ pcnet32_init_ring(struct net_device *dev)
lp
->
dirty_rx
=
lp
->
dirty_tx
=
0
;
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
struct
sk_buff
*
rx_skbuff
=
lp
->
rx_skbuff
[
i
];
struct
sk_buff
*
rx_skbuff
=
lp
->
rx_skbuff
[
i
];
if
(
rx_skbuff
==
NULL
)
{
if
(
!
(
rx_skbuff
=
lp
->
rx_skbuff
[
i
]
=
dev_alloc_skb
(
PKT_BUF_SZ
)))
{
/* there is not much, we can do at this point */
printk
(
KERN_ERR
"%s: pcnet32_init_ring dev_alloc_skb failed.
\n
"
,
dev
->
name
);
printk
(
KERN_ERR
"%s: pcnet32_init_ring dev_alloc_skb failed.
\n
"
,
dev
->
name
);
return
-
1
;
}
skb_reserve
(
rx_skbuff
,
2
);
}
if
(
lp
->
rx_dma_addr
[
i
]
==
0
)
lp
->
rx_dma_addr
[
i
]
=
pci_map_single
(
lp
->
pci_dev
,
rx_skbuff
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
lp
->
rx_dma_addr
[
i
]
=
pci_map_single
(
lp
->
pci_dev
,
rx_skbuff
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
lp
->
rx_ring
[
i
].
base
=
(
u32
)
le32_to_cpu
(
lp
->
rx_dma_addr
[
i
]);
lp
->
rx_ring
[
i
].
buf_length
=
le16_to_cpu
(
2
-
PKT_BUF_SZ
);
lp
->
rx_ring
[
i
].
status
=
le16_to_cpu
(
0x8000
);
}
/* The Tx buffer address is filled in as needed, but we do need to clear
the upper ownership bit. */
*
the upper ownership bit. */
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
lp
->
tx_ring
[
i
].
base
=
0
;
lp
->
tx_ring
[
i
].
status
=
0
;
lp
->
tx_dma_addr
[
i
]
=
0
;
lp
->
tx_dma_addr
[
i
]
=
0
;
}
wmb
();
/* Make sure all changes are visible */
lp
->
init_block
.
tlen_rlen
=
le16_to_cpu
(
TX_RING_LEN_BITS
|
RX_RING_LEN_BITS
);
for
(
i
=
0
;
i
<
6
;
i
++
)
lp
->
init_block
.
phys_addr
[
i
]
=
dev
->
dev_addr
[
i
];
lp
->
init_block
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
rx_ring
));
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
lp
->
init_block
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
rx_ring
));
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
return
0
;
}
...
...
@@ -1036,11 +1374,11 @@ pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
i
;
pcnet32_purge_tx_ring
(
dev
);
if
(
pcnet32_init_ring
(
dev
))
return
;
/* ReInit Ring */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
1
);
i
=
0
;
...
...
@@ -1060,31 +1398,31 @@ pcnet32_tx_timeout (struct net_device *dev)
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
/* Transmitter timeout, serious problems. */
printk
(
KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
lp
->
stats
.
tx_errors
++
;
if
(
pcnet32_debug
>
2
)
{
int
i
;
printk
(
KERN_DEBUG
" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d."
,
lp
->
dirty_tx
,
lp
->
cur_tx
,
lp
->
tx_full
?
" (full)"
:
""
,
lp
->
cur_rx
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
rx_ring
[
i
].
base
,
-
lp
->
rx_ring
[
i
].
buf_length
,
lp
->
rx_ring
[
i
].
msg_length
,
(
unsigned
)
lp
->
rx_ring
[
i
].
status
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
tx_ring
[
i
].
base
,
-
lp
->
tx_ring
[
i
].
length
,
lp
->
tx_ring
[
i
].
misc
,
(
unsigned
)
lp
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
}
pcnet32_restart
(
dev
,
0x0042
);
printk
(
KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
lp
->
stats
.
tx_errors
++
;
if
(
netif_msg_tx_err
(
lp
)
)
{
int
i
;
printk
(
KERN_DEBUG
" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d."
,
lp
->
dirty_tx
,
lp
->
cur_tx
,
lp
->
tx_full
?
" (full)"
:
""
,
lp
->
cur_rx
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
rx_ring
[
i
].
base
,
-
lp
->
rx_ring
[
i
].
buf_length
,
lp
->
rx_ring
[
i
].
msg_length
,
(
unsigned
)
lp
->
rx_ring
[
i
].
status
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
tx_ring
[
i
].
base
,
-
lp
->
tx_ring
[
i
].
length
,
lp
->
tx_ring
[
i
].
misc
,
(
unsigned
)
lp
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
}
pcnet32_restart
(
dev
,
0x0042
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
}
...
...
@@ -1097,7 +1435,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
int
entry
;
unsigned
long
flags
;
if
(
pcnet32_debug
>
3
)
{
if
(
netif_msg_tx_queued
(
lp
)
)
{
printk
(
KERN_DEBUG
"%s: pcnet32_start_xmit() called, csr0 %4.4x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
}
...
...
@@ -1120,21 +1458,22 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
status
=
0x9300
;
}
/* Fill in a Tx ring entry */
/* Mask to ring buffer boundary. */
entry
=
lp
->
cur_tx
&
TX_RING_MOD_MASK
;
/* Caution: the write order is important here, set the status
with the "ownership" bits last. */
*
with the "ownership" bits last. */
lp
->
tx_ring
[
entry
].
length
=
le16_to_cpu
(
-
skb
->
len
);
lp
->
tx_ring
[
entry
].
misc
=
0x00000000
;
lp
->
tx_skbuff
[
entry
]
=
skb
;
lp
->
tx_dma_addr
[
entry
]
=
pci_map_single
(
lp
->
pci_dev
,
skb
->
data
,
skb
->
len
,
PCI_DMA_TODEVICE
);
lp
->
tx_dma_addr
[
entry
]
=
pci_map_single
(
lp
->
pci_dev
,
skb
->
data
,
skb
->
len
,
PCI_DMA_TODEVICE
);
lp
->
tx_ring
[
entry
].
base
=
(
u32
)
le32_to_cpu
(
lp
->
tx_dma_addr
[
entry
]);
wmb
();
/* Make sure owner changes after all others are visible */
lp
->
tx_ring
[
entry
].
status
=
le16_to_cpu
(
status
);
...
...
@@ -1147,9 +1486,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev
->
trans_start
=
jiffies
;
if
(
lp
->
tx_ring
[(
entry
+
1
)
&
TX_RING_MOD_MASK
].
base
==
0
)
netif_wake_queue
(
dev
);
else
{
if
(
lp
->
tx_ring
[(
entry
+
1
)
&
TX_RING_MOD_MASK
].
base
!=
0
)
{
lp
->
tx_full
=
1
;
netif_stop_queue
(
dev
);
}
...
...
@@ -1176,17 +1513,20 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr
=
dev
->
base_addr
;
lp
=
dev
->
priv
;
spin_lock
(
&
lp
->
lock
);
rap
=
lp
->
a
.
read_rap
(
ioaddr
);
while
((
csr0
=
lp
->
a
.
read_csr
(
ioaddr
,
0
))
&
0x8600
&&
--
boguscnt
>=
0
)
{
if
(
csr0
==
0xffff
)
{
break
;
/* PCMCIA remove happened */
}
/* Acknowledge all of the current interrupt sources ASAP. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
csr0
&
~
0x004f
);
must_restart
=
0
;
if
(
pcnet32_debug
>
5
)
if
(
netif_msg_intr
(
lp
)
)
printk
(
KERN_DEBUG
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.
\n
"
,
dev
->
name
,
csr0
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
...
@@ -1200,7 +1540,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
while
(
dirty_tx
!=
lp
->
cur_tx
)
{
int
entry
=
dirty_tx
&
TX_RING_MOD_MASK
;
int
status
=
(
short
)
le16_to_cpu
(
lp
->
tx_ring
[
entry
].
status
);
if
(
status
<
0
)
break
;
/* It still hasn't been Txed */
...
...
@@ -1242,11 +1582,11 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb */
if
(
lp
->
tx_skbuff
[
entry
])
{
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
entry
],
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
entry
],
lp
->
tx_skbuff
[
entry
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_irq
(
lp
->
tx_skbuff
[
entry
]);
lp
->
tx_skbuff
[
entry
]
=
0
;
lp
->
tx_dma_addr
[
entry
]
=
0
;
lp
->
tx_dma_addr
[
entry
]
=
0
;
}
dirty_tx
++
;
}
...
...
@@ -1275,11 +1615,12 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/*
* this happens when our receive ring is full. This shouldn't
* be a problem as we will see normal rx interrupts for the frames
* in the receive ring. But there are some PCI chipsets (I can reproduce
* this on SP3G with Intel saturn chipset) which have sometimes problems
* and will fill up the receive ring with error descriptors. In this
* situation we don't get a rx interrupt, but a missed frame interrupt sooner
* or later. So we try to clean up our receive ring here.
* in the receive ring. But there are some PCI chipsets (I can
* reproduce this on SP3G with Intel saturn chipset) which have
* sometimes problems and will fill up the receive ring with
* error descriptors. In this situation we don't get a rx
* interrupt, but a missed frame interrupt sooner or later.
* So we try to clean up our receive ring here.
*/
pcnet32_rx
(
dev
);
lp
->
stats
.
rx_errors
++
;
/* Missed a Rx frame. */
...
...
@@ -1300,8 +1641,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* Clear any other interrupt, and set interrupt enable. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x7940
);
lp
->
a
.
write_rap
(
ioaddr
,
rap
);
if
(
pcnet32_debug
>
4
)
if
(
netif_msg_intr
(
lp
)
)
printk
(
KERN_DEBUG
"%s: exiting interrupt, csr0=%#4.4x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
...
@@ -1321,7 +1662,7 @@ pcnet32_rx(struct net_device *dev)
int
status
=
(
short
)
le16_to_cpu
(
lp
->
rx_ring
[
entry
].
status
)
>>
8
;
if
(
status
!=
0x03
)
{
/* There was an error. */
/*
/*
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with full-sized
* buffers it's possible for a jabber packet to use two
...
...
@@ -1338,8 +1679,8 @@ pcnet32_rx(struct net_device *dev)
/* Malloc up new buffer, compatible with net-2e. */
short
pkt_len
=
(
le32_to_cpu
(
lp
->
rx_ring
[
entry
].
msg_length
)
&
0xfff
)
-
4
;
struct
sk_buff
*
skb
;
if
(
pkt_len
<
60
)
{
if
(
pkt_len
<
60
)
{
printk
(
KERN_ERR
"%s: Runt packet!
\n
"
,
dev
->
name
);
lp
->
stats
.
rx_errors
++
;
}
else
{
...
...
@@ -1347,8 +1688,8 @@ pcnet32_rx(struct net_device *dev)
if
(
pkt_len
>
rx_copybreak
)
{
struct
sk_buff
*
newskb
;
if
((
newskb
=
dev_alloc_skb
(
PKT_BUF_SZ
)))
{
if
((
newskb
=
dev_alloc_skb
(
PKT_BUF_SZ
)))
{
skb_reserve
(
newskb
,
2
);
skb
=
lp
->
rx_skbuff
[
entry
];
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
entry
],
...
...
@@ -1356,22 +1697,24 @@ pcnet32_rx(struct net_device *dev)
skb_put
(
skb
,
pkt_len
);
lp
->
rx_skbuff
[
entry
]
=
newskb
;
newskb
->
dev
=
dev
;
lp
->
rx_dma_addr
[
entry
]
=
pci_map_single
(
lp
->
pci_dev
,
newskb
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
lp
->
rx_dma_addr
[
entry
]
=
pci_map_single
(
lp
->
pci_dev
,
newskb
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
lp
->
rx_ring
[
entry
].
base
=
le32_to_cpu
(
lp
->
rx_dma_addr
[
entry
]);
rx_in_place
=
1
;
}
else
skb
=
NULL
;
}
else
{
skb
=
dev_alloc_skb
(
pkt_len
+
2
);
}
}
if
(
skb
==
NULL
)
{
int
i
;
printk
(
KERN_ERR
"%s: Memory squeeze, deferring packet.
\n
"
,
dev
->
name
);
int
i
;
printk
(
KERN_ERR
"%s: Memory squeeze, deferring packet.
\n
"
,
dev
->
name
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
if
((
short
)
le16_to_cpu
(
lp
->
rx_ring
[(
entry
+
i
)
&
RX_RING_MOD_MASK
].
status
)
<
0
)
if
((
short
)
le16_to_cpu
(
lp
->
rx_ring
[(
entry
+
i
)
&
RX_RING_MOD_MASK
].
status
)
<
0
)
break
;
if
(
i
>
RX_RING_SIZE
-
2
)
{
...
...
@@ -1390,8 +1733,8 @@ pcnet32_rx(struct net_device *dev)
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
eth_copy_and_sum
(
skb
,
(
unsigned
char
*
)(
lp
->
rx_skbuff
[
entry
]
->
tail
),
pkt_len
,
0
);
(
unsigned
char
*
)(
lp
->
rx_skbuff
[
entry
]
->
tail
),
pkt_len
,
0
);
}
lp
->
stats
.
rx_bytes
+=
skb
->
len
;
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
...
...
@@ -1405,6 +1748,7 @@ pcnet32_rx(struct net_device *dev)
* of QNX reports that some revs of the 79C965 clear it.
*/
lp
->
rx_ring
[
entry
].
buf_length
=
le16_to_cpu
(
2
-
PKT_BUF_SZ
);
wmb
();
/* Make sure owner changes after all others are visible */
lp
->
rx_ring
[
entry
].
status
|=
le16_to_cpu
(
0x8000
);
entry
=
(
++
lp
->
cur_rx
)
&
RX_RING_MOD_MASK
;
}
...
...
@@ -1425,7 +1769,7 @@ pcnet32_close(struct net_device *dev)
lp
->
stats
.
rx_missed_errors
=
lp
->
a
.
read_csr
(
ioaddr
,
112
);
if
(
pcnet32_debug
>
1
)
if
(
netif_msg_ifdown
(
lp
)
)
printk
(
KERN_DEBUG
"%s: Shutting down ethercard, status was %2.2x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
...
@@ -1433,34 +1777,35 @@ pcnet32_close(struct net_device *dev)
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/*
* Switch back to 16bit mode to avoid problems with dumb
* Switch back to 16bit mode to avoid problems with dumb
* DOS packet driver after a warm reboot
*/
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
4
);
free_irq
(
dev
->
irq
,
dev
);
/* free all allocated skbuffs */
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
lp
->
rx_ring
[
i
].
status
=
0
;
lp
->
rx_ring
[
i
].
status
=
0
;
if
(
lp
->
rx_skbuff
[
i
])
{
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
i
],
PKT_BUF_SZ
-
2
,
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
i
],
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
dev_kfree_skb
(
lp
->
rx_skbuff
[
i
]);
}
}
lp
->
rx_skbuff
[
i
]
=
NULL
;
lp
->
rx_dma_addr
[
i
]
=
0
;
lp
->
rx_dma_addr
[
i
]
=
0
;
}
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
if
(
lp
->
tx_skbuff
[
i
])
{
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
i
],
lp
->
tx_skbuff
[
i
]
->
len
,
PCI_DMA_TODEVICE
);
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
tx_dma_addr
[
i
],
lp
->
tx_skbuff
[
i
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb
(
lp
->
tx_skbuff
[
i
]);
}
}
lp
->
tx_skbuff
[
i
]
=
NULL
;
lp
->
tx_dma_addr
[
i
]
=
0
;
lp
->
tx_dma_addr
[
i
]
=
0
;
}
return
0
;
}
...
...
@@ -1491,9 +1836,9 @@ static void pcnet32_load_multicast (struct net_device *dev)
char
*
addrs
;
int
i
;
u32
crc
;
/* set all multicast bits */
if
(
dev
->
flags
&
IFF_ALLMULTI
)
{
if
(
dev
->
flags
&
IFF_ALLMULTI
)
{
ib
->
filter
[
0
]
=
0xffffffff
;
ib
->
filter
[
1
]
=
0xffffffff
;
return
;
...
...
@@ -1503,19 +1848,18 @@ static void pcnet32_load_multicast (struct net_device *dev)
ib
->
filter
[
1
]
=
0
;
/* Add addresses */
for
(
i
=
0
;
i
<
dev
->
mc_count
;
i
++
){
for
(
i
=
0
;
i
<
dev
->
mc_count
;
i
++
)
{
addrs
=
dmi
->
dmi_addr
;
dmi
=
dmi
->
next
;
/* multicast address? */
if
(
!
(
*
addrs
&
1
))
continue
;
crc
=
ether_crc_le
(
6
,
addrs
);
crc
=
crc
>>
26
;
mcast_table
[
crc
>>
4
]
=
le16_to_cpu
(
le16_to_cpu
(
mcast_table
[
crc
>>
4
])
|
(
1
<<
(
crc
&
0xf
))
);
le16_to_cpu
(
mcast_table
[
crc
>>
4
])
|
(
1
<<
(
crc
&
0xf
)));
}
return
;
}
...
...
@@ -1527,7 +1871,7 @@ static void pcnet32_load_multicast (struct net_device *dev)
static
void
pcnet32_set_multicast_list
(
struct
net_device
*
dev
)
{
unsigned
long
ioaddr
=
dev
->
base_addr
,
flags
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
if
(
dev
->
flags
&
IFF_PROMISC
)
{
...
...
@@ -1538,7 +1882,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
lp
->
init_block
.
mode
=
le16_to_cpu
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
<<
7
);
pcnet32_load_multicast
(
dev
);
}
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/* Temporarily stop the lance. */
pcnet32_restart
(
dev
,
0x0042
);
/* Resume normal operation */
...
...
@@ -1547,143 +1891,46 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
u16
val_out
;
int
phyaddr
;
if
(
!
lp
->
mii
)
return
0
;
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
((
phy_id
&
0x1f
)
<<
5
)
|
(
reg_num
&
0x1f
));
val_out
=
lp
->
a
.
read_bcr
(
ioaddr
,
34
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
phyaddr
);
return
val_out
;
}
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
u16
val_out
;
int
phyaddr
;
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
,
int
val
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
phyaddr
;
if
(
!
lp
->
mii
)
return
0
;
if
(
!
lp
->
mii
)
return
;
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
((
phy_id
&
0x1f
)
<<
5
)
|
(
reg_num
&
0x1f
));
lp
->
a
.
write_bcr
(
ioaddr
,
34
,
val
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
phyaddr
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
((
phy_id
&
0x1f
)
<<
5
)
|
(
reg_num
&
0x1f
));
val_out
=
lp
->
a
.
read_bcr
(
ioaddr
,
34
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
phyaddr
);
return
val_out
;
}
static
int
pcnet32_ethtool_ioctl
(
struct
net_device
*
dev
,
void
*
useraddr
)
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
,
int
val
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
u32
ethcmd
;
int
phyaddr
=
0
;
int
phy_id
=
0
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
if
(
lp
->
mii
)
{
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
phy_id
=
(
phyaddr
>>
5
)
&
0x1f
;
lp
->
mii_if
.
phy_id
=
phy_id
;
}
if
(
copy_from_user
(
&
ethcmd
,
useraddr
,
sizeof
(
ethcmd
)))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GDRVINFO
:
{
struct
ethtool_drvinfo
info
=
{
ETHTOOL_GDRVINFO
};
strcpy
(
info
.
driver
,
DRV_NAME
);
strcpy
(
info
.
version
,
DRV_VERSION
);
if
(
lp
->
pci_dev
)
strcpy
(
info
.
bus_info
,
pci_name
(
lp
->
pci_dev
));
else
sprintf
(
info
.
bus_info
,
"VLB 0x%lx"
,
dev
->
base_addr
);
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
phyaddr
;
/* get settings */
case
ETHTOOL_GSET
:
{
struct
ethtool_cmd
ecmd
=
{
ETHTOOL_GSET
};
spin_lock_irq
(
&
lp
->
lock
);
mii_ethtool_gset
(
&
lp
->
mii_if
,
&
ecmd
);
spin_unlock_irq
(
&
lp
->
lock
);
if
(
copy_to_user
(
useraddr
,
&
ecmd
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
return
0
;
}
/* set settings */
case
ETHTOOL_SSET
:
{
int
r
;
struct
ethtool_cmd
ecmd
;
if
(
copy_from_user
(
&
ecmd
,
useraddr
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
spin_lock_irq
(
&
lp
->
lock
);
r
=
mii_ethtool_sset
(
&
lp
->
mii_if
,
&
ecmd
);
spin_unlock_irq
(
&
lp
->
lock
);
return
r
;
}
/* restart autonegotiation */
case
ETHTOOL_NWAY_RST
:
{
int
r
;
spin_lock_irq
(
&
lp
->
lock
);
r
=
mii_nway_restart
(
&
lp
->
mii_if
);
spin_unlock_irq
(
&
lp
->
lock
);
return
r
;
}
/* get link status */
case
ETHTOOL_GLINK
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
spin_lock_irq
(
&
lp
->
lock
);
edata
.
data
=
mii_link_ok
(
&
lp
->
mii_if
);
spin_unlock_irq
(
&
lp
->
lock
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
if
(
!
lp
->
mii
)
return
;
/* get message-level */
case
ETHTOOL_GMSGLVL
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GMSGLVL
};
edata
.
data
=
pcnet32_debug
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
/* set message-level */
case
ETHTOOL_SMSGLVL
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
pcnet32_debug
=
edata
.
data
;
return
0
;
}
default:
break
;
}
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
return
-
EOPNOTSUPP
;
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
((
phy_id
&
0x1f
)
<<
5
)
|
(
reg_num
&
0x1f
));
lp
->
a
.
write_bcr
(
ioaddr
,
34
,
val
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
phyaddr
);
}
static
int
pcnet32_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
mii_ioctl_data
*
data
=
(
struct
mii_ioctl_data
*
)
&
rq
->
ifr_data
;
int
rc
;
unsigned
long
flags
;
if
(
cmd
==
SIOCETHTOOL
)
return
pcnet32_ethtool_ioctl
(
dev
,
(
void
*
)
rq
->
ifr_data
);
/* SIOC[GS]MIIxxx ioctls */
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
...
...
@@ -1711,24 +1958,40 @@ static void pcnet32_watchdog(struct net_device *dev)
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
}
static
void
__devexit
pcnet32_remove_one
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
if
(
dev
)
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unregister_netdev
(
dev
);
release_region
(
dev
->
base_addr
,
PCNET32_TOTAL_SIZE
);
pci_free_consistent
(
lp
->
pci_dev
,
sizeof
(
*
lp
),
lp
,
lp
->
dma_addr
);
free_netdev
(
dev
);
pci_set_drvdata
(
pdev
,
NULL
);
}
}
static
struct
pci_driver
pcnet32_driver
=
{
.
name
=
DRV_NAME
,
.
probe
=
pcnet32_probe_pci
,
.
remove
=
__devexit_p
(
pcnet32_remove_one
),
.
id_table
=
pcnet32_pci_tbl
,
};
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM_DESC
(
debug
,
DRV_NAME
" debug level
(0-6)
"
);
MODULE_PARM_DESC
(
debug
,
DRV_NAME
" debug level"
);
MODULE_PARM
(
max_interrupt_work
,
"i"
);
MODULE_PARM_DESC
(
max_interrupt_work
,
DRV_NAME
" maximum events handled per interrupt"
);
MODULE_PARM_DESC
(
max_interrupt_work
,
DRV_NAME
" maximum events handled per interrupt"
);
MODULE_PARM
(
rx_copybreak
,
"i"
);
MODULE_PARM_DESC
(
rx_copybreak
,
DRV_NAME
" copy breakpoint for copy-only-tiny-frames"
);
MODULE_PARM_DESC
(
rx_copybreak
,
DRV_NAME
" copy breakpoint for copy-only-tiny-frames"
);
MODULE_PARM
(
tx_start_pt
,
"i"
);
MODULE_PARM_DESC
(
tx_start_pt
,
DRV_NAME
" transmit start point (0-3)"
);
MODULE_PARM_DESC
(
tx_start_pt
,
DRV_NAME
" transmit start point (0-3)"
);
MODULE_PARM
(
pcnet32vlb
,
"i"
);
MODULE_PARM_DESC
(
pcnet32vlb
,
DRV_NAME
" Vesa local bus (VLB) support (0/1)"
);
MODULE_PARM_DESC
(
pcnet32vlb
,
DRV_NAME
" Vesa local bus (VLB) support (0/1)"
);
MODULE_PARM
(
options
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM_DESC
(
options
,
DRV_NAME
" initial option setting(s) (0-15)"
);
MODULE_PARM_DESC
(
options
,
DRV_NAME
" initial option setting(s) (0-15)"
);
MODULE_PARM
(
full_duplex
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM_DESC
(
full_duplex
,
DRV_NAME
" full duplex setting(s) (1)"
);
...
...
@@ -1745,8 +2008,8 @@ static int __init pcnet32_init_module(void)
{
printk
(
KERN_INFO
"%s"
,
version
);
if
(
debug
>
0
)
pcnet32_debug
=
debug
;
if
(
debug
>
=
0
&&
debug
<
(
sizeof
(
int
)
-
1
)
)
pcnet32_debug
=
1
<<
debug
;
if
((
tx_start_pt
>=
0
)
&&
(
tx_start_pt
<=
3
))
tx_start
=
tx_start_pt
;
...
...
@@ -1761,7 +2024,7 @@ static int __init pcnet32_init_module(void)
if
(
cards_found
)
printk
(
KERN_INFO
PFX
"%d cards_found.
\n
"
,
cards_found
);
return
(
pcnet32_have_pci
+
cards_found
)
?
0
:
-
ENODEV
;
}
...
...
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