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
523f0519
Commit
523f0519
authored
Apr 13, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/r8169
into redhat.com:/spare/repo/net-drivers-2.6
parents
62c6cb13
86af9cf0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
794 additions
and
218 deletions
+794
-218
MAINTAINERS
MAINTAINERS
+6
-0
drivers/net/r8169.c
drivers/net/r8169.c
+788
-218
No files found.
MAINTAINERS
View file @
523f0519
...
...
@@ -113,6 +113,12 @@ M: jgarzik@pobox.com
W: http://sourceforge.net/projects/gkernel/
S: Maintained
8169 10/100/1000 GIGABIT ETHERNET DRIVER
P: Francois Romieu
M: romieu@fr.zoreil.com
L: netdev@oss.sgi.com
S: Maintained
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
P: Russell King
M: rmk+serial@arm.linux.org.uk
...
...
drivers/net/r8169.c
View file @
523f0519
...
...
@@ -40,6 +40,7 @@ VERSION 1.2 <2002/11/30>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/init.h>
...
...
@@ -56,9 +57,11 @@ VERSION 1.2 <2002/11/30>
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#define dprintk(fmt, args...) do { printk(PFX fmt, ## args) } while (0)
#else
#define assert(expr) do {} while (0)
#endif
#define dprintk(fmt, args...) do {} while (0)
#endif
/* RTL8169_DEBUG */
/* media options */
#define MAX_UNITS 8
...
...
@@ -89,9 +92,12 @@ static int multicast_filter_limit = 32;
#define NUM_TX_DESC 64
/* Number of Tx descriptor registers */
#define NUM_RX_DESC 64
/* Number of Rx descriptor registers */
#define RX_BUF_SIZE 1536
/* Rx Buffer size */
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define RTL_MIN_IO_SIZE 0x80
#define TX_TIMEOUT (6*HZ)
#define RTL8169_TX_TIMEOUT (6*HZ)
#define RTL8169_PHY_TIMEOUT (HZ)
/* write/read MMIO register */
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
...
...
@@ -101,11 +107,35 @@ static int multicast_filter_limit = 32;
#define RTL_R16(reg) readw (ioaddr + (reg))
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
static
struct
{
enum
mac_version
{
RTL_GIGA_MAC_VER_B
=
0x00
,
/* RTL_GIGA_MAC_VER_C = 0x03, */
RTL_GIGA_MAC_VER_D
=
0x01
,
RTL_GIGA_MAC_VER_E
=
0x02
};
enum
phy_version
{
RTL_GIGA_PHY_VER_C
=
0x03
,
/* PHY Reg 0x03 bit0-3 == 0x0000 */
RTL_GIGA_PHY_VER_D
=
0x04
,
/* PHY Reg 0x03 bit0-3 == 0x0000 */
RTL_GIGA_PHY_VER_E
=
0x05
,
/* PHY Reg 0x03 bit0-3 == 0x0000 */
RTL_GIGA_PHY_VER_F
=
0x06
,
/* PHY Reg 0x03 bit0-3 == 0x0001 */
RTL_GIGA_PHY_VER_G
=
0x07
,
/* PHY Reg 0x03 bit0-3 == 0x0002 */
};
#define _R(NAME,MAC,MASK) \
{ .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
const
static
struct
{
const
char
*
name
;
}
board_info
[]
__devinitdata
=
{
{
"RealTek RTL8169 Gigabit Ethernet"
},};
u8
mac_version
;
u32
RxConfigMask
;
/* Clears the bits supported by this chip */
}
rtl_chip_info
[]
=
{
_R
(
"RTL8169"
,
RTL_GIGA_MAC_VER_B
,
0xff7e1880
),
_R
(
"RTL8169s/8110s"
,
RTL_GIGA_MAC_VER_D
,
0xff7e1880
),
_R
(
"RTL8169s/8110s"
,
RTL_GIGA_MAC_VER_E
,
0xff7e1880
)
};
#undef _R
static
struct
pci_device_id
rtl8169_pci_tbl
[]
=
{
{
0x10ec
,
0x8169
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
...
...
@@ -114,11 +144,15 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
MODULE_DEVICE_TABLE
(
pci
,
rtl8169_pci_tbl
);
static
int
rx_copybreak
=
200
;
enum
RTL8169_registers
{
MAC0
=
0
,
/* Ethernet hardware address. */
MAR0
=
8
,
/* Multicast filter. */
TxDescStartAddr
=
0x20
,
TxHDescStartAddr
=
0x28
,
TxDescStartAddrLow
=
0x20
,
TxDescStartAddrHigh
=
0x24
,
TxHDescStartAddrLow
=
0x28
,
TxHDescStartAddrHigh
=
0x2c
,
FLASH
=
0x30
,
ERSR
=
0x36
,
ChipCmd
=
0x37
,
...
...
@@ -143,7 +177,8 @@ enum RTL8169_registers {
PHYstatus
=
0x6C
,
RxMaxSize
=
0xDA
,
CPlusCmd
=
0xE0
,
RxDescStartAddr
=
0xE4
,
RxDescAddrLow
=
0xE4
,
RxDescAddrHigh
=
0xE8
,
EarlyTxThres
=
0xEC
,
FuncEvent
=
0xF0
,
FuncEventMask
=
0xF4
,
...
...
@@ -195,7 +230,13 @@ enum RTL8169_register_content {
/*TxConfigBits */
TxInterFrameGapShift
=
24
,
TxDMAShift
=
8
,
/* DMA burst value (0-7) is shift this many bits */
TxDMAShift
=
8
,
/* DMA burst value (0-7) is shift this many bits */
/* CPlusCmd p.31 */
RxVlan
=
(
1
<<
6
),
RxChkSum
=
(
1
<<
5
),
PCIDAC
=
(
1
<<
4
),
PCIMulRW
=
(
1
<<
3
),
/*rtl8169_PHYstatus */
TBI_Enable
=
0x80
,
...
...
@@ -242,14 +283,6 @@ enum RTL8169_register_content {
TBILinkOK
=
0x02000000
,
};
const
static
struct
{
const
char
*
name
;
u8
version
;
/* depend on RTL8169 docs */
u32
RxConfigMask
;
/* should clear the bits supported by this chip */
}
rtl_chip_info
[]
=
{
{
"RTL-8169"
,
0x00
,
0xff7e1880
,},};
enum
_DescStatusBit
{
OWNbit
=
0x80000000
,
EORbit
=
0x40000000
,
...
...
@@ -257,18 +290,18 @@ enum _DescStatusBit {
LSbit
=
0x10000000
,
};
#define RsvdMask 0x3fffc000
struct
TxDesc
{
u32
status
;
u32
vlan_tag
;
u32
buf_addr
;
u32
buf_Haddr
;
u64
addr
;
};
struct
RxDesc
{
u32
status
;
u32
vlan_tag
;
u32
buf_addr
;
u32
buf_Haddr
;
u64
addr
;
};
struct
rtl8169_private
{
...
...
@@ -277,28 +310,34 @@ struct rtl8169_private {
struct
net_device_stats
stats
;
/* statistics of net device */
spinlock_t
lock
;
/* spin lock flag */
int
chipset
;
unsigned
long
cur_rx
;
/* Index into the Rx descriptor buffer of next Rx pkt. */
unsigned
long
cur_tx
;
/* Index into the Tx descriptor buffer of next Rx pkt. */
unsigned
long
dirty_tx
;
unsigned
char
*
TxDescArrays
;
/* Index of Tx Descriptor buffer */
unsigned
char
*
RxDescArrays
;
/* Index of Rx Descriptor buffer */
int
mac_version
;
int
phy_version
;
u32
cur_rx
;
/* Index into the Rx descriptor buffer of next Rx pkt. */
u32
cur_tx
;
/* Index into the Tx descriptor buffer of next Rx pkt. */
u32
dirty_rx
;
u32
dirty_tx
;
struct
TxDesc
*
TxDescArray
;
/* Index of 256-alignment Tx Descriptor buffer */
struct
RxDesc
*
RxDescArray
;
/* Index of 256-alignment Rx Descriptor buffer */
unsigned
char
*
RxBufferRings
;
/* Index of Rx Buffer */
unsigned
char
*
RxBufferRing
[
NUM_RX_DESC
];
/* Index of Rx Buffer array */
dma_addr_t
TxPhyAddr
;
dma_addr_t
RxPhyAddr
;
struct
sk_buff
*
Rx_skbuff
[
NUM_RX_DESC
];
/* Rx data buffers */
struct
sk_buff
*
Tx_skbuff
[
NUM_TX_DESC
];
/* Index of Transmit data buffer */
struct
timer_list
timer
;
unsigned
long
phy_link_down_cnt
;
u16
cp_cmd
;
};
MODULE_AUTHOR
(
"Realtek"
);
MODULE_DESCRIPTION
(
"RealTek RTL-8169 Gigabit Ethernet driver"
);
MODULE_PARM
(
media
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM
(
rx_copybreak
,
"i"
);
MODULE_LICENSE
(
"GPL"
);
static
int
rtl8169_open
(
struct
net_device
*
dev
);
static
int
rtl8169_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
irqreturn_t
rtl8169_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
void
rtl8169_init_ring
(
struct
net_device
*
dev
);
static
int
rtl8169_init_ring
(
struct
net_device
*
dev
);
static
void
rtl8169_hw_start
(
struct
net_device
*
dev
);
static
int
rtl8169_close
(
struct
net_device
*
dev
);
static
void
rtl8169_set_rx_mode
(
struct
net_device
*
dev
);
...
...
@@ -306,13 +345,16 @@ static void rtl8169_tx_timeout(struct net_device *dev);
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
netdev
);
static
const
u16
rtl8169_intr_mask
=
SYSErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
static
const
unsigned
int
rtl8169_rx_config
=
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
void
mdio_write
(
void
*
ioaddr
,
int
RegAddr
,
int
value
)
#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
static
void
mdio_write
(
void
*
ioaddr
,
int
RegAddr
,
int
value
)
{
int
i
;
...
...
@@ -329,8 +371,7 @@ mdio_write(void *ioaddr, int RegAddr, int value)
}
}
int
mdio_read
(
void
*
ioaddr
,
int
RegAddr
)
static
int
mdio_read
(
void
*
ioaddr
,
int
RegAddr
)
{
int
i
,
value
=
-
1
;
...
...
@@ -342,13 +383,272 @@ mdio_read(void *ioaddr, int RegAddr)
if
(
RTL_R32
(
PHYAR
)
&
0x80000000
)
{
value
=
(
int
)
(
RTL_R32
(
PHYAR
)
&
0xFFFF
);
break
;
}
else
{
udelay
(
100
);
}
udelay
(
100
);
}
return
value
;
}
static
void
rtl8169_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
strcpy
(
info
->
driver
,
RTL8169_DRIVER_NAME
);
strcpy
(
info
->
version
,
RTL8169_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
tp
->
pci_dev
));
}
static
struct
ethtool_ops
rtl8169_ethtool_ops
=
{
.
get_drvinfo
=
rtl8169_get_drvinfo
,
};
static
void
rtl8169_write_gmii_reg_bit
(
void
*
ioaddr
,
int
reg
,
int
bitnum
,
int
bitval
)
{
int
val
;
val
=
mdio_read
(
ioaddr
,
reg
);
val
=
(
bitval
==
1
)
?
val
|
(
bitval
<<
bitnum
)
:
val
&
~
(
0x0001
<<
bitnum
);
mdio_write
(
ioaddr
,
reg
,
val
&
0xffff
);
}
static
void
rtl8169_get_mac_version
(
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
const
struct
{
u32
mask
;
int
mac_version
;
}
mac_info
[]
=
{
{
0x1
<<
26
,
RTL_GIGA_MAC_VER_E
},
{
0x1
<<
23
,
RTL_GIGA_MAC_VER_D
},
{
0x00000000
,
RTL_GIGA_MAC_VER_B
}
/* Catch-all */
},
*
p
=
mac_info
;
u32
reg
;
reg
=
RTL_R32
(
TxConfig
)
&
0x7c800000
;
while
((
reg
&
p
->
mask
)
!=
p
->
mask
)
p
++
;
tp
->
mac_version
=
p
->
mac_version
;
}
static
void
rtl8169_print_mac_version
(
struct
rtl8169_private
*
tp
)
{
struct
{
int
version
;
char
*
msg
;
}
mac_print
[]
=
{
{
RTL_GIGA_MAC_VER_E
,
"RTL_GIGA_MAC_VER_E"
},
{
RTL_GIGA_MAC_VER_D
,
"RTL_GIGA_MAC_VER_D"
},
{
RTL_GIGA_MAC_VER_B
,
"RTL_GIGA_MAC_VER_B"
},
{
0
,
NULL
}
},
*
p
;
for
(
p
=
mac_print
;
p
->
msg
;
p
++
)
{
if
(
tp
->
mac_version
==
p
->
version
)
{
dprintk
(
"mac_version == %s (%04d)
\n
"
,
p
->
msg
,
p
->
version
);
return
;
}
}
dprintk
(
"mac_version == Unknown
\n
"
);
}
static
void
rtl8169_get_phy_version
(
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
const
struct
{
u16
mask
;
u16
set
;
int
phy_version
;
}
phy_info
[]
=
{
{
0x000f
,
0x0002
,
RTL_GIGA_PHY_VER_G
},
{
0x000f
,
0x0001
,
RTL_GIGA_PHY_VER_F
},
{
0x000f
,
0x0000
,
RTL_GIGA_PHY_VER_E
},
{
0x0000
,
0x0000
,
RTL_GIGA_PHY_VER_D
}
/* Catch-all */
},
*
p
=
phy_info
;
u16
reg
;
reg
=
mdio_read
(
ioaddr
,
3
)
&
0xffff
;
while
((
reg
&
p
->
mask
)
!=
p
->
set
)
p
++
;
tp
->
phy_version
=
p
->
phy_version
;
}
static
void
rtl8169_print_phy_version
(
struct
rtl8169_private
*
tp
)
{
struct
{
int
version
;
char
*
msg
;
u32
reg
;
}
phy_print
[]
=
{
{
RTL_GIGA_PHY_VER_G
,
"RTL_GIGA_PHY_VER_G"
,
0x0002
},
{
RTL_GIGA_PHY_VER_F
,
"RTL_GIGA_PHY_VER_F"
,
0x0001
},
{
RTL_GIGA_PHY_VER_E
,
"RTL_GIGA_PHY_VER_E"
,
0x0000
},
{
RTL_GIGA_PHY_VER_D
,
"RTL_GIGA_PHY_VER_D"
,
0x0000
},
{
0
,
NULL
,
0x0000
}
},
*
p
;
for
(
p
=
phy_print
;
p
->
msg
;
p
++
)
{
if
(
tp
->
phy_version
==
p
->
version
)
{
dprintk
(
"phy_version == %s (%04x)
\n
"
,
p
->
msg
,
p
->
reg
);
return
;
}
}
dprintk
(
"phy_version == Unknown
\n
"
);
}
static
void
rtl8169_hw_phy_config
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
struct
{
u16
regs
[
5
];
/* Beware of bit-sign propagation */
}
phy_magic
[
5
]
=
{
{
{
0x0000
,
//w 4 15 12 0
0x00a1
,
//w 3 15 0 00a1
0x0008
,
//w 2 15 0 0008
0x1020
,
//w 1 15 0 1020
0x1000
}
},{
//w 0 15 0 1000
{
0x7000
,
//w 4 15 12 7
0xff41
,
//w 3 15 0 ff41
0xde60
,
//w 2 15 0 de60
0x0140
,
//w 1 15 0 0140
0x0077
}
},{
//w 0 15 0 0077
{
0xa000
,
//w 4 15 12 a
0xdf01
,
//w 3 15 0 df01
0xdf20
,
//w 2 15 0 df20
0xff95
,
//w 1 15 0 ff95
0xfa00
}
},{
//w 0 15 0 fa00
{
0xb000
,
//w 4 15 12 b
0xff41
,
//w 3 15 0 ff41
0xde20
,
//w 2 15 0 de20
0x0140
,
//w 1 15 0 0140
0x00bb
}
},{
//w 0 15 0 00bb
{
0xf000
,
//w 4 15 12 f
0xdf01
,
//w 3 15 0 df01
0xdf20
,
//w 2 15 0 df20
0xff95
,
//w 1 15 0 ff95
0xbf00
}
//w 0 15 0 bf00
}
},
*
p
=
phy_magic
;
int
i
;
rtl8169_print_mac_version
(
tp
);
rtl8169_print_phy_version
(
tp
);
if
(
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
return
;
if
(
tp
->
phy_version
>=
RTL_GIGA_PHY_VER_F
)
return
;
dprintk
(
"MAC version != 0 && PHY version == 0 or 1
\n
"
);
dprintk
(
"Do final_reg2.cfg
\n
"
);
/* Shazam ! */
// phy config for RTL8169s mac_version C chip
mdio_write
(
ioaddr
,
31
,
0x0001
);
//w 31 2 0 1
mdio_write
(
ioaddr
,
21
,
0x1000
);
//w 21 15 0 1000
mdio_write
(
ioaddr
,
24
,
0x65c7
);
//w 24 15 0 65c7
rtl8169_write_gmii_reg_bit
(
ioaddr
,
4
,
11
,
0
);
//w 4 11 11 0
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
phy_magic
);
i
++
,
p
++
)
{
int
val
,
pos
=
4
;
val
=
(
mdio_read
(
ioaddr
,
pos
)
&
0x0fff
)
|
(
p
->
regs
[
0
]
&
0xffff
);
mdio_write
(
ioaddr
,
pos
,
val
);
while
(
--
pos
>=
0
)
mdio_write
(
ioaddr
,
pos
,
p
->
regs
[
4
-
pos
]
&
0xffff
);
rtl8169_write_gmii_reg_bit
(
ioaddr
,
4
,
11
,
1
);
//w 4 11 11 1
rtl8169_write_gmii_reg_bit
(
ioaddr
,
4
,
11
,
0
);
//w 4 11 11 0
}
mdio_write
(
ioaddr
,
31
,
0x0000
);
//w 31 2 0 0
}
static
void
rtl8169_hw_phy_reset
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
i
,
val
;
printk
(
KERN_WARNING
PFX
"%s: Reset RTL8169s PHY
\n
"
,
dev
->
name
);
val
=
(
mdio_read
(
ioaddr
,
0
)
|
0x8000
)
&
0xffff
;
mdio_write
(
ioaddr
,
0
,
val
);
for
(
i
=
50
;
i
>=
0
;
i
--
)
{
if
(
!
(
mdio_read
(
ioaddr
,
0
)
&
0x8000
))
break
;
udelay
(
100
);
/* Gross */
}
if
(
i
<
0
)
{
printk
(
KERN_WARNING
PFX
"%s: no PHY Reset ack. Giving up.
\n
"
,
dev
->
name
);
}
}
static
void
rtl8169_phy_timer
(
unsigned
long
__opaque
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
__opaque
;
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
void
*
ioaddr
=
tp
->
mmio_addr
;
assert
(
tp
->
mac_version
>
RTL_GIGA_MAC_VER_B
);
assert
(
tp
->
phy_version
<
RTL_GIGA_PHY_VER_G
);
if
(
RTL_R8
(
PHYstatus
)
&
LinkStatus
)
tp
->
phy_link_down_cnt
=
0
;
else
{
tp
->
phy_link_down_cnt
++
;
if
(
tp
->
phy_link_down_cnt
>=
12
)
{
int
reg
;
// If link on 1000, perform phy reset.
reg
=
mdio_read
(
ioaddr
,
PHY_1000_CTRL_REG
);
if
(
reg
&
PHY_Cap_1000_Full
)
rtl8169_hw_phy_reset
(
dev
);
tp
->
phy_link_down_cnt
=
0
;
}
}
mod_timer
(
timer
,
jiffies
+
RTL8169_PHY_TIMEOUT
);
}
static
inline
void
rtl8169_delete_timer
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
(
tp
->
phy_version
>=
RTL_GIGA_PHY_VER_G
))
return
;
del_timer_sync
(
timer
);
tp
->
phy_link_down_cnt
=
0
;
}
static
inline
void
rtl8169_request_timer
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
(
tp
->
phy_version
>=
RTL_GIGA_PHY_VER_G
))
return
;
tp
->
phy_link_down_cnt
=
0
;
init_timer
(
timer
);
timer
->
expires
=
jiffies
+
RTL8169_PHY_TIMEOUT
;
timer
->
data
=
(
unsigned
long
)(
dev
);
timer
->
function
=
rtl8169_phy_timer
;
add_timer
(
timer
);
}
static
int
__devinit
rtl8169_init_board
(
struct
pci_dev
*
pdev
,
struct
net_device
**
dev_out
,
void
**
ioaddr_out
)
...
...
@@ -356,9 +656,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
void
*
ioaddr
=
NULL
;
struct
net_device
*
dev
;
struct
rtl8169_private
*
tp
;
int
rc
,
i
;
unsigned
long
mmio_start
,
mmio_end
,
mmio_flags
,
mmio_len
;
u32
tmp
;
int
rc
,
i
,
acpi_idle_state
=
0
,
pm_cap
;
assert
(
pdev
!=
NULL
);
assert
(
ioaddr_out
!=
NULL
);
...
...
@@ -379,8 +679,22 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
// enable device (incl. PCI PM wakeup and hotplug setup)
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"%s: unable to enable device
\n
"
,
pdev
->
slot_name
);
goto
err_out
;
}
/* save power state before pci_enable_device overwrites it */
pm_cap
=
pci_find_capability
(
pdev
,
PCI_CAP_ID_PM
);
if
(
pm_cap
)
{
u16
pwr_command
;
pci_read_config_word
(
pdev
,
pm_cap
+
PCI_PM_CTRL
,
&
pwr_command
);
acpi_idle_state
=
pwr_command
&
PCI_PM_CTRL_STATE_MASK
;
}
else
{
printk
(
KERN_ERR
PFX
"Cannot find PowerManagement capability, aborting.
\n
"
);
goto
err_out_free_res
;
}
mmio_start
=
pci_resource_start
(
pdev
,
1
);
mmio_end
=
pci_resource_end
(
pdev
,
1
);
...
...
@@ -402,8 +716,24 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
}
rc
=
pci_request_regions
(
pdev
,
dev
->
name
);
if
(
rc
)
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"%s: Could not request regions.
\n
"
,
pdev
->
slot_name
);
goto
err_out_disable
;
}
tp
->
cp_cmd
=
PCIMulRW
|
RxChkSum
;
if
((
sizeof
(
dma_addr_t
)
>
32
)
&&
!
pci_set_dma_mask
(
pdev
,
DMA_64BIT_MASK
))
tp
->
cp_cmd
|=
PCIDAC
;
else
{
rc
=
pci_set_dma_mask
(
pdev
,
DMA_32BIT_MASK
);
if
(
rc
<
0
)
{
printk
(
KERN_ERR
PFX
"DMA configuration failed.
\n
"
);
goto
err_out_free_res
;
}
}
// enable PCI bus-mastering
pci_set_master
(
pdev
);
...
...
@@ -420,30 +750,32 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
RTL_W8
(
ChipCmd
,
CmdReset
);
// Check that the chip has finished the reset.
for
(
i
=
1000
;
i
>
0
;
i
--
)
for
(
i
=
1000
;
i
>
0
;
i
--
)
{
if
((
RTL_R8
(
ChipCmd
)
&
CmdReset
)
==
0
)
break
;
else
udelay
(
10
);
udelay
(
10
);
}
// identify chip attached to board
tmp
=
RTL_R32
(
TxConfig
);
tmp
=
((
tmp
&
0x7c000000
)
+
((
tmp
&
0x00800000
)
<<
2
))
>>
24
;
// Identify chip attached to board
rtl8169_get_mac_version
(
tp
,
ioaddr
);
rtl8169_get_phy_version
(
tp
,
ioaddr
);
rtl8169_print_mac_version
(
tp
);
rtl8169_print_phy_version
(
tp
);
for
(
i
=
ARRAY_SIZE
(
rtl_chip_info
)
-
1
;
i
>=
0
;
i
--
)
{
if
(
tp
->
mac_version
==
rtl_chip_info
[
i
].
mac_version
)
break
;
}
if
(
i
<
0
)
{
/* Unknown chip: assume array element #0, original RTL-8169 */
printk
(
KERN_DEBUG
PFX
"PCI device %s: unknown chip version, assuming %s
\n
"
,
pci_name
(
pdev
),
rtl_chip_info
[
0
].
name
);
i
++
;
}
tp
->
chipset
=
i
;
for
(
i
=
ARRAY_SIZE
(
rtl_chip_info
)
-
1
;
i
>=
0
;
i
--
)
if
(
tmp
==
rtl_chip_info
[
i
].
version
)
{
tp
->
chipset
=
i
;
goto
match
;
}
//if unknown chip, assume array element #0, original RTL-8169 in this case
printk
(
KERN_DEBUG
PFX
"PCI device %s: unknown chip version, assuming RTL-8169
\n
"
,
pci_name
(
pdev
));
printk
(
KERN_DEBUG
PFX
"PCI device %s: TxConfig = 0x%lx
\n
"
,
pci_name
(
pdev
),
(
unsigned
long
)
RTL_R32
(
TxConfig
));
tp
->
chipset
=
0
;
match:
*
ioaddr_out
=
ioaddr
;
*
dev_out
=
dev
;
return
0
;
...
...
@@ -496,10 +828,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev
->
open
=
rtl8169_open
;
dev
->
hard_start_xmit
=
rtl8169_start_xmit
;
dev
->
get_stats
=
rtl8169_get_stats
;
dev
->
ethtool_ops
=
&
rtl8169_ethtool_ops
;
dev
->
stop
=
rtl8169_close
;
dev
->
tx_timeout
=
rtl8169_tx_timeout
;
dev
->
set_multicast_list
=
rtl8169_set_rx_mode
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
dev
->
watchdog_timeo
=
RTL8169_
TX_TIMEOUT
;
dev
->
irq
=
pdev
->
irq
;
dev
->
base_addr
=
(
unsigned
long
)
ioaddr
;
// dev->do_ioctl = mii_ioctl;
...
...
@@ -528,12 +861,29 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d
\n
"
,
dev
->
name
,
board
_info
[
ent
->
driver_data
].
name
,
rtl_chip
_info
[
ent
->
driver_data
].
name
,
dev
->
base_addr
,
dev
->
dev_addr
[
0
],
dev
->
dev_addr
[
1
],
dev
->
dev_addr
[
2
],
dev
->
dev_addr
[
3
],
dev
->
dev_addr
[
4
],
dev
->
dev_addr
[
5
],
dev
->
irq
);
rtl8169_hw_phy_config
(
dev
);
dprintk
(
"Set MAC Reg C+CR Offset 0x82h = 0x01h
\n
"
);
RTL_W8
(
0x82
,
0x01
);
if
(
tp
->
mac_version
<
RTL_GIGA_MAC_VER_E
)
{
dprintk
(
"Set PCI Latency=0x40
\n
"
);
pci_write_config_byte
(
pdev
,
PCI_LATENCY_TIMER
,
0x40
);
}
if
(
tp
->
mac_version
==
RTL_GIGA_MAC_VER_D
)
{
dprintk
(
"Set MAC Reg C+CR Offset 0x82h = 0x01h
\n
"
);
RTL_W8
(
0x82
,
0x01
);
dprintk
(
"Set PHY Reg 0x0bh = 0x00h
\n
"
);
mdio_write
(
ioaddr
,
0x0b
,
0x0000
);
//w 0x0b 15 0 0
}
// if TBI is not endbled
if
(
!
(
RTL_R8
(
PHYstatus
)
&
TBI_Enable
))
{
int
val
=
mdio_read
(
ioaddr
,
PHY_AUTO_NEGO_REG
);
...
...
@@ -546,23 +896,23 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
Cap10_100
=
0
,
Cap1000
=
0
;
switch
(
option
)
{
case
_10_Half
:
Cap10_100
=
PHY_Cap_10_Half
;
Cap10_100
=
PHY_Cap_10_Half
_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_10_Full
:
Cap10_100
=
PHY_Cap_10_Full
;
Cap10_100
=
PHY_Cap_10_Full
_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Half
:
Cap10_100
=
PHY_Cap_100_Half
;
Cap10_100
=
PHY_Cap_100_Half
_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Full
:
Cap10_100
=
PHY_Cap_100_Full
;
Cap10_100
=
PHY_Cap_100_Full
_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_1000_Full
:
Cap10_100
=
PHY_Cap_
Null
;
Cap10_100
=
PHY_Cap_
100_Full_Or_Less
;
Cap1000
=
PHY_Cap_1000_Full
;
break
;
default:
...
...
@@ -576,9 +926,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
mdio_write
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
PHY_Cap_10_Half
|
PHY_Cap_10_Full
|
PHY_Cap_100_Half
|
PHY_Cap_100_Full
|
(
val
&
0x1F
));
PHY_Cap_100_Full_Or_Less
|
(
val
&
0x1f
));
// enable 1000 Full Mode
mdio_write
(
ioaddr
,
PHY_1000_CTRL_REG
,
...
...
@@ -647,56 +995,96 @@ rtl8169_remove_one(struct pci_dev *pdev)
pci_set_drvdata
(
pdev
,
NULL
);
}
#ifdef CONFIG_PM
static
int
rtl8169_suspend
(
struct
pci_dev
*
pdev
,
u32
state
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
if
(
!
netif_running
(
dev
))
return
0
;
netif_device_detach
(
dev
);
netif_stop_queue
(
dev
);
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
/* Disable interrupts, stop Rx and Tx */
RTL_W16
(
IntrMask
,
0
);
RTL_W8
(
ChipCmd
,
0
);
/* Update the error counts. */
tp
->
stats
.
rx_missed_errors
+=
RTL_R32
(
RxMissed
);
RTL_W32
(
RxMissed
,
0
);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
return
0
;
}
static
int
rtl8169_resume
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
if
(
!
netif_running
(
dev
))
return
0
;
netif_device_attach
(
dev
);
rtl8169_hw_start
(
dev
);
return
0
;
}
#endif
/* CONFIG_PM */
static
int
rtl8169_open
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
int
retval
;
u8
diff
;
u32
TxPhyAddr
,
RxPhyAddr
;
retval
=
request_irq
(
dev
->
irq
,
rtl8169_interrupt
,
SA_SHIRQ
,
dev
->
name
,
dev
);
if
(
retval
)
{
return
retval
;
}
if
(
retval
<
0
)
goto
out
;
tp
->
TxDescArrays
=
kmalloc
(
NUM_TX_DESC
*
sizeof
(
struct
TxDesc
)
+
256
,
GFP_KERNEL
);
// Tx Desscriptor needs 256 bytes alignment;
TxPhyAddr
=
virt_to_bus
(
tp
->
TxDescArrays
);
diff
=
256
-
(
TxPhyAddr
-
((
TxPhyAddr
>>
8
)
<<
8
));
TxPhyAddr
+=
diff
;
tp
->
TxDescArray
=
(
struct
TxDesc
*
)
(
tp
->
TxDescArrays
+
diff
);
tp
->
RxDescArrays
=
kmalloc
(
NUM_RX_DESC
*
sizeof
(
struct
RxDesc
)
+
256
,
GFP_KERNEL
);
// Rx Desscriptor needs 256 bytes alignment;
RxPhyAddr
=
virt_to_bus
(
tp
->
RxDescArrays
);
diff
=
256
-
(
RxPhyAddr
-
((
RxPhyAddr
>>
8
)
<<
8
));
RxPhyAddr
+=
diff
;
tp
->
RxDescArray
=
(
struct
RxDesc
*
)
(
tp
->
RxDescArrays
+
diff
);
if
(
tp
->
TxDescArrays
==
NULL
||
tp
->
RxDescArrays
==
NULL
)
{
printk
(
KERN_INFO
"Allocate RxDescArray or TxDescArray failed
\n
"
);
free_irq
(
dev
->
irq
,
dev
);
if
(
tp
->
TxDescArrays
)
kfree
(
tp
->
TxDescArrays
);
if
(
tp
->
RxDescArrays
)
kfree
(
tp
->
RxDescArrays
);
return
-
ENOMEM
;
}
tp
->
RxBufferRings
=
kmalloc
(
RX_BUF_SIZE
*
NUM_RX_DESC
,
GFP_KERNEL
);
if
(
tp
->
RxBufferRings
==
NULL
)
{
printk
(
KERN_INFO
"Allocate RxBufferRing failed
\n
"
);
}
retval
=
-
ENOMEM
;
rtl8169_init_ring
(
dev
);
rtl8169_hw_start
(
dev
);
/*
* Rx and Tx desscriptors needs 256 bytes alignment.
* pci_alloc_consistent provides more.
*/
tp
->
TxDescArray
=
pci_alloc_consistent
(
pdev
,
R8169_TX_RING_BYTES
,
&
tp
->
TxPhyAddr
);
if
(
!
tp
->
TxDescArray
)
goto
err_free_irq
;
return
0
;
tp
->
RxDescArray
=
pci_alloc_consistent
(
pdev
,
R8169_RX_RING_BYTES
,
&
tp
->
RxPhyAddr
);
if
(
!
tp
->
RxDescArray
)
goto
err_free_tx
;
retval
=
rtl8169_init_ring
(
dev
);
if
(
retval
<
0
)
goto
err_free_rx
;
rtl8169_hw_start
(
dev
);
rtl8169_request_timer
(
dev
);
out:
return
retval
;
err_free_rx:
pci_free_consistent
(
pdev
,
R8169_RX_RING_BYTES
,
tp
->
RxDescArray
,
tp
->
RxPhyAddr
);
err_free_tx:
pci_free_consistent
(
pdev
,
R8169_TX_RING_BYTES
,
tp
->
TxDescArray
,
tp
->
TxPhyAddr
);
err_free_irq:
free_irq
(
dev
->
irq
,
dev
);
goto
out
;
}
static
void
...
...
@@ -733,11 +1121,21 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W32
(
TxConfig
,
(
TX_DMA_BURST
<<
TxDMAShift
)
|
(
InterFrameGap
<<
TxInterFrameGapShift
));
tp
->
cp_cmd
|=
RTL_R16
(
CPlusCmd
);
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
if
(
tp
->
mac_version
==
RTL_GIGA_MAC_VER_D
)
{
dprintk
(
KERN_INFO
PFX
"Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1
\n
"
);
tp
->
cp_cmd
|=
(
1
<<
14
)
|
PCIMulRW
;
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
}
tp
->
cur_rx
=
0
;
RTL_W32
(
TxDescStartAddr
,
virt_to_bus
(
tp
->
TxDescArray
));
RTL_W32
(
RxDescStartAddr
,
virt_to_bus
(
tp
->
RxDescArray
));
RTL_W32
(
TxDescStartAddrLow
,
((
u64
)
tp
->
TxPhyAddr
&
DMA_32BIT_MASK
));
RTL_W32
(
TxDescStartAddrHigh
,
((
u64
)
tp
->
TxPhyAddr
>>
32
));
RTL_W32
(
RxDescAddrLow
,
((
u64
)
tp
->
RxPhyAddr
&
DMA_32BIT_MASK
));
RTL_W32
(
RxDescAddrHigh
,
((
u64
)
tp
->
RxPhyAddr
>>
32
));
RTL_W8
(
Cfg9346
,
Cfg9346_Lock
);
udelay
(
10
);
...
...
@@ -755,31 +1153,131 @@ rtl8169_hw_start(struct net_device *dev)
}
static
void
rtl8169_init_ring
(
struct
net_device
*
dev
)
static
inline
void
rtl8169_make_unusable_by_asic
(
struct
RxDesc
*
desc
)
{
desc
->
addr
=
0x0badbadbadbadbad
;
desc
->
status
&=
~
cpu_to_le32
(
OWNbit
|
RsvdMask
);
}
static
void
rtl8169_free_rx_skb
(
struct
pci_dev
*
pdev
,
struct
sk_buff
**
sk_buff
,
struct
RxDesc
*
desc
)
{
pci_unmap_single
(
pdev
,
le64_to_cpu
(
desc
->
addr
),
RX_BUF_SIZE
,
PCI_DMA_FROMDEVICE
);
dev_kfree_skb
(
*
sk_buff
);
*
sk_buff
=
NULL
;
rtl8169_make_unusable_by_asic
(
desc
);
}
static
inline
void
rtl8169_return_to_asic
(
struct
RxDesc
*
desc
)
{
desc
->
status
|=
cpu_to_le32
(
OWNbit
+
RX_BUF_SIZE
);
}
static
inline
void
rtl8169_give_to_asic
(
struct
RxDesc
*
desc
,
dma_addr_t
mapping
)
{
desc
->
addr
=
cpu_to_le64
(
mapping
);
desc
->
status
|=
cpu_to_le32
(
OWNbit
+
RX_BUF_SIZE
);
}
static
int
rtl8169_alloc_rx_skb
(
struct
pci_dev
*
pdev
,
struct
net_device
*
dev
,
struct
sk_buff
**
sk_buff
,
struct
RxDesc
*
desc
)
{
struct
sk_buff
*
skb
;
dma_addr_t
mapping
;
int
ret
=
0
;
skb
=
dev_alloc_skb
(
RX_BUF_SIZE
);
if
(
!
skb
)
goto
err_out
;
skb
->
dev
=
dev
;
skb_reserve
(
skb
,
2
);
*
sk_buff
=
skb
;
mapping
=
pci_map_single
(
pdev
,
skb
->
tail
,
RX_BUF_SIZE
,
PCI_DMA_FROMDEVICE
);
rtl8169_give_to_asic
(
desc
,
mapping
);
out:
return
ret
;
err_out:
ret
=
-
ENOMEM
;
rtl8169_make_unusable_by_asic
(
desc
);
goto
out
;
}
static
void
rtl8169_rx_clear
(
struct
rtl8169_private
*
tp
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
int
i
;
tp
->
cur_rx
=
0
;
tp
->
cur_tx
=
0
;
tp
->
dirty_tx
=
0
;
for
(
i
=
0
;
i
<
NUM_RX_DESC
;
i
++
)
{
if
(
tp
->
Rx_skbuff
[
i
])
{
rtl8169_free_rx_skb
(
tp
->
pci_dev
,
tp
->
Rx_skbuff
+
i
,
tp
->
RxDescArray
+
i
);
}
}
}
static
u32
rtl8169_rx_fill
(
struct
rtl8169_private
*
tp
,
struct
net_device
*
dev
,
u32
start
,
u32
end
)
{
u32
cur
;
for
(
cur
=
start
;
end
-
cur
>
0
;
cur
++
)
{
int
ret
,
i
=
cur
%
NUM_RX_DESC
;
if
(
tp
->
Rx_skbuff
[
i
])
continue
;
ret
=
rtl8169_alloc_rx_skb
(
tp
->
pci_dev
,
dev
,
tp
->
Rx_skbuff
+
i
,
tp
->
RxDescArray
+
i
);
if
(
ret
<
0
)
break
;
}
return
cur
-
start
;
}
static
inline
void
rtl8169_mark_as_last_descriptor
(
struct
RxDesc
*
desc
)
{
desc
->
status
|=
cpu_to_le32
(
EORbit
);
}
static
int
rtl8169_init_ring
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
tp
->
cur_rx
=
tp
->
dirty_rx
=
0
;
tp
->
cur_tx
=
tp
->
dirty_tx
=
0
;
memset
(
tp
->
TxDescArray
,
0x0
,
NUM_TX_DESC
*
sizeof
(
struct
TxDesc
));
memset
(
tp
->
RxDescArray
,
0x0
,
NUM_RX_DESC
*
sizeof
(
struct
RxDesc
));
for
(
i
=
0
;
i
<
NUM_TX_DESC
;
i
++
)
{
tp
->
Tx_skbuff
[
i
]
=
NULL
;
}
for
(
i
=
0
;
i
<
NUM_RX_DESC
;
i
++
)
{
if
(
i
==
(
NUM_RX_DESC
-
1
))
tp
->
RxDescArray
[
i
].
status
=
(
OWNbit
|
EORbit
)
+
RX_BUF_SIZE
;
else
tp
->
RxDescArray
[
i
].
status
=
OWNbit
+
RX_BUF_SIZE
;
memset
(
tp
->
Tx_skbuff
,
0x0
,
NUM_TX_DESC
*
sizeof
(
struct
sk_buff
*
));
memset
(
tp
->
Rx_skbuff
,
0x0
,
NUM_RX_DESC
*
sizeof
(
struct
sk_buff
*
));
tp
->
RxBufferRing
[
i
]
=
&
(
tp
->
RxBufferRings
[
i
*
RX_BUF_SIZE
]);
tp
->
RxDescArray
[
i
].
buf_addr
=
virt_to_bus
(
tp
->
RxBufferRing
[
i
]);
}
if
(
rtl8169_rx_fill
(
tp
,
dev
,
0
,
NUM_RX_DESC
)
!=
NUM_RX_DESC
)
goto
err_out
;
rtl8169_mark_as_last_descriptor
(
tp
->
RxDescArray
+
NUM_RX_DESC
-
1
);
return
0
;
err_out:
rtl8169_rx_clear
(
tp
);
return
-
ENOMEM
;
}
static
void
rtl8169_unmap_tx_skb
(
struct
pci_dev
*
pdev
,
struct
sk_buff
**
sk_buff
,
struct
TxDesc
*
desc
)
{
u32
len
=
sk_buff
[
0
]
->
len
;
pci_unmap_single
(
pdev
,
le64_to_cpu
(
desc
->
addr
),
len
<
ETH_ZLEN
?
ETH_ZLEN
:
len
,
PCI_DMA_TODEVICE
);
desc
->
addr
=
0x00
;
*
sk_buff
=
NULL
;
}
static
void
...
...
@@ -789,9 +1287,12 @@ rtl8169_tx_clear(struct rtl8169_private *tp)
tp
->
cur_tx
=
0
;
for
(
i
=
0
;
i
<
NUM_TX_DESC
;
i
++
)
{
if
(
tp
->
Tx_skbuff
[
i
]
!=
NULL
)
{
dev_kfree_skb
(
tp
->
Tx_skbuff
[
i
]);
tp
->
Tx_skbuff
[
i
]
=
NULL
;
struct
sk_buff
*
skb
=
tp
->
Tx_skbuff
[
i
];
if
(
skb
)
{
rtl8169_unmap_tx_skb
(
tp
->
pci_dev
,
tp
->
Tx_skbuff
+
i
,
tp
->
TxDescArray
+
i
);
dev_kfree_skb
(
skb
);
tp
->
stats
.
tx_dropped
++
;
}
}
...
...
@@ -829,48 +1330,58 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
entry
=
tp
->
cur_tx
%
NUM_TX_DESC
;
u32
len
=
skb
->
len
;
if
(
skb
->
len
<
ETH_ZLEN
)
{
if
(
unlikely
(
skb
->
len
<
ETH_ZLEN
)
)
{
skb
=
skb_padto
(
skb
,
ETH_ZLEN
);
if
(
skb
==
NULL
)
return
0
;
if
(
!
skb
)
goto
err_update_stats
;
len
=
ETH_ZLEN
;
}
spin_lock_irq
(
&
tp
->
lock
);
if
((
tp
->
TxDescArray
[
entry
].
status
&
OWNbit
)
==
0
)
{
if
(
!
(
le32_to_cpu
(
tp
->
TxDescArray
[
entry
].
status
)
&
OWNbit
))
{
dma_addr_t
mapping
;
mapping
=
pci_map_single
(
tp
->
pci_dev
,
skb
->
data
,
len
,
PCI_DMA_TODEVICE
);
tp
->
Tx_skbuff
[
entry
]
=
skb
;
tp
->
TxDescArray
[
entry
].
buf_addr
=
virt_to_bus
(
skb
->
data
);
if
(
entry
!=
(
NUM_TX_DESC
-
1
))
tp
->
TxDescArray
[
entry
].
status
=
(
OWNbit
|
FSbit
|
LSbit
)
|
((
skb
->
len
>
ETH_ZLEN
)
?
skb
->
len
:
ETH_ZLEN
);
else
tp
->
TxDescArray
[
entry
].
status
=
(
OWNbit
|
EORbit
|
FSbit
|
LSbit
)
|
((
skb
->
len
>
ETH_ZLEN
)
?
skb
->
len
:
ETH_ZLEN
);
tp
->
TxDescArray
[
entry
].
addr
=
cpu_to_le64
(
mapping
);
tp
->
TxDescArray
[
entry
].
status
=
cpu_to_le32
(
OWNbit
|
FSbit
|
LSbit
|
len
|
(
EORbit
*
!
((
entry
+
1
)
%
NUM_TX_DESC
)));
RTL_W8
(
TxPoll
,
0x40
);
//set polling bit
dev
->
trans_start
=
jiffies
;
tp
->
cur_tx
++
;
}
}
else
goto
err_drop
;
spin_unlock_irq
(
&
tp
->
lock
);
if
((
tp
->
cur_tx
-
NUM_TX_DESC
)
==
tp
->
dirty_tx
)
{
netif_stop_queue
(
dev
);
}
out:
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
err_drop:
dev_kfree_skb
(
skb
);
err_update_stats:
tp
->
stats
.
tx_dropped
++
;
goto
out
;
}
static
void
rtl8169_tx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
unsigned
long
dirty_tx
,
tx_left
=
0
;
unsigned
long
dirty_tx
,
tx_left
;
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
...
...
@@ -881,18 +1392,24 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
while
(
tx_left
>
0
)
{
int
entry
=
dirty_tx
%
NUM_TX_DESC
;
struct
sk_buff
*
skb
=
tp
->
Tx_skbuff
[
entry
];
u32
status
;
if
((
tp
->
TxDescArray
[
entry
].
status
&
OWNbit
)
==
0
)
{
struct
sk_buff
*
skb
=
tp
->
Tx_skbuff
[
entry
];
rmb
();
status
=
le32_to_cpu
(
tp
->
TxDescArray
[
entry
].
status
);
if
(
status
&
OWNbit
)
break
;
tp
->
stats
.
tx_bytes
+=
skb
->
len
>=
ETH_ZLEN
?
skb
->
len
:
ETH_ZLEN
;
tp
->
stats
.
tx_packets
++
;
dev_kfree_skb_irq
(
skb
);
tp
->
Tx_skbuff
[
entry
]
=
NULL
;
dirty_tx
++
;
tx_left
--
;
}
/* FIXME: is it really accurate for TxErr ? */
tp
->
stats
.
tx_bytes
+=
skb
->
len
>=
ETH_ZLEN
?
skb
->
len
:
ETH_ZLEN
;
tp
->
stats
.
tx_packets
++
;
rtl8169_unmap_tx_skb
(
tp
->
pci_dev
,
tp
->
Tx_skbuff
+
entry
,
tp
->
TxDescArray
+
entry
);
dev_kfree_skb_irq
(
skb
);
tp
->
Tx_skbuff
[
entry
]
=
NULL
;
dirty_tx
++
;
tx_left
--
;
}
if
(
tp
->
dirty_tx
!=
dirty_tx
)
{
...
...
@@ -902,70 +1419,108 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
}
}
static
inline
int
rtl8169_try_rx_copy
(
struct
sk_buff
**
sk_buff
,
int
pkt_size
,
struct
RxDesc
*
desc
,
struct
net_device
*
dev
)
{
int
ret
=
-
1
;
if
(
pkt_size
<
rx_copybreak
)
{
struct
sk_buff
*
skb
;
skb
=
dev_alloc_skb
(
pkt_size
+
2
);
if
(
skb
)
{
skb
->
dev
=
dev
;
skb_reserve
(
skb
,
2
);
eth_copy_and_sum
(
skb
,
sk_buff
[
0
]
->
tail
,
pkt_size
,
0
);
*
sk_buff
=
skb
;
rtl8169_return_to_asic
(
desc
);
ret
=
0
;
}
}
return
ret
;
}
static
void
rtl8169_rx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
int
cur_rx
;
struct
sk_buff
*
skb
;
int
pkt_size
=
0
;
unsigned
long
cur_rx
,
rx_left
;
int
delta
;
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
cur_rx
=
tp
->
cur_rx
;
rx_left
=
NUM_RX_DESC
+
tp
->
dirty_rx
-
cur_rx
;
while
(
rx_left
>
0
)
{
int
entry
=
cur_rx
%
NUM_RX_DESC
;
u32
status
;
while
((
tp
->
RxDescArray
[
cur_rx
].
status
&
OWNbit
)
==
0
)
{
rmb
();
status
=
le32_to_cpu
(
tp
->
RxDescArray
[
entry
].
status
);
if
(
tp
->
RxDescArray
[
cur_rx
].
status
&
RxRES
)
{
if
(
status
&
OWNbit
)
break
;
if
(
status
&
RxRES
)
{
printk
(
KERN_INFO
"%s: Rx ERROR!!!
\n
"
,
dev
->
name
);
tp
->
stats
.
rx_errors
++
;
if
(
tp
->
RxDescArray
[
cur_rx
].
status
&
(
RxRWT
|
RxRUNT
))
if
(
status
&
(
RxRWT
|
RxRUNT
))
tp
->
stats
.
rx_length_errors
++
;
if
(
tp
->
RxDescArray
[
cur_rx
].
status
&
RxCRC
)
if
(
status
&
RxCRC
)
tp
->
stats
.
rx_crc_errors
++
;
}
else
{
pkt_size
=
(
int
)
(
tp
->
RxDescArray
[
cur_rx
].
status
&
0x00001FFF
)
-
4
;
skb
=
dev_alloc_skb
(
pkt_size
+
2
);
if
(
skb
!=
NULL
)
{
skb
->
dev
=
dev
;
skb_reserve
(
skb
,
2
);
// 16 byte align the IP fields. //
eth_copy_and_sum
(
skb
,
tp
->
RxBufferRing
[
cur_rx
],
pkt_size
,
0
);
skb_put
(
skb
,
pkt_size
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
netif_rx
(
skb
);
if
(
cur_rx
==
(
NUM_RX_DESC
-
1
))
tp
->
RxDescArray
[
cur_rx
].
status
=
(
OWNbit
|
EORbit
)
+
RX_BUF_SIZE
;
else
tp
->
RxDescArray
[
cur_rx
].
status
=
OWNbit
+
RX_BUF_SIZE
;
tp
->
RxDescArray
[
cur_rx
].
buf_addr
=
virt_to_bus
(
tp
->
RxBufferRing
[
cur_rx
]);
dev
->
last_rx
=
jiffies
;
tp
->
stats
.
rx_bytes
+=
pkt_size
;
tp
->
stats
.
rx_packets
++
;
}
else
{
printk
(
KERN_WARNING
"%s: Memory squeeze, deferring packet.
\n
"
,
dev
->
name
);
/* We should check that some rx space is free.
If not, free one and mark stats->rx_dropped++. */
tp
->
stats
.
rx_dropped
++
;
struct
RxDesc
*
desc
=
tp
->
RxDescArray
+
entry
;
struct
sk_buff
*
skb
=
tp
->
Rx_skbuff
[
entry
];
int
pkt_size
=
(
status
&
0x00001FFF
)
-
4
;
void
(
*
pci_action
)(
struct
pci_dev
*
,
dma_addr_t
,
size_t
,
int
)
=
pci_dma_sync_single_for_device
;
pci_dma_sync_single_for_cpu
(
tp
->
pci_dev
,
le64_to_cpu
(
desc
->
addr
),
RX_BUF_SIZE
,
PCI_DMA_FROMDEVICE
);
if
(
rtl8169_try_rx_copy
(
&
skb
,
pkt_size
,
desc
,
dev
))
{
pci_action
=
pci_unmap_single
;
tp
->
Rx_skbuff
[
entry
]
=
NULL
;
}
}
cur_rx
=
(
cur_rx
+
1
)
%
NUM_RX_DESC
;
pci_action
(
tp
->
pci_dev
,
le64_to_cpu
(
desc
->
addr
),
RX_BUF_SIZE
,
PCI_DMA_FROMDEVICE
);
skb_put
(
skb
,
pkt_size
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
netif_rx
(
skb
);
dev
->
last_rx
=
jiffies
;
tp
->
stats
.
rx_bytes
+=
pkt_size
;
tp
->
stats
.
rx_packets
++
;
}
cur_rx
++
;
rx_left
--
;
}
tp
->
cur_rx
=
cur_rx
;
delta
=
rtl8169_rx_fill
(
tp
,
dev
,
tp
->
dirty_rx
,
tp
->
cur_rx
);
if
(
delta
>
0
)
tp
->
dirty_rx
+=
delta
;
else
if
(
delta
<
0
)
printk
(
KERN_INFO
"%s: no Rx buffer allocated
\n
"
,
dev
->
name
);
/*
* FIXME: until there is periodic timer to try and refill the ring,
* a temporary shortage may definitely kill the Rx process.
* - disable the asic to try and avoid an overflow and kick it again
* after refill ?
* - how do others driver handle this condition (Uh oh...).
*/
if
(
tp
->
dirty_rx
+
NUM_RX_DESC
==
tp
->
cur_rx
)
printk
(
KERN_EMERG
"%s: Rx buffers exhausted
\n
"
,
dev
->
name
);
}
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
...
...
@@ -982,8 +1537,8 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
do
{
status
=
RTL_R16
(
IntrStatus
);
/* h
/w no longer present (hotplug?) or major error, bail
*/
if
(
status
==
0xFFFF
)
/* h
otplug/major error/no more work/shared irq
*/
if
(
(
status
==
0xFFFF
)
||
!
status
)
break
;
handled
=
1
;
...
...
@@ -994,9 +1549,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
RTL_W16
(
IntrStatus
,
(
status
&
RxFIFOOver
)
?
(
status
|
RxOverflow
)
:
status
);
if
((
status
&
(
SYSErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
))
==
0
)
if
(
!
(
status
&
rtl8169_intr_mask
))
break
;
// Rx interrupt
...
...
@@ -1026,11 +1579,13 @@ static int
rtl8169_close
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
i
;
netif_stop_queue
(
dev
);
rtl8169_delete_timer
(
dev
);
spin_lock_irq
(
&
tp
->
lock
);
/* Stop the chip's Tx and Rx DMA processes. */
...
...
@@ -1049,16 +1604,15 @@ rtl8169_close(struct net_device *dev)
free_irq
(
dev
->
irq
,
dev
);
rtl8169_tx_clear
(
tp
);
kfree
(
tp
->
TxDescArrays
);
kfree
(
tp
->
RxDescArrays
);
tp
->
TxDescArrays
=
NULL
;
tp
->
RxDescArrays
=
NULL
;
rtl8169_rx_clear
(
tp
);
pci_free_consistent
(
pdev
,
R8169_RX_RING_BYTES
,
tp
->
RxDescArray
,
tp
->
RxPhyAddr
);
pci_free_consistent
(
pdev
,
R8169_TX_RING_BYTES
,
tp
->
TxDescArray
,
tp
->
TxPhyAddr
);
tp
->
TxDescArray
=
NULL
;
tp
->
RxDescArray
=
NULL
;
kfree
(
tp
->
RxBufferRings
);
for
(
i
=
0
;
i
<
NUM_RX_DESC
;
i
++
)
{
tp
->
RxBufferRing
[
i
]
=
NULL
;
}
return
0
;
}
...
...
@@ -1112,11 +1666,25 @@ rtl8169_set_rx_mode(struct net_device *dev)
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
}
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
dev
)
/**
* rtl8169_get_stats - Get rtl8169 read/write statistics
* @dev: The Ethernet Device to get statistics for
*
* Get TX/RX statistics for rtl8169
*/
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
if
(
netif_running
(
dev
))
{
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
tp
->
stats
.
rx_missed_errors
+=
RTL_R32
(
RxMissed
);
RTL_W32
(
RxMissed
,
0
);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
}
return
&
tp
->
stats
;
}
...
...
@@ -1125,8 +1693,10 @@ static struct pci_driver rtl8169_pci_driver = {
.
id_table
=
rtl8169_pci_tbl
,
.
probe
=
rtl8169_init_one
,
.
remove
=
__devexit_p
(
rtl8169_remove_one
),
.
suspend
=
NULL
,
.
resume
=
NULL
,
#ifdef CONFIG_PM
.
suspend
=
rtl8169_suspend
,
.
resume
=
rtl8169_resume
,
#endif
};
static
int
__init
...
...
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