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
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. */
/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
/*
/*
* Copyright 1996-1999 Thomas Bogendoerfer
* Copyright 1996-1999 Thomas Bogendoerfer
*
*
* Derived from the lance driver written 1993,1994,1995 by Donald Becker.
* Derived from the lance driver written 1993,1994,1995 by Donald Becker.
*
*
* Copyright 1993 United States Government as represented by the
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency.
* Director, National Security Agency.
*
*
* This software may be used and distributed according to the terms
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
* of the GNU General Public License, incorporated herein by reference.
*
*
...
@@ -22,8 +22,8 @@
...
@@ -22,8 +22,8 @@
*************************************************************************/
*************************************************************************/
#define DRV_NAME "pcnet32"
#define DRV_NAME "pcnet32"
#define DRV_VERSION "1.2
7b
"
#define DRV_VERSION "1.2
8
"
#define DRV_RELDATE "0
1.10.2002
"
#define DRV_RELDATE "0
2.20.2004
"
#define PFX DRV_NAME ": "
#define PFX DRV_NAME ": "
static
const
char
*
version
=
static
const
char
*
version
=
...
@@ -58,6 +58,12 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
...
@@ -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
[]
=
{
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_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
},
{
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
,
}
{
0
,
}
};
};
...
@@ -65,15 +71,15 @@ MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
...
@@ -65,15 +71,15 @@ MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
int
cards_found
__initdata
;
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
};
{
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
tx_start
=
1
;
/* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
static
int
pcnet32vlb
;
/* check for VLB cards ? */
static
int
pcnet32vlb
;
/* check for VLB cards ? */
...
@@ -103,7 +109,7 @@ static int rx_copybreak = 200;
...
@@ -103,7 +109,7 @@ static int rx_copybreak = 200;
static
unsigned
char
options_mapping
[]
=
{
static
unsigned
char
options_mapping
[]
=
{
PCNET32_PORT_ASEL
,
/* 0 Auto-select */
PCNET32_PORT_ASEL
,
/* 0 Auto-select */
PCNET32_PORT_AUI
,
/* 1 BNC/AUI */
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_ASEL
,
/* 3 not supported */
PCNET32_PORT_10BT
|
PCNET32_PORT_FD
,
/* 4 10baseT-FD */
PCNET32_PORT_10BT
|
PCNET32_PORT_FD
,
/* 4 10baseT-FD */
PCNET32_PORT_ASEL
,
/* 5 not supported */
PCNET32_PORT_ASEL
,
/* 5 not supported */
...
@@ -119,20 +125,25 @@ static unsigned char options_mapping[] = {
...
@@ -119,20 +125,25 @@ static unsigned char options_mapping[] = {
PCNET32_PORT_ASEL
/* 15 not supported */
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 */
#define MAX_UNITS 8
/* More are supported, limit only on options */
static
int
options
[
MAX_UNITS
];
static
int
options
[
MAX_UNITS
];
static
int
full_duplex
[
MAX_UNITS
];
static
int
full_duplex
[
MAX_UNITS
];
/*
/*
* Theory of Operation
* Theory of Operation
*
*
* This driver uses the same software structure as the normal lance
* This driver uses the same software structure as the normal lance
* driver. So look for a verbose description in lance.c. The differences
* 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
* 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
* and PCnetPCI chips. Because these chips are 32bit chips, there is no
* 16MB limitation and we don't need bounce buffers.
* 16MB limitation and we don't need bounce buffers.
*/
*/
/*
/*
* History:
* History:
* v0.01: Initial version
* v0.01: Initial version
...
@@ -186,7 +197,7 @@ static int full_duplex[MAX_UNITS];
...
@@ -186,7 +197,7 @@ static int full_duplex[MAX_UNITS];
* v1.22: changed pci scanning code to make PPC people happy
* v1.22: changed pci scanning code to make PPC people happy
* fixed switching to 32bit mode in pcnet32_open() (thanks
* fixed switching to 32bit mode in pcnet32_open() (thanks
* to Michael Richard <mcr@solidum.com> for noticing this one)
* 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>)
* Michael Richard <mcr@solidum.com>)
* added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
* added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
* v1.23 fixed small bug, when manual selecting MII speed/duplex
* v1.23 fixed small bug, when manual selecting MII speed/duplex
...
@@ -204,7 +215,7 @@ static int full_duplex[MAX_UNITS];
...
@@ -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.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
* v1.27 improved CSR/PROM address detection, lots of cleanups,
* v1.27 improved CSR/PROM address detection, lots of cleanups,
* new pcnet32vlb module option, HP-PARISC support,
* new pcnet32vlb module option, HP-PARISC support,
* added module parameter descriptions,
* added module parameter descriptions,
* initial ethtool support - Helge Deller <deller@gmx.de>
* initial ethtool support - Helge Deller <deller@gmx.de>
* v1.27a Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
* v1.27a Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
* use alloc_etherdev and register_netdev
* use alloc_etherdev and register_netdev
...
@@ -213,6 +224,11 @@ static int full_duplex[MAX_UNITS];
...
@@ -213,6 +224,11 @@ static int full_duplex[MAX_UNITS];
* clean up and using new mii module
* clean up and using new mii module
* v1.27b Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
* v1.27b Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
* Added timer for cable connection state changes.
* 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];
...
@@ -253,11 +269,11 @@ static int full_duplex[MAX_UNITS];
struct
pcnet32_rx_head
{
struct
pcnet32_rx_head
{
u32
base
;
u32
base
;
s16
buf_length
;
s16
buf_length
;
s16
status
;
s16
status
;
u32
msg_length
;
u32
msg_length
;
u32
reserved
;
u32
reserved
;
};
};
struct
pcnet32_tx_head
{
struct
pcnet32_tx_head
{
u32
base
;
u32
base
;
s16
length
;
s16
length
;
...
@@ -273,7 +289,7 @@ struct pcnet32_init_block {
...
@@ -273,7 +289,7 @@ struct pcnet32_init_block {
u8
phys_addr
[
6
];
u8
phys_addr
[
6
];
u16
reserved
;
u16
reserved
;
u32
filter
[
2
];
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
rx_ring
;
u32
tx_ring
;
u32
tx_ring
;
};
};
...
@@ -290,7 +306,7 @@ struct pcnet32_access {
...
@@ -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().
* so we allocate the structure should be allocated by pci_alloc_consistent().
*/
*/
struct
pcnet32_private
{
struct
pcnet32_private
{
...
@@ -298,16 +314,18 @@ struct pcnet32_private {
...
@@ -298,16 +314,18 @@ struct pcnet32_private {
struct
pcnet32_rx_head
rx_ring
[
RX_RING_SIZE
];
struct
pcnet32_rx_head
rx_ring
[
RX_RING_SIZE
];
struct
pcnet32_tx_head
tx_ring
[
TX_RING_SIZE
];
struct
pcnet32_tx_head
tx_ring
[
TX_RING_SIZE
];
struct
pcnet32_init_block
init_block
;
struct
pcnet32_init_block
init_block
;
dma_addr_t
dma_addr
;
/* DMA address of beginning of this object,
dma_addr_t
dma_addr
;
/* DMA address of beginning of this
returned by pci_alloc_consistent */
object, returned by
struct
pci_dev
*
pci_dev
;
/* Pointer to the associated pci device structure */
pci_alloc_consistent */
struct
pci_dev
*
pci_dev
;
/* Pointer to the associated pci device
structure */
const
char
*
name
;
const
char
*
name
;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct
sk_buff
*
tx_skbuff
[
TX_RING_SIZE
];
struct
sk_buff
*
tx_skbuff
[
TX_RING_SIZE
];
struct
sk_buff
*
rx_skbuff
[
RX_RING_SIZE
];
struct
sk_buff
*
rx_skbuff
[
RX_RING_SIZE
];
dma_addr_t
tx_dma_addr
[
TX_RING_SIZE
];
dma_addr_t
tx_dma_addr
[
TX_RING_SIZE
];
dma_addr_t
rx_dma_addr
[
RX_RING_SIZE
];
dma_addr_t
rx_dma_addr
[
RX_RING_SIZE
];
struct
pcnet32_access
a
;
struct
pcnet32_access
a
;
spinlock_t
lock
;
/* Guard lock */
spinlock_t
lock
;
/* Guard lock */
unsigned
int
cur_rx
,
cur_tx
;
/* The next free ring entry */
unsigned
int
cur_rx
,
cur_tx
;
/* The next free ring entry */
unsigned
int
dirty_rx
,
dirty_tx
;
/* The ring entries to be free()ed. */
unsigned
int
dirty_rx
,
dirty_tx
;
/* The ring entries to be free()ed. */
...
@@ -319,8 +337,9 @@ struct pcnet32_private {
...
@@ -319,8 +337,9 @@ struct pcnet32_private {
dxsuflo:
1
,
/* disable transmit stop on uflo */
dxsuflo:
1
,
/* disable transmit stop on uflo */
mii:
1
;
/* mii port available */
mii:
1
;
/* mii port available */
struct
net_device
*
next
;
struct
net_device
*
next
;
struct
mii_if_info
mii_if
;
struct
mii_if_info
mii_if
;
struct
timer_list
watchdog_timer
;
struct
timer_list
watchdog_timer
;
u32
msg_enable
;
/* debug message level */
};
};
static
void
pcnet32_probe_vlbus
(
void
);
static
void
pcnet32_probe_vlbus
(
void
);
...
@@ -339,6 +358,10 @@ static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);
...
@@ -339,6 +358,10 @@ static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);
static
void
pcnet32_watchdog
(
struct
net_device
*
);
static
void
pcnet32_watchdog
(
struct
net_device
*
);
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
);
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
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
{
enum
pci_flags_bit
{
PCI_USES_IO
=
1
,
PCI_USES_MEM
=
2
,
PCI_USES_MASTER
=
4
,
PCI_USES_IO
=
1
,
PCI_USES_MEM
=
2
,
PCI_USES_MASTER
=
4
,
...
@@ -458,23 +481,290 @@ static struct pcnet32_access pcnet32_dwio = {
...
@@ -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 */
* pci_register_driver via pcnet32_probe_pci */
static
void
__devinit
static
void
__devinit
pcnet32_probe_vlbus
(
void
)
pcnet32_probe_vlbus
(
void
)
{
{
unsigned
int
*
port
,
ioaddr
;
unsigned
int
*
port
,
ioaddr
;
/* search for PCnet32 VLB cards at known addresses */
/* search for PCnet32 VLB cards at known addresses */
for
(
port
=
pcnet32_portlist
;
(
ioaddr
=
*
port
);
port
++
)
{
for
(
port
=
pcnet32_portlist
;
(
ioaddr
=
*
port
);
port
++
)
{
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_vlbus"
))
{
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_vlbus"
))
{
/* check if there is really a pcnet chip on that ioaddr */
/* check if there is really a pcnet chip on that ioaddr */
if
((
inb
(
ioaddr
+
14
)
==
0x57
)
&&
(
inb
(
ioaddr
+
15
)
==
0x57
))
{
if
((
inb
(
ioaddr
+
14
)
==
0x57
)
&&
(
inb
(
ioaddr
+
15
)
==
0x57
))
{
pcnet32_probe1
(
ioaddr
,
0
,
0
,
NULL
);
pcnet32_probe1
(
ioaddr
,
0
,
0
,
NULL
);
}
else
{
}
else
{
release_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
);
release_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
);
}
}
}
}
}
}
}
}
...
@@ -495,25 +785,25 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -495,25 +785,25 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr
=
pci_resource_start
(
pdev
,
0
);
ioaddr
=
pci_resource_start
(
pdev
,
0
);
if
(
!
ioaddr
)
{
if
(
!
ioaddr
)
{
printk
(
KERN_ERR
PFX
"card has no PCI IO resources, aborting
\n
"
);
printk
(
KERN_ERR
PFX
"card has no PCI IO resources, aborting
\n
"
);
return
-
ENODEV
;
return
-
ENODEV
;
}
}
if
(
!
pci_dma_supported
(
pdev
,
PCNET32_DMA_MASK
))
{
if
(
!
pci_dma_supported
(
pdev
,
PCNET32_DMA_MASK
))
{
printk
(
KERN_ERR
PFX
"architecture does not support 32bit PCI busmaster DMA
\n
"
);
printk
(
KERN_ERR
PFX
"architecture does not support 32bit PCI busmaster DMA
\n
"
);
return
-
ENODEV
;
return
-
ENODEV
;
}
}
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_pci"
)
==
NULL
)
{
if
(
request_region
(
ioaddr
,
PCNET32_TOTAL_SIZE
,
"pcnet32_probe_pci"
)
==
NULL
)
{
printk
(
KERN_ERR
PFX
"io address range already allocated
\n
"
);
printk
(
KERN_ERR
PFX
"io address range already allocated
\n
"
);
return
-
EBUSY
;
return
-
EBUSY
;
}
}
return
pcnet32_probe1
(
ioaddr
,
pdev
->
irq
,
1
,
pdev
);
return
pcnet32_probe1
(
ioaddr
,
pdev
->
irq
,
1
,
pdev
);
}
}
/* pcnet32_probe1
/* pcnet32_probe1
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
* pdev will be NULL when called from pcnet32_probe_vlbus.
* pdev will be NULL when called from pcnet32_probe_vlbus.
*/
*/
static
int
__devinit
static
int
__devinit
...
@@ -546,11 +836,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -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
);
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
);
printk
(
KERN_INFO
" PCnet chip version is %#x.
\n
"
,
chip_version
);
if
((
chip_version
&
0xfff
)
!=
0x003
)
if
((
chip_version
&
0xfff
)
!=
0x003
)
{
goto
err_release_region
;
printk
(
KERN_INFO
PFX
"Unsupported chip version.
\n
"
);
goto
err_release_region
;
}
/* initialize variables */
/* initialize variables */
fdx
=
mii
=
fset
=
dxsuflo
=
ltint
=
0
;
fdx
=
mii
=
fset
=
dxsuflo
=
ltint
=
0
;
chip_version
=
(
chip_version
>>
12
)
&
0xffff
;
chip_version
=
(
chip_version
>>
12
)
&
0xffff
;
...
@@ -585,7 +877,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -585,7 +877,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
case
0x2626
:
case
0x2626
:
chipname
=
"PCnet/Home 79C978"
;
/* PCI */
chipname
=
"PCnet/Home 79C978"
;
/* PCI */
fdx
=
1
;
fdx
=
1
;
/*
/*
* This is based on specs published at www.amd.com. This section
* 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
* assumes that a card with a 79C978 wants to go into 1Mb HomePNA
* mode. The 79C978 can also go into standard ethernet, and there
* 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,
...
@@ -594,13 +886,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
*/
*/
/* switch to home wiring mode */
/* switch to home wiring mode */
media
=
a
->
read_bcr
(
ioaddr
,
49
);
media
=
a
->
read_bcr
(
ioaddr
,
49
);
#if 0
if
(
pcnet32_debug
&
NETIF_MSG_PROBE
)
if (pcnet32_debug > 2)
printk(KERN_DEBUG PFX "media value %#x.\n", media);
media &= ~3;
media |= 1;
#endif
if
(
pcnet32_debug
>
2
)
printk
(
KERN_DEBUG
PFX
"media reset to %#x.
\n
"
,
media
);
printk
(
KERN_DEBUG
PFX
"media reset to %#x.
\n
"
,
media
);
a
->
write_bcr
(
ioaddr
,
49
,
media
);
a
->
write_bcr
(
ioaddr
,
49
,
media
);
break
;
break
;
...
@@ -610,29 +896,29 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -610,29 +896,29 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
break
;
break
;
default:
default:
printk
(
KERN_INFO
PFX
"PCnet version %#x, no PCnet32 chip.
\n
"
,
printk
(
KERN_INFO
PFX
"PCnet version %#x, no PCnet32 chip.
\n
"
,
chip_version
);
chip_version
);
goto
err_release_region
;
goto
err_release_region
;
}
}
/*
/*
* On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
* On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
* starting until the packet is loaded. Strike one for reliability, lose
* 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.
* 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_bcr
(
ioaddr
,
18
,
(
a
->
read_bcr
(
ioaddr
,
18
)
|
0x0800
));
a
->
write_csr
(
ioaddr
,
80
,
(
a
->
read_csr
(
ioaddr
,
80
)
&
0x0C00
)
|
0x0c00
);
a
->
write_csr
(
ioaddr
,
80
,
(
a
->
read_csr
(
ioaddr
,
80
)
&
0x0C00
)
|
0x0c00
);
dxsuflo
=
1
;
dxsuflo
=
1
;
ltint
=
1
;
ltint
=
1
;
}
}
dev
=
alloc_etherdev
(
0
);
dev
=
alloc_etherdev
(
0
);
if
(
!
dev
)
{
if
(
!
dev
)
{
ret
=
-
ENOMEM
;
printk
(
KERN_ERR
PFX
"Memory allocation failed.
\n
"
);
goto
err_release_region
;
ret
=
-
ENOMEM
;
goto
err_release_region
;
}
}
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
...
@@ -656,13 +942,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -656,13 +942,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
/* read PROM address and compare with CSR address */
/* read PROM address and compare with CSR address */
for
(
i
=
0
;
i
<
6
;
i
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
promaddr
[
i
]
=
inb
(
ioaddr
+
i
);
promaddr
[
i
]
=
inb
(
ioaddr
+
i
);
if
(
memcmp
(
promaddr
,
dev
->
dev_addr
,
6
)
if
(
memcmp
(
promaddr
,
dev
->
dev_addr
,
6
)
||
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
{
||
!
is_valid_ether_addr
(
dev
->
dev_addr
))
{
#ifndef __powerpc__
#ifndef __powerpc__
if
(
is_valid_ether_addr
(
promaddr
)
)
{
if
(
is_valid_ether_addr
(
promaddr
))
{
#else
#else
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
&&
is_valid_ether_addr
(
promaddr
))
{
&&
is_valid_ether_addr
(
promaddr
))
{
#endif
#endif
printk
(
" warning: CSR address invalid,
\n
"
);
printk
(
" warning: CSR address invalid,
\n
"
);
...
@@ -672,13 +958,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -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 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
));
memset
(
dev
->
dev_addr
,
0
,
sizeof
(
dev
->
dev_addr
));
for
(
i
=
0
;
i
<
6
;
i
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
printk
(
" %2.2x"
,
dev
->
dev_addr
[
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 */
i
=
a
->
read_csr
(
ioaddr
,
80
)
&
0x0C00
;
/* Check tx_start_pt */
printk
(
"
\n
"
KERN_INFO
" tx_start_pt(0x%04x):"
,
i
);
printk
(
"
\n
"
KERN_INFO
" tx_start_pt(0x%04x):"
,
i
);
switch
(
i
>>
10
)
{
switch
(
i
>>
10
)
{
...
@@ -704,6 +990,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -704,6 +990,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
dev
->
base_addr
=
ioaddr
;
dev
->
base_addr
=
ioaddr
;
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
/* 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
)
{
if
((
lp
=
pci_alloc_consistent
(
pdev
,
sizeof
(
*
lp
),
&
lp_dma_addr
))
==
NULL
)
{
printk
(
KERN_ERR
PFX
"Consistent memory allocation failed.
\n
"
);
ret
=
-
ENOMEM
;
ret
=
-
ENOMEM
;
goto
err_free_netdev
;
goto
err_free_netdev
;
}
}
...
@@ -713,7 +1000,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -713,7 +1000,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
pci_dev
=
pdev
;
lp
->
pci_dev
=
pdev
;
spin_lock_init
(
&
lp
->
lock
);
spin_lock_init
(
&
lp
->
lock
);
SET_MODULE_OWNER
(
dev
);
SET_MODULE_OWNER
(
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
dev
->
priv
=
lp
;
dev
->
priv
=
lp
;
...
@@ -725,6 +1012,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -725,6 +1012,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
dxsuflo
=
dxsuflo
;
lp
->
dxsuflo
=
dxsuflo
;
lp
->
ltint
=
ltint
;
lp
->
ltint
=
ltint
;
lp
->
mii
=
mii
;
lp
->
mii
=
mii
;
lp
->
msg_enable
=
pcnet32_debug
;
if
((
cards_found
>=
MAX_UNITS
)
||
(
options
[
cards_found
]
>
sizeof
(
options_mapping
)))
if
((
cards_found
>=
MAX_UNITS
)
||
(
options
[
cards_found
]
>
sizeof
(
options_mapping
)))
lp
->
options
=
PCNET32_PORT_ASEL
;
lp
->
options
=
PCNET32_PORT_ASEL
;
else
else
...
@@ -732,46 +1020,51 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -732,46 +1020,51 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
lp
->
mii_if
.
dev
=
dev
;
lp
->
mii_if
.
dev
=
dev
;
lp
->
mii_if
.
mdio_read
=
mdio_read
;
lp
->
mii_if
.
mdio_read
=
mdio_read
;
lp
->
mii_if
.
mdio_write
=
mdio_write
;
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
]))
((
cards_found
>=
MAX_UNITS
)
||
full_duplex
[
cards_found
]))
lp
->
options
|=
PCNET32_PORT_FD
;
lp
->
options
|=
PCNET32_PORT_FD
;
if
(
!
a
)
{
if
(
!
a
)
{
printk
(
KERN_ERR
PFX
"No access methods
\n
"
);
printk
(
KERN_ERR
PFX
"No access methods
\n
"
);
ret
=
-
ENODEV
;
ret
=
-
ENODEV
;
goto
err_free_consistent
;
goto
err_free_consistent
;
}
}
lp
->
a
=
*
a
;
lp
->
a
=
*
a
;
/* detect special T1/E1 WAN card by checking for MAC address */
/* 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
->
options
=
PCNET32_PORT_FD
|
PCNET32_PORT_GPSI
;
lp
->
init_block
.
mode
=
le16_to_cpu
(
0x0003
);
/* Disable Rx and Tx. */
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
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
lp
->
init_block
.
phys_addr
[
i
]
=
dev
->
dev_addr
[
i
];
lp
->
init_block
.
phys_addr
[
i
]
=
dev
->
dev_addr
[
i
];
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
1
]
=
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
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
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 */
/* 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
)
{
if
(
irq_line
)
{
dev
->
irq
=
irq_line
;
dev
->
irq
=
irq_line
;
}
}
if
(
dev
->
irq
>=
2
)
if
(
dev
->
irq
>=
2
)
printk
(
" assigned IRQ %d.
\n
"
,
dev
->
irq
);
printk
(
" assigned IRQ %d.
\n
"
,
dev
->
irq
);
else
{
else
{
unsigned
long
irq_mask
=
probe_irq_on
();
unsigned
long
irq_mask
=
probe_irq_on
();
/*
/*
* To auto-IRQ we enable the initialization-done and DMA error
* To auto-IRQ we enable the initialization-done and DMA error
* interrupts. For ISA boards we get a DMA error, but VLB and PCI
* 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,
...
@@ -780,7 +1073,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
/* Trigger an initialization just for the interrupt. */
/* Trigger an initialization just for the interrupt. */
a
->
write_csr
(
ioaddr
,
0
,
0x41
);
a
->
write_csr
(
ioaddr
,
0
,
0x41
);
mdelay
(
1
);
mdelay
(
1
);
dev
->
irq
=
probe_irq_off
(
irq_mask
);
dev
->
irq
=
probe_irq_off
(
irq_mask
);
if
(
!
dev
->
irq
)
{
if
(
!
dev
->
irq
)
{
printk
(
", failed to detect IRQ line.
\n
"
);
printk
(
", failed to detect IRQ line.
\n
"
);
...
@@ -797,7 +1090,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -797,7 +1090,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
init_timer
(
&
lp
->
watchdog_timer
);
init_timer
(
&
lp
->
watchdog_timer
);
lp
->
watchdog_timer
.
data
=
(
unsigned
long
)
dev
;
lp
->
watchdog_timer
.
data
=
(
unsigned
long
)
dev
;
lp
->
watchdog_timer
.
function
=
(
void
*
)
&
pcnet32_watchdog
;
lp
->
watchdog_timer
.
function
=
(
void
*
)
&
pcnet32_watchdog
;
/* The PCNET32-specific entries in the device structure. */
/* The PCNET32-specific entries in the device structure. */
dev
->
open
=
&
pcnet32_open
;
dev
->
open
=
&
pcnet32_open
;
dev
->
hard_start_xmit
=
&
pcnet32_start_xmit
;
dev
->
hard_start_xmit
=
&
pcnet32_start_xmit
;
...
@@ -805,6 +1098,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -805,6 +1098,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
dev
->
get_stats
=
&
pcnet32_get_stats
;
dev
->
get_stats
=
&
pcnet32_get_stats
;
dev
->
set_multicast_list
=
&
pcnet32_set_multicast_list
;
dev
->
set_multicast_list
=
&
pcnet32_set_multicast_list
;
dev
->
do_ioctl
=
&
pcnet32_ioctl
;
dev
->
do_ioctl
=
&
pcnet32_ioctl
;
dev
->
ethtool_ops
=
&
pcnet32_ethtool_ops
;
dev
->
tx_timeout
=
pcnet32_tx_timeout
;
dev
->
tx_timeout
=
pcnet32_tx_timeout
;
dev
->
watchdog_timeo
=
(
5
*
HZ
);
dev
->
watchdog_timeo
=
(
5
*
HZ
);
...
@@ -812,8 +1106,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
...
@@ -812,8 +1106,13 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
if
(
register_netdev
(
dev
))
if
(
register_netdev
(
dev
))
goto
err_free_consistent
;
goto
err_free_consistent
;
lp
->
next
=
pcnet32_dev
;
if
(
pdev
)
{
pcnet32_dev
=
dev
;
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
);
printk
(
KERN_INFO
"%s: registered as %s
\n
"
,
dev
->
name
,
lp
->
name
);
cards_found
++
;
cards_found
++
;
return
0
;
return
0
;
...
@@ -835,6 +1134,7 @@ pcnet32_open(struct net_device *dev)
...
@@ -835,6 +1134,7 @@ pcnet32_open(struct net_device *dev)
unsigned
long
ioaddr
=
dev
->
base_addr
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
u16
val
;
u16
val
;
int
i
;
int
i
;
int
rc
;
if
(
dev
->
irq
==
0
||
if
(
dev
->
irq
==
0
||
request_irq
(
dev
->
irq
,
&
pcnet32_interrupt
,
request_irq
(
dev
->
irq
,
&
pcnet32_interrupt
,
...
@@ -843,8 +1143,10 @@ pcnet32_open(struct net_device *dev)
...
@@ -843,8 +1143,10 @@ pcnet32_open(struct net_device *dev)
}
}
/* Check for a valid station address */
/* Check for a valid station address */
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
)
)
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
))
{
return
-
EINVAL
;
rc
=
-
EINVAL
;
goto
err_free_irq
;
}
/* Reset the PCNET32 */
/* Reset the PCNET32 */
lp
->
a
.
reset
(
ioaddr
);
lp
->
a
.
reset
(
ioaddr
);
...
@@ -852,19 +1154,19 @@ pcnet32_open(struct net_device *dev)
...
@@ -852,19 +1154,19 @@ pcnet32_open(struct net_device *dev)
/* switch pcnet32 to 32bit mode */
/* switch pcnet32 to 32bit mode */
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
2
);
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
"
,
printk
(
KERN_DEBUG
"%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.
\n
"
,
dev
->
name
,
dev
->
irq
,
dev
->
name
,
dev
->
irq
,
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
)),
(
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
,
rx_ring
)),
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
)));
(
u32
)
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
)));
/* set/reset autoselect bit */
/* set/reset autoselect bit */
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
2
)
&
~
2
;
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
2
)
&
~
2
;
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
val
|=
2
;
val
|=
2
;
lp
->
a
.
write_bcr
(
ioaddr
,
2
,
val
);
lp
->
a
.
write_bcr
(
ioaddr
,
2
,
val
);
/* handle full duplex setting */
/* handle full duplex setting */
if
(
lp
->
mii_if
.
full_duplex
)
{
if
(
lp
->
mii_if
.
full_duplex
)
{
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
9
)
&
~
3
;
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
9
)
&
~
3
;
...
@@ -874,34 +1176,38 @@ pcnet32_open(struct net_device *dev)
...
@@ -874,34 +1176,38 @@ pcnet32_open(struct net_device *dev)
val
|=
2
;
val
|=
2
;
}
else
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
}
else
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
/* workaround of xSeries250, turn on for 79C975 only */
/* workaround of xSeries250, turn on for 79C975 only */
i
=
((
lp
->
a
.
read_csr
(
ioaddr
,
88
)
|
(
lp
->
a
.
read_csr
(
ioaddr
,
89
)
<<
16
))
>>
12
)
&
0xffff
;
i
=
((
lp
->
a
.
read_csr
(
ioaddr
,
88
)
|
if
(
i
==
0x2627
)
val
|=
3
;
(
lp
->
a
.
read_csr
(
ioaddr
,
89
)
<<
16
))
>>
12
)
&
0xffff
;
if
(
i
==
0x2627
)
val
|=
3
;
}
}
lp
->
a
.
write_bcr
(
ioaddr
,
9
,
val
);
lp
->
a
.
write_bcr
(
ioaddr
,
9
,
val
);
}
}
/* set/reset GPSI bit in test register */
/* set/reset GPSI bit in test register */
val
=
lp
->
a
.
read_csr
(
ioaddr
,
124
)
&
~
0x10
;
val
=
lp
->
a
.
read_csr
(
ioaddr
,
124
)
&
~
0x10
;
if
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
==
PCNET32_PORT_GPSI
)
if
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
==
PCNET32_PORT_GPSI
)
val
|=
0x10
;
val
|=
0x10
;
lp
->
a
.
write_csr
(
ioaddr
,
124
,
val
);
lp
->
a
.
write_csr
(
ioaddr
,
124
,
val
);
if
(
lp
->
mii
&&
!
(
lp
->
options
&
PCNET32_PORT_ASEL
))
{
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
)
if
(
lp
->
options
&
PCNET32_PORT_FD
)
val
|=
0x10
;
val
|=
0x10
;
if
(
lp
->
options
&
PCNET32_PORT_100
)
if
(
lp
->
options
&
PCNET32_PORT_100
)
val
|=
0x08
;
val
|=
0x08
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
}
else
{
}
else
{
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
/* enable auto negotiate, setup, disable fd */
if
(
lp
->
options
&
PCNET32_PORT_ASEL
)
{
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x98
;
/* enable auto negotiate, setup, disable fd */
val
|=
0x20
;
val
=
lp
->
a
.
read_bcr
(
ioaddr
,
32
)
&
~
0x98
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
val
|=
0x20
;
lp
->
a
.
write_bcr
(
ioaddr
,
32
,
val
);
}
}
}
}
#ifdef DO_DXSUFLO
#ifdef DO_DXSUFLO
if
(
lp
->
dxsuflo
)
{
/* Disable transmit stop on underflow */
if
(
lp
->
dxsuflo
)
{
/* Disable transmit stop on underflow */
val
=
lp
->
a
.
read_csr
(
ioaddr
,
3
);
val
=
lp
->
a
.
read_csr
(
ioaddr
,
3
);
val
|=
0x40
;
val
|=
0x40
;
...
@@ -914,16 +1220,20 @@ pcnet32_open(struct net_device *dev)
...
@@ -914,16 +1220,20 @@ pcnet32_open(struct net_device *dev)
val
|=
(
1
<<
14
);
val
|=
(
1
<<
14
);
lp
->
a
.
write_csr
(
ioaddr
,
5
,
val
);
lp
->
a
.
write_csr
(
ioaddr
,
5
,
val
);
}
}
lp
->
init_block
.
mode
=
le16_to_cpu
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
<<
7
);
lp
->
init_block
.
mode
=
le16_to_cpu
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
<<
7
);
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
0
]
=
0x00000000
;
lp
->
init_block
.
filter
[
1
]
=
0x00000000
;
lp
->
init_block
.
filter
[
1
]
=
0x00000000
;
if
(
pcnet32_init_ring
(
dev
))
if
(
pcnet32_init_ring
(
dev
))
{
return
-
ENOMEM
;
rc
=
-
ENOMEM
;
goto
err_free_ring
;
}
/* Re-initialize the PCNET32, and start it when done. */
/* 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
,
1
,
(
lp
->
dma_addr
+
lp
->
a
.
write_csr
(
ioaddr
,
2
,
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
init_block
))
>>
16
);
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
,
4
,
0x0915
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0001
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0001
);
...
@@ -935,24 +1245,47 @@ pcnet32_open(struct net_device *dev)
...
@@ -935,24 +1245,47 @@ pcnet32_open(struct net_device *dev)
mii_check_media
(
&
lp
->
mii_if
,
1
,
1
);
mii_check_media
(
&
lp
->
mii_if
,
1
,
1
);
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
}
}
i
=
0
;
i
=
0
;
while
(
i
++
<
100
)
while
(
i
++
<
100
)
if
(
lp
->
a
.
read_csr
(
ioaddr
,
0
)
&
0x0100
)
if
(
lp
->
a
.
read_csr
(
ioaddr
,
0
)
&
0x0100
)
break
;
break
;
/*
/*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
* reports that doing so triggers a bug in the '974.
*/
*/
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0042
);
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
"
,
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
)),
dev
->
name
,
i
,
(
u32
)
(
lp
->
dma_addr
+
lp
->
a
.
read_csr
(
ioaddr
,
0
));
offsetof
(
struct
pcnet32_private
,
init_block
)),
lp
->
a
.
read_csr
(
ioaddr
,
0
));
return
0
;
/* Always succeed */
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)
...
@@ -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
* 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
)
pcnet32_purge_tx_ring
(
struct
net_device
*
dev
)
{
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
...
@@ -976,10 +1309,11 @@ pcnet32_purge_tx_ring(struct net_device *dev)
...
@@ -976,10 +1309,11 @@ pcnet32_purge_tx_ring(struct net_device *dev)
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
if
(
lp
->
tx_skbuff
[
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
],
dev_kfree_skb_any
(
lp
->
tx_skbuff
[
i
]);
lp
->
tx_skbuff
[
i
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_any
(
lp
->
tx_skbuff
[
i
]);
lp
->
tx_skbuff
[
i
]
=
NULL
;
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)
...
@@ -997,36 +1331,40 @@ pcnet32_init_ring(struct net_device *dev)
lp
->
dirty_rx
=
lp
->
dirty_tx
=
0
;
lp
->
dirty_rx
=
lp
->
dirty_tx
=
0
;
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
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
==
NULL
)
{
if
(
!
(
rx_skbuff
=
lp
->
rx_skbuff
[
i
]
=
dev_alloc_skb
(
PKT_BUF_SZ
)))
{
if
(
!
(
rx_skbuff
=
lp
->
rx_skbuff
[
i
]
=
dev_alloc_skb
(
PKT_BUF_SZ
)))
{
/* there is not much, we can do at this point */
/* 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
;
return
-
1
;
}
}
skb_reserve
(
rx_skbuff
,
2
);
skb_reserve
(
rx_skbuff
,
2
);
}
}
if
(
lp
->
rx_dma_addr
[
i
]
==
0
)
if
(
lp
->
rx_dma_addr
[
i
]
==
0
)
lp
->
rx_dma_addr
[
i
]
=
pci_map_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
i
]
=
pci_map_single
(
lp
->
pci_dev
,
rx_skbuff
->
tail
,
rx_skbuff
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
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
].
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
].
buf_length
=
le16_to_cpu
(
2
-
PKT_BUF_SZ
);
lp
->
rx_ring
[
i
].
status
=
le16_to_cpu
(
0x8000
);
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 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
++
)
{
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
lp
->
tx_ring
[
i
].
base
=
0
;
lp
->
tx_ring
[
i
].
base
=
0
;
lp
->
tx_ring
[
i
].
status
=
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
);
lp
->
init_block
.
tlen_rlen
=
le16_to_cpu
(
TX_RING_LEN_BITS
|
RX_RING_LEN_BITS
);
for
(
i
=
0
;
i
<
6
;
i
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
lp
->
init_block
.
phys_addr
[
i
]
=
dev
->
dev_addr
[
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
.
rx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
lp
->
init_block
.
tx_ring
=
(
u32
)
le32_to_cpu
(
lp
->
dma_addr
+
offsetof
(
struct
pcnet32_private
,
tx_ring
));
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
;
return
0
;
}
}
...
@@ -1036,11 +1374,11 @@ pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
...
@@ -1036,11 +1374,11 @@ pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
i
;
int
i
;
pcnet32_purge_tx_ring
(
dev
);
pcnet32_purge_tx_ring
(
dev
);
if
(
pcnet32_init_ring
(
dev
))
if
(
pcnet32_init_ring
(
dev
))
return
;
return
;
/* ReInit Ring */
/* ReInit Ring */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
1
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
1
);
i
=
0
;
i
=
0
;
...
@@ -1060,31 +1398,31 @@ pcnet32_tx_timeout (struct net_device *dev)
...
@@ -1060,31 +1398,31 @@ pcnet32_tx_timeout (struct net_device *dev)
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
/* Transmitter timeout, serious problems. */
/* Transmitter timeout, serious problems. */
printk
(
KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.
\n
"
,
printk
(
KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
lp
->
stats
.
tx_errors
++
;
lp
->
stats
.
tx_errors
++
;
if
(
pcnet32_debug
>
2
)
{
if
(
netif_msg_tx_err
(
lp
)
)
{
int
i
;
int
i
;
printk
(
KERN_DEBUG
" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d."
,
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
->
dirty_tx
,
lp
->
cur_tx
,
lp
->
tx_full
?
" (full)"
:
""
,
lp
->
cur_rx
);
lp
->
cur_rx
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
rx_ring
[
i
].
base
,
-
lp
->
rx_ring
[
i
].
buf_length
,
lp
->
rx_ring
[
i
].
base
,
-
lp
->
rx_ring
[
i
].
buf_length
,
lp
->
rx_ring
[
i
].
msg_length
,
(
unsigned
)
lp
->
rx_ring
[
i
].
status
);
lp
->
rx_ring
[
i
].
msg_length
,
(
unsigned
)
lp
->
rx_ring
[
i
].
status
);
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
printk
(
"%s %08x %04x %08x %04x"
,
i
&
1
?
""
:
"
\n
"
,
lp
->
tx_ring
[
i
].
base
,
-
lp
->
tx_ring
[
i
].
length
,
lp
->
tx_ring
[
i
].
base
,
-
lp
->
tx_ring
[
i
].
length
,
lp
->
tx_ring
[
i
].
misc
,
(
unsigned
)
lp
->
tx_ring
[
i
].
status
);
lp
->
tx_ring
[
i
].
misc
,
(
unsigned
)
lp
->
tx_ring
[
i
].
status
);
printk
(
"
\n
"
);
printk
(
"
\n
"
);
}
}
pcnet32_restart
(
dev
,
0x0042
);
pcnet32_restart
(
dev
,
0x0042
);
dev
->
trans_start
=
jiffies
;
dev
->
trans_start
=
jiffies
;
netif_wake_queue
(
dev
);
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)
...
@@ -1097,7 +1435,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
int
entry
;
int
entry
;
unsigned
long
flags
;
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
"
,
printk
(
KERN_DEBUG
"%s: pcnet32_start_xmit() called, csr0 %4.4x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
}
}
...
@@ -1120,21 +1458,22 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1120,21 +1458,22 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
*/
status
=
0x9300
;
status
=
0x9300
;
}
}
/* Fill in a Tx ring entry */
/* Fill in a Tx ring entry */
/* Mask to ring buffer boundary. */
/* Mask to ring buffer boundary. */
entry
=
lp
->
cur_tx
&
TX_RING_MOD_MASK
;
entry
=
lp
->
cur_tx
&
TX_RING_MOD_MASK
;
/* Caution: the write order is important here, set the status
/* 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
].
length
=
le16_to_cpu
(
-
skb
->
len
);
lp
->
tx_ring
[
entry
].
misc
=
0x00000000
;
lp
->
tx_ring
[
entry
].
misc
=
0x00000000
;
lp
->
tx_skbuff
[
entry
]
=
skb
;
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
]);
lp
->
tx_ring
[
entry
].
base
=
(
u32
)
le32_to_cpu
(
lp
->
tx_dma_addr
[
entry
]);
wmb
();
/* Make sure owner changes after all others are visible */
wmb
();
/* Make sure owner changes after all others are visible */
lp
->
tx_ring
[
entry
].
status
=
le16_to_cpu
(
status
);
lp
->
tx_ring
[
entry
].
status
=
le16_to_cpu
(
status
);
...
@@ -1147,9 +1486,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1147,9 +1486,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev
->
trans_start
=
jiffies
;
dev
->
trans_start
=
jiffies
;
if
(
lp
->
tx_ring
[(
entry
+
1
)
&
TX_RING_MOD_MASK
].
base
==
0
)
if
(
lp
->
tx_ring
[(
entry
+
1
)
&
TX_RING_MOD_MASK
].
base
!=
0
)
{
netif_wake_queue
(
dev
);
else
{
lp
->
tx_full
=
1
;
lp
->
tx_full
=
1
;
netif_stop_queue
(
dev
);
netif_stop_queue
(
dev
);
}
}
...
@@ -1176,17 +1513,20 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
...
@@ -1176,17 +1513,20 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr
=
dev
->
base_addr
;
ioaddr
=
dev
->
base_addr
;
lp
=
dev
->
priv
;
lp
=
dev
->
priv
;
spin_lock
(
&
lp
->
lock
);
spin_lock
(
&
lp
->
lock
);
rap
=
lp
->
a
.
read_rap
(
ioaddr
);
rap
=
lp
->
a
.
read_rap
(
ioaddr
);
while
((
csr0
=
lp
->
a
.
read_csr
(
ioaddr
,
0
))
&
0x8600
&&
--
boguscnt
>=
0
)
{
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. */
/* Acknowledge all of the current interrupt sources ASAP. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
csr0
&
~
0x004f
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
csr0
&
~
0x004f
);
must_restart
=
0
;
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
"
,
printk
(
KERN_DEBUG
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.
\n
"
,
dev
->
name
,
csr0
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
csr0
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
@@ -1200,7 +1540,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
...
@@ -1200,7 +1540,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
while
(
dirty_tx
!=
lp
->
cur_tx
)
{
while
(
dirty_tx
!=
lp
->
cur_tx
)
{
int
entry
=
dirty_tx
&
TX_RING_MOD_MASK
;
int
entry
=
dirty_tx
&
TX_RING_MOD_MASK
;
int
status
=
(
short
)
le16_to_cpu
(
lp
->
tx_ring
[
entry
].
status
);
int
status
=
(
short
)
le16_to_cpu
(
lp
->
tx_ring
[
entry
].
status
);
if
(
status
<
0
)
if
(
status
<
0
)
break
;
/* It still hasn't been Txed */
break
;
/* It still hasn't been Txed */
...
@@ -1242,11 +1582,11 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
...
@@ -1242,11 +1582,11 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb */
/* We must free the original skb */
if
(
lp
->
tx_skbuff
[
entry
])
{
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
);
lp
->
tx_skbuff
[
entry
]
->
len
,
PCI_DMA_TODEVICE
);
dev_kfree_skb_irq
(
lp
->
tx_skbuff
[
entry
]);
dev_kfree_skb_irq
(
lp
->
tx_skbuff
[
entry
]);
lp
->
tx_skbuff
[
entry
]
=
0
;
lp
->
tx_skbuff
[
entry
]
=
0
;
lp
->
tx_dma_addr
[
entry
]
=
0
;
lp
->
tx_dma_addr
[
entry
]
=
0
;
}
}
dirty_tx
++
;
dirty_tx
++
;
}
}
...
@@ -1275,11 +1615,12 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
...
@@ -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
* this happens when our receive ring is full. This shouldn't
* be a problem as we will see normal rx interrupts for the frames
* 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
* in the receive ring. But there are some PCI chipsets (I can
* this on SP3G with Intel saturn chipset) which have sometimes problems
* reproduce this on SP3G with Intel saturn chipset) which have
* and will fill up the receive ring with error descriptors. In this
* sometimes problems and will fill up the receive ring with
* situation we don't get a rx interrupt, but a missed frame interrupt sooner
* error descriptors. In this situation we don't get a rx
* or later. So we try to clean up our receive ring here.
* interrupt, but a missed frame interrupt sooner or later.
* So we try to clean up our receive ring here.
*/
*/
pcnet32_rx
(
dev
);
pcnet32_rx
(
dev
);
lp
->
stats
.
rx_errors
++
;
/* Missed a Rx frame. */
lp
->
stats
.
rx_errors
++
;
/* Missed a Rx frame. */
...
@@ -1300,8 +1641,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
...
@@ -1300,8 +1641,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* Clear any other interrupt, and set interrupt enable. */
/* Clear any other interrupt, and set interrupt enable. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x7940
);
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x7940
);
lp
->
a
.
write_rap
(
ioaddr
,
rap
);
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
"
,
printk
(
KERN_DEBUG
"%s: exiting interrupt, csr0=%#4.4x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
@@ -1321,7 +1662,7 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1321,7 +1662,7 @@ pcnet32_rx(struct net_device *dev)
int
status
=
(
short
)
le16_to_cpu
(
lp
->
rx_ring
[
entry
].
status
)
>>
8
;
int
status
=
(
short
)
le16_to_cpu
(
lp
->
rx_ring
[
entry
].
status
)
>>
8
;
if
(
status
!=
0x03
)
{
/* There was an error. */
if
(
status
!=
0x03
)
{
/* There was an error. */
/*
/*
* There is a tricky error noted by John Murphy,
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with full-sized
* <murf@perftech.com> to Russ Nelson: Even with full-sized
* buffers it's possible for a jabber packet to use two
* buffers it's possible for a jabber packet to use two
...
@@ -1338,8 +1679,8 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1338,8 +1679,8 @@ pcnet32_rx(struct net_device *dev)
/* Malloc up new buffer, compatible with net-2e. */
/* Malloc up new buffer, compatible with net-2e. */
short
pkt_len
=
(
le32_to_cpu
(
lp
->
rx_ring
[
entry
].
msg_length
)
&
0xfff
)
-
4
;
short
pkt_len
=
(
le32_to_cpu
(
lp
->
rx_ring
[
entry
].
msg_length
)
&
0xfff
)
-
4
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
if
(
pkt_len
<
60
)
{
if
(
pkt_len
<
60
)
{
printk
(
KERN_ERR
"%s: Runt packet!
\n
"
,
dev
->
name
);
printk
(
KERN_ERR
"%s: Runt packet!
\n
"
,
dev
->
name
);
lp
->
stats
.
rx_errors
++
;
lp
->
stats
.
rx_errors
++
;
}
else
{
}
else
{
...
@@ -1347,8 +1688,8 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1347,8 +1688,8 @@ pcnet32_rx(struct net_device *dev)
if
(
pkt_len
>
rx_copybreak
)
{
if
(
pkt_len
>
rx_copybreak
)
{
struct
sk_buff
*
newskb
;
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_reserve
(
newskb
,
2
);
skb
=
lp
->
rx_skbuff
[
entry
];
skb
=
lp
->
rx_skbuff
[
entry
];
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
entry
],
pci_unmap_single
(
lp
->
pci_dev
,
lp
->
rx_dma_addr
[
entry
],
...
@@ -1356,22 +1697,24 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1356,22 +1697,24 @@ pcnet32_rx(struct net_device *dev)
skb_put
(
skb
,
pkt_len
);
skb_put
(
skb
,
pkt_len
);
lp
->
rx_skbuff
[
entry
]
=
newskb
;
lp
->
rx_skbuff
[
entry
]
=
newskb
;
newskb
->
dev
=
dev
;
newskb
->
dev
=
dev
;
lp
->
rx_dma_addr
[
entry
]
=
lp
->
rx_dma_addr
[
entry
]
=
pci_map_single
(
lp
->
pci_dev
,
newskb
->
tail
,
pci_map_single
(
lp
->
pci_dev
,
newskb
->
tail
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
lp
->
rx_ring
[
entry
].
base
=
le32_to_cpu
(
lp
->
rx_dma_addr
[
entry
]);
lp
->
rx_ring
[
entry
].
base
=
le32_to_cpu
(
lp
->
rx_dma_addr
[
entry
]);
rx_in_place
=
1
;
rx_in_place
=
1
;
}
else
}
else
skb
=
NULL
;
skb
=
NULL
;
}
else
{
}
else
{
skb
=
dev_alloc_skb
(
pkt_len
+
2
);
skb
=
dev_alloc_skb
(
pkt_len
+
2
);
}
}
if
(
skb
==
NULL
)
{
if
(
skb
==
NULL
)
{
int
i
;
int
i
;
printk
(
KERN_ERR
"%s: Memory squeeze, deferring packet.
\n
"
,
dev
->
name
);
printk
(
KERN_ERR
"%s: Memory squeeze, deferring packet.
\n
"
,
dev
->
name
);
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
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
;
break
;
if
(
i
>
RX_RING_SIZE
-
2
)
{
if
(
i
>
RX_RING_SIZE
-
2
)
{
...
@@ -1390,8 +1733,8 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1390,8 +1733,8 @@ pcnet32_rx(struct net_device *dev)
PKT_BUF_SZ
-
2
,
PKT_BUF_SZ
-
2
,
PCI_DMA_FROMDEVICE
);
PCI_DMA_FROMDEVICE
);
eth_copy_and_sum
(
skb
,
eth_copy_and_sum
(
skb
,
(
unsigned
char
*
)(
lp
->
rx_skbuff
[
entry
]
->
tail
),
(
unsigned
char
*
)(
lp
->
rx_skbuff
[
entry
]
->
tail
),
pkt_len
,
0
);
pkt_len
,
0
);
}
}
lp
->
stats
.
rx_bytes
+=
skb
->
len
;
lp
->
stats
.
rx_bytes
+=
skb
->
len
;
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
...
@@ -1405,6 +1748,7 @@ pcnet32_rx(struct net_device *dev)
...
@@ -1405,6 +1748,7 @@ pcnet32_rx(struct net_device *dev)
* of QNX reports that some revs of the 79C965 clear it.
* of QNX reports that some revs of the 79C965 clear it.
*/
*/
lp
->
rx_ring
[
entry
].
buf_length
=
le16_to_cpu
(
2
-
PKT_BUF_SZ
);
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
);
lp
->
rx_ring
[
entry
].
status
|=
le16_to_cpu
(
0x8000
);
entry
=
(
++
lp
->
cur_rx
)
&
RX_RING_MOD_MASK
;
entry
=
(
++
lp
->
cur_rx
)
&
RX_RING_MOD_MASK
;
}
}
...
@@ -1425,7 +1769,7 @@ pcnet32_close(struct net_device *dev)
...
@@ -1425,7 +1769,7 @@ pcnet32_close(struct net_device *dev)
lp
->
stats
.
rx_missed_errors
=
lp
->
a
.
read_csr
(
ioaddr
,
112
);
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
"
,
printk
(
KERN_DEBUG
"%s: Shutting down ethercard, status was %2.2x.
\n
"
,
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
dev
->
name
,
lp
->
a
.
read_csr
(
ioaddr
,
0
));
...
@@ -1433,34 +1777,35 @@ pcnet32_close(struct net_device *dev)
...
@@ -1433,34 +1777,35 @@ pcnet32_close(struct net_device *dev)
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
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
* DOS packet driver after a warm reboot
*/
*/
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
4
);
lp
->
a
.
write_bcr
(
ioaddr
,
20
,
4
);
free_irq
(
dev
->
irq
,
dev
);
free_irq
(
dev
->
irq
,
dev
);
/* free all allocated skbuffs */
/* free all allocated skbuffs */
for
(
i
=
0
;
i
<
RX_RING_SIZE
;
i
++
)
{
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
])
{
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
);
PCI_DMA_FROMDEVICE
);
dev_kfree_skb
(
lp
->
rx_skbuff
[
i
]);
dev_kfree_skb
(
lp
->
rx_skbuff
[
i
]);
}
}
lp
->
rx_skbuff
[
i
]
=
NULL
;
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
++
)
{
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
if
(
lp
->
tx_skbuff
[
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
]);
dev_kfree_skb
(
lp
->
tx_skbuff
[
i
]);
}
}
lp
->
tx_skbuff
[
i
]
=
NULL
;
lp
->
tx_skbuff
[
i
]
=
NULL
;
lp
->
tx_dma_addr
[
i
]
=
0
;
lp
->
tx_dma_addr
[
i
]
=
0
;
}
}
return
0
;
return
0
;
}
}
...
@@ -1491,9 +1836,9 @@ static void pcnet32_load_multicast (struct net_device *dev)
...
@@ -1491,9 +1836,9 @@ static void pcnet32_load_multicast (struct net_device *dev)
char
*
addrs
;
char
*
addrs
;
int
i
;
int
i
;
u32
crc
;
u32
crc
;
/* set all multicast bits */
/* set all multicast bits */
if
(
dev
->
flags
&
IFF_ALLMULTI
)
{
if
(
dev
->
flags
&
IFF_ALLMULTI
)
{
ib
->
filter
[
0
]
=
0xffffffff
;
ib
->
filter
[
0
]
=
0xffffffff
;
ib
->
filter
[
1
]
=
0xffffffff
;
ib
->
filter
[
1
]
=
0xffffffff
;
return
;
return
;
...
@@ -1503,19 +1848,18 @@ static void pcnet32_load_multicast (struct net_device *dev)
...
@@ -1503,19 +1848,18 @@ static void pcnet32_load_multicast (struct net_device *dev)
ib
->
filter
[
1
]
=
0
;
ib
->
filter
[
1
]
=
0
;
/* Add addresses */
/* Add addresses */
for
(
i
=
0
;
i
<
dev
->
mc_count
;
i
++
){
for
(
i
=
0
;
i
<
dev
->
mc_count
;
i
++
)
{
addrs
=
dmi
->
dmi_addr
;
addrs
=
dmi
->
dmi_addr
;
dmi
=
dmi
->
next
;
dmi
=
dmi
->
next
;
/* multicast address? */
/* multicast address? */
if
(
!
(
*
addrs
&
1
))
if
(
!
(
*
addrs
&
1
))
continue
;
continue
;
crc
=
ether_crc_le
(
6
,
addrs
);
crc
=
ether_crc_le
(
6
,
addrs
);
crc
=
crc
>>
26
;
crc
=
crc
>>
26
;
mcast_table
[
crc
>>
4
]
=
le16_to_cpu
(
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
;
return
;
}
}
...
@@ -1527,7 +1871,7 @@ static void pcnet32_load_multicast (struct net_device *dev)
...
@@ -1527,7 +1871,7 @@ static void pcnet32_load_multicast (struct net_device *dev)
static
void
pcnet32_set_multicast_list
(
struct
net_device
*
dev
)
static
void
pcnet32_set_multicast_list
(
struct
net_device
*
dev
)
{
{
unsigned
long
ioaddr
=
dev
->
base_addr
,
flags
;
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
);
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
if
(
dev
->
flags
&
IFF_PROMISC
)
{
if
(
dev
->
flags
&
IFF_PROMISC
)
{
...
@@ -1538,7 +1882,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
...
@@ -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
);
lp
->
init_block
.
mode
=
le16_to_cpu
((
lp
->
options
&
PCNET32_PORT_PORTSEL
)
<<
7
);
pcnet32_load_multicast
(
dev
);
pcnet32_load_multicast
(
dev
);
}
}
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/* Temporarily stop the lance. */
lp
->
a
.
write_csr
(
ioaddr
,
0
,
0x0004
);
/* Temporarily stop the lance. */
pcnet32_restart
(
dev
,
0x0042
);
/* Resume normal operation */
pcnet32_restart
(
dev
,
0x0042
);
/* Resume normal operation */
...
@@ -1547,143 +1891,46 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
...
@@ -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
)
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
)
{
{
struct
pcnet32_private
*
lp
=
dev
->
priv
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
u16
val_out
;
u16
val_out
;
int
phyaddr
;
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
;
}
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg_num
,
int
val
)
if
(
!
lp
->
mii
)
{
return
0
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
phyaddr
;
if
(
!
lp
->
mii
)
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
return
;
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
,
33
,
((
phy_id
&
0x1f
)
<<
5
)
|
(
reg_num
&
0x1f
));
lp
->
a
.
write_bcr
(
ioaddr
,
34
,
val
);
val_out
=
lp
->
a
.
read_bcr
(
ioaddr
,
34
);
lp
->
a
.
write_bcr
(
ioaddr
,
33
,
phyaddr
);
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
;
struct
pcnet32_private
*
lp
=
dev
->
priv
;
u32
ethcmd
;
unsigned
long
ioaddr
=
dev
->
base_addr
;
int
phyaddr
=
0
;
int
phyaddr
;
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
;
}
/* get settings */
if
(
!
lp
->
mii
)
case
ETHTOOL_GSET
:
{
return
;
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
;
}
/* get message-level */
phyaddr
=
lp
->
a
.
read_bcr
(
ioaddr
,
33
);
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
;
}
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
)
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
;
struct
mii_ioctl_data
*
data
=
(
struct
mii_ioctl_data
*
)
&
rq
->
ifr_data
;
int
rc
;
int
rc
;
unsigned
long
flags
;
unsigned
long
flags
;
if
(
cmd
==
SIOCETHTOOL
)
return
pcnet32_ethtool_ioctl
(
dev
,
(
void
*
)
rq
->
ifr_data
);
/* SIOC[GS]MIIxxx ioctls */
/* SIOC[GS]MIIxxx ioctls */
if
(
lp
->
mii
)
{
if
(
lp
->
mii
)
{
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
...
@@ -1711,24 +1958,40 @@ static void pcnet32_watchdog(struct net_device *dev)
...
@@ -1711,24 +1958,40 @@ static void pcnet32_watchdog(struct net_device *dev)
mod_timer
(
&
(
lp
->
watchdog_timer
),
PCNET32_WATCHDOG_TIMEOUT
);
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
=
{
static
struct
pci_driver
pcnet32_driver
=
{
.
name
=
DRV_NAME
,
.
name
=
DRV_NAME
,
.
probe
=
pcnet32_probe_pci
,
.
probe
=
pcnet32_probe_pci
,
.
remove
=
__devexit_p
(
pcnet32_remove_one
),
.
id_table
=
pcnet32_pci_tbl
,
.
id_table
=
pcnet32_pci_tbl
,
};
};
MODULE_PARM
(
debug
,
"i"
);
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
(
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
(
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
(
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
(
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
(
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
(
full_duplex
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM_DESC
(
full_duplex
,
DRV_NAME
" full duplex setting(s) (1)"
);
MODULE_PARM_DESC
(
full_duplex
,
DRV_NAME
" full duplex setting(s) (1)"
);
...
@@ -1745,8 +2008,8 @@ static int __init pcnet32_init_module(void)
...
@@ -1745,8 +2008,8 @@ static int __init pcnet32_init_module(void)
{
{
printk
(
KERN_INFO
"%s"
,
version
);
printk
(
KERN_INFO
"%s"
,
version
);
if
(
debug
>
0
)
if
(
debug
>
=
0
&&
debug
<
(
sizeof
(
int
)
-
1
)
)
pcnet32_debug
=
debug
;
pcnet32_debug
=
1
<<
debug
;
if
((
tx_start_pt
>=
0
)
&&
(
tx_start_pt
<=
3
))
if
((
tx_start_pt
>=
0
)
&&
(
tx_start_pt
<=
3
))
tx_start
=
tx_start_pt
;
tx_start
=
tx_start_pt
;
...
@@ -1761,7 +2024,7 @@ static int __init pcnet32_init_module(void)
...
@@ -1761,7 +2024,7 @@ static int __init pcnet32_init_module(void)
if
(
cards_found
)
if
(
cards_found
)
printk
(
KERN_INFO
PFX
"%d cards_found.
\n
"
,
cards_found
);
printk
(
KERN_INFO
PFX
"%d cards_found.
\n
"
,
cards_found
);
return
(
pcnet32_have_pci
+
cards_found
)
?
0
:
-
ENODEV
;
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