Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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