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
61304905
Commit
61304905
authored
Jul 02, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge pobox.com:/spare/repo/linux-2.6
into pobox.com:/spare/repo/netdev-2.6/r8169
parents
004a3668
d15947f4
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
456 additions
and
202 deletions
+456
-202
drivers/net/Kconfig
drivers/net/Kconfig
+5
-0
drivers/net/r8169.c
drivers/net/r8169.c
+451
-202
No files found.
drivers/net/Kconfig
View file @
61304905
...
@@ -2043,6 +2043,11 @@ config R8169
...
@@ -2043,6 +2043,11 @@ config R8169
To compile this driver as a module, choose M here: the module
To compile this driver as a module, choose M here: the module
will be called r8169. This is recommended.
will be called r8169. This is recommended.
config R8169_NAPI
bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
depends on R8169 && EXPERIMENTAL
config SK98LIN
config SK98LIN
tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
depends on PCI
depends on PCI
...
...
drivers/net/r8169.c
View file @
61304905
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
May 20 2002 - Add link status force-mode and TBI mode support.
May 20 2002 - Add link status force-mode and TBI mode support.
=========================================================================
=========================================================================
1. The media can be forced in 5 modes.
1.
[DEPRECATED: use ethtool instead]
The media can be forced in 5 modes.
Command: 'insmod r8169 media = SET_MEDIA'
Command: 'insmod r8169 media = SET_MEDIA'
Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
...
@@ -41,6 +41,7 @@ VERSION 1.2 <2002/11/30>
...
@@ -41,6 +41,7 @@ VERSION 1.2 <2002/11/30>
#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
...
@@ -64,6 +65,14 @@ VERSION 1.2 <2002/11/30>
...
@@ -64,6 +65,14 @@ VERSION 1.2 <2002/11/30>
#define dprintk(fmt, args...) do {} while (0)
#define dprintk(fmt, args...) do {} while (0)
#endif
/* RTL8169_DEBUG */
#endif
/* RTL8169_DEBUG */
#ifdef CONFIG_R8169_NAPI
#define rtl8169_rx_skb netif_receive_skb
#define rtl8169_rx_quota(count, quota) min(count, quota)
#else
#define rtl8169_rx_skb netif_rx
#define rtl8169_rx_quota(count, quota) count
#endif
/* media options */
/* media options */
#define MAX_UNITS 8
#define MAX_UNITS 8
static
int
media
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
static
int
media
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
...
@@ -90,15 +99,16 @@ static int multicast_filter_limit = 32;
...
@@ -90,15 +99,16 @@ static int multicast_filter_limit = 32;
#define RxPacketMaxSize 0x0800
/* Maximum size supported is 16K-1 */
#define RxPacketMaxSize 0x0800
/* Maximum size supported is 16K-1 */
#define InterFrameGap 0x03
/* 3 means InterFrameGap = the shortest one */
#define InterFrameGap 0x03
/* 3 means InterFrameGap = the shortest one */
#define R8169_NAPI_WEIGHT 64
#define NUM_TX_DESC 64
/* Number of Tx descriptor registers */
#define NUM_TX_DESC 64
/* Number of Tx descriptor registers */
#define NUM_RX_DESC
64
/* Number of Rx descriptor registers */
#define NUM_RX_DESC
256
/* Number of Rx descriptor registers */
#define RX_BUF_SIZE 1536
/* Rx Buffer size */
#define RX_BUF_SIZE 1536
/* Rx Buffer size */
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
#define RTL_MIN_IO_SIZE 0x80
#define RTL_MIN_IO_SIZE 0x80
#define RTL8169_TX_TIMEOUT (6*HZ)
#define RTL8169_TX_TIMEOUT (6*HZ)
#define RTL8169_PHY_TIMEOUT (
HZ)
#define RTL8169_PHY_TIMEOUT (
10*HZ)
/* write/read MMIO register */
/* write/read MMIO register */
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
...
@@ -194,7 +204,7 @@ enum RTL8169_register_content {
...
@@ -194,7 +204,7 @@ enum RTL8169_register_content {
SWInt
=
0x0100
,
SWInt
=
0x0100
,
TxDescUnavail
=
0x80
,
TxDescUnavail
=
0x80
,
RxFIFOOver
=
0x40
,
RxFIFOOver
=
0x40
,
RxUnderrun
=
0x20
,
LinkChg
=
0x20
,
RxOverflow
=
0x10
,
RxOverflow
=
0x10
,
TxErr
=
0x08
,
TxErr
=
0x08
,
TxOK
=
0x04
,
TxOK
=
0x04
,
...
@@ -233,6 +243,14 @@ enum RTL8169_register_content {
...
@@ -233,6 +243,14 @@ enum RTL8169_register_content {
TxInterFrameGapShift
=
24
,
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 */
/* TBICSR p.28 */
TBIReset
=
0x80000000
,
TBILoopback
=
0x40000000
,
TBINwEnable
=
0x20000000
,
TBINwRestart
=
0x10000000
,
TBILinkOk
=
0x02000000
,
TBINwComplete
=
0x01000000
,
/* CPlusCmd p.31 */
/* CPlusCmd p.31 */
RxVlan
=
(
1
<<
6
),
RxVlan
=
(
1
<<
6
),
RxChkSum
=
(
1
<<
5
),
RxChkSum
=
(
1
<<
5
),
...
@@ -306,10 +324,10 @@ struct RxDesc {
...
@@ -306,10 +324,10 @@ struct RxDesc {
};
};
struct
rtl8169_private
{
struct
rtl8169_private
{
void
*
mmio_addr
;
/* memory map physical address */
void
*
mmio_addr
;
/* memory map physical address */
struct
pci_dev
*
pci_dev
;
/* Index of PCI device */
struct
pci_dev
*
pci_dev
;
/* Index of PCI device */
struct
net_device_stats
stats
;
/* statistics of net device */
struct
net_device_stats
stats
;
/* statistics of net device */
spinlock_t
lock
;
/* spin lock flag */
spinlock_t
lock
;
/* spin lock flag */
int
chipset
;
int
chipset
;
int
mac_version
;
int
mac_version
;
int
phy_version
;
int
phy_version
;
...
@@ -317,15 +335,23 @@ struct rtl8169_private {
...
@@ -317,15 +335,23 @@ struct rtl8169_private {
u32
cur_tx
;
/* Index into the Tx descriptor buffer of next Rx pkt. */
u32
cur_tx
;
/* Index into the Tx descriptor buffer of next Rx pkt. */
u32
dirty_rx
;
u32
dirty_rx
;
u32
dirty_tx
;
u32
dirty_tx
;
struct
TxDesc
*
TxDescArray
;
/*
Index of 256-alignment Tx Descriptor buffer
*/
struct
TxDesc
*
TxDescArray
;
/*
256-aligned Tx descriptor ring
*/
struct
RxDesc
*
RxDescArray
;
/*
Index of 256-alignment Rx Descriptor buffer
*/
struct
RxDesc
*
RxDescArray
;
/*
256-aligned Rx descriptor ring
*/
dma_addr_t
TxPhyAddr
;
dma_addr_t
TxPhyAddr
;
dma_addr_t
RxPhyAddr
;
dma_addr_t
RxPhyAddr
;
struct
sk_buff
*
Rx_skbuff
[
NUM_RX_DESC
];
/* Rx data buffers */
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
sk_buff
*
Tx_skbuff
[
NUM_TX_DESC
];
/*
Tx data buffers
*/
struct
timer_list
timer
;
struct
timer_list
timer
;
unsigned
long
phy_link_down_cnt
;
u16
cp_cmd
;
u16
cp_cmd
;
u16
intr_mask
;
int
phy_auto_nego_reg
;
int
phy_1000_ctrl_reg
;
int
(
*
set_speed
)(
struct
net_device
*
,
u8
autoneg
,
u16
speed
,
u8
duplex
);
void
(
*
get_settings
)(
struct
net_device
*
,
struct
ethtool_cmd
*
);
void
(
*
phy_reset_enable
)(
void
*
);
unsigned
int
(
*
phy_reset_pending
)(
void
*
);
unsigned
int
(
*
link_ok
)(
void
*
);
};
};
MODULE_AUTHOR
(
"Realtek"
);
MODULE_AUTHOR
(
"Realtek"
);
...
@@ -344,9 +370,14 @@ static int rtl8169_close(struct net_device *dev);
...
@@ -344,9 +370,14 @@ static int rtl8169_close(struct net_device *dev);
static
void
rtl8169_set_rx_mode
(
struct
net_device
*
dev
);
static
void
rtl8169_set_rx_mode
(
struct
net_device
*
dev
);
static
void
rtl8169_tx_timeout
(
struct
net_device
*
dev
);
static
void
rtl8169_tx_timeout
(
struct
net_device
*
dev
);
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
netdev
);
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
netdev
);
#ifdef CONFIG_R8169_NAPI
static
int
rtl8169_poll
(
struct
net_device
*
dev
,
int
*
budget
);
#endif
static
const
u16
rtl8169_intr_mask
=
static
const
u16
rtl8169_intr_mask
=
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
LinkChg
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
static
const
u16
rtl8169_napi_event
=
RxOK
|
RxOverflow
|
RxFIFOOver
|
TxOK
|
TxErr
;
static
const
unsigned
int
rtl8169_rx_config
=
static
const
unsigned
int
rtl8169_rx_config
=
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
...
@@ -364,11 +395,9 @@ static void mdio_write(void *ioaddr, int RegAddr, int value)
...
@@ -364,11 +395,9 @@ static void mdio_write(void *ioaddr, int RegAddr, int value)
for
(
i
=
2000
;
i
>
0
;
i
--
)
{
for
(
i
=
2000
;
i
>
0
;
i
--
)
{
// Check if the RTL8169 has completed writing to the specified MII register
// Check if the RTL8169 has completed writing to the specified MII register
if
(
!
(
RTL_R32
(
PHYAR
)
&
0x80000000
))
{
if
(
!
(
RTL_R32
(
PHYAR
)
&
0x80000000
))
break
;
break
;
}
else
{
udelay
(
100
);
udelay
(
100
);
}
}
}
}
}
...
@@ -390,18 +419,264 @@ static int mdio_read(void *ioaddr, int RegAddr)
...
@@ -390,18 +419,264 @@ static int mdio_read(void *ioaddr, int RegAddr)
return
value
;
return
value
;
}
}
static
unsigned
int
rtl8169_tbi_reset_pending
(
void
*
ioaddr
)
{
return
RTL_R32
(
TBICSR
)
&
TBIReset
;
}
static
unsigned
int
rtl8169_xmii_reset_pending
(
void
*
ioaddr
)
{
return
mdio_read
(
ioaddr
,
0
)
&
0x8000
;
}
static
unsigned
int
rtl8169_tbi_link_ok
(
void
*
ioaddr
)
{
return
RTL_R32
(
TBICSR
)
&
TBILinkOk
;
}
static
unsigned
int
rtl8169_xmii_link_ok
(
void
*
ioaddr
)
{
return
RTL_R8
(
PHYstatus
)
&
LinkStatus
;
}
static
void
rtl8169_tbi_reset_enable
(
void
*
ioaddr
)
{
RTL_W32
(
TBICSR
,
RTL_R32
(
TBICSR
)
|
TBIReset
);
}
static
void
rtl8169_xmii_reset_enable
(
void
*
ioaddr
)
{
unsigned
int
val
;
val
=
(
mdio_read
(
ioaddr
,
PHY_CTRL_REG
)
|
0x8000
)
&
0xffff
;
mdio_write
(
ioaddr
,
PHY_CTRL_REG
,
val
);
}
static
void
rtl8169_check_link_status
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
if
(
tp
->
link_ok
(
ioaddr
))
{
netif_carrier_on
(
dev
);
printk
(
KERN_INFO
PFX
"%s: link up
\n
"
,
dev
->
name
);
}
else
netif_carrier_off
(
dev
);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
}
static
void
rtl8169_link_option
(
int
idx
,
u8
*
autoneg
,
u16
*
speed
,
u8
*
duplex
)
{
struct
{
u16
speed
;
u8
duplex
;
u8
autoneg
;
u8
media
;
}
link_settings
[]
=
{
{
SPEED_10
,
DUPLEX_HALF
,
AUTONEG_DISABLE
,
_10_Half
},
{
SPEED_10
,
DUPLEX_FULL
,
AUTONEG_DISABLE
,
_10_Full
},
{
SPEED_100
,
DUPLEX_HALF
,
AUTONEG_DISABLE
,
_100_Half
},
{
SPEED_100
,
DUPLEX_FULL
,
AUTONEG_DISABLE
,
_100_Full
},
{
SPEED_1000
,
DUPLEX_FULL
,
AUTONEG_DISABLE
,
_1000_Full
},
/* Make TBI happy */
{
SPEED_1000
,
DUPLEX_FULL
,
AUTONEG_ENABLE
,
0xff
}
},
*
p
;
unsigned
char
option
;
option
=
((
idx
<
MAX_UNITS
)
&&
(
idx
>=
0
))
?
media
[
idx
]
:
0xff
;
if
((
option
!=
0xff
)
&&
!
idx
)
printk
(
KERN_WARNING
PFX
"media option is deprecated.
\n
"
);
for
(
p
=
link_settings
;
p
->
media
!=
0xff
;
p
++
)
{
if
(
p
->
media
==
option
)
break
;
}
*
autoneg
=
p
->
autoneg
;
*
speed
=
p
->
speed
;
*
duplex
=
p
->
duplex
;
}
static
void
rtl8169_get_drvinfo
(
struct
net_device
*
dev
,
static
void
rtl8169_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
struct
ethtool_drvinfo
*
info
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
strcpy
(
info
->
driver
,
RTL8169_DRIVER_NAME
);
strcpy
(
info
->
driver
,
RTL8169_DRIVER_NAME
);
strcpy
(
info
->
version
,
RTL8169_VERSION
);
strcpy
(
info
->
version
,
RTL8169_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
tp
->
pci_dev
));
strcpy
(
info
->
bus_info
,
pci_name
(
tp
->
pci_dev
));
}
}
static
int
rtl8169_set_speed_tbi
(
struct
net_device
*
dev
,
u8
autoneg
,
u16
speed
,
u8
duplex
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
void
*
ioaddr
=
tp
->
mmio_addr
;
int
ret
=
0
;
u32
reg
;
reg
=
RTL_R32
(
TBICSR
);
if
((
autoneg
==
AUTONEG_DISABLE
)
&&
(
speed
==
SPEED_1000
)
&&
(
duplex
==
DUPLEX_FULL
))
{
RTL_W32
(
TBICSR
,
reg
&
~
(
TBINwEnable
|
TBINwRestart
));
}
else
if
(
autoneg
==
AUTONEG_ENABLE
)
RTL_W32
(
TBICSR
,
reg
|
TBINwEnable
|
TBINwRestart
);
else
{
printk
(
KERN_WARNING
PFX
"%s: incorrect speed setting refused in TBI mode
\n
"
,
dev
->
name
);
ret
=
-
EOPNOTSUPP
;
}
return
ret
;
}
static
int
rtl8169_set_speed_xmii
(
struct
net_device
*
dev
,
u8
autoneg
,
u16
speed
,
u8
duplex
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
void
*
ioaddr
=
tp
->
mmio_addr
;
int
auto_nego
,
giga_ctrl
;
auto_nego
=
mdio_read
(
ioaddr
,
PHY_AUTO_NEGO_REG
);
auto_nego
&=
~
(
PHY_Cap_10_Half
|
PHY_Cap_10_Full
|
PHY_Cap_100_Half
|
PHY_Cap_100_Full
);
giga_ctrl
=
mdio_read
(
ioaddr
,
PHY_1000_CTRL_REG
);
giga_ctrl
&=
~
(
PHY_Cap_1000_Full
|
PHY_Cap_Null
);
if
(
autoneg
==
AUTONEG_ENABLE
)
{
auto_nego
|=
(
PHY_Cap_10_Half
|
PHY_Cap_10_Full
|
PHY_Cap_100_Half
|
PHY_Cap_100_Full
);
giga_ctrl
|=
PHY_Cap_1000_Full
;
}
else
{
if
(
speed
==
SPEED_10
)
auto_nego
|=
PHY_Cap_10_Half
|
PHY_Cap_10_Full
;
else
if
(
speed
==
SPEED_100
)
auto_nego
|=
PHY_Cap_100_Half
|
PHY_Cap_100_Full
;
else
if
(
speed
==
SPEED_1000
)
giga_ctrl
|=
PHY_Cap_1000_Full
;
if
(
duplex
==
DUPLEX_HALF
)
auto_nego
&=
~
(
PHY_Cap_10_Full
|
PHY_Cap_100_Full
);
}
tp
->
phy_auto_nego_reg
=
auto_nego
;
tp
->
phy_1000_ctrl_reg
=
giga_ctrl
;
mdio_write
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
auto_nego
);
mdio_write
(
ioaddr
,
PHY_1000_CTRL_REG
,
giga_ctrl
);
mdio_write
(
ioaddr
,
PHY_CTRL_REG
,
PHY_Enable_Auto_Nego
|
PHY_Restart_Auto_Nego
);
return
0
;
}
static
int
rtl8169_set_speed
(
struct
net_device
*
dev
,
u8
autoneg
,
u16
speed
,
u8
duplex
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
int
ret
;
ret
=
tp
->
set_speed
(
dev
,
autoneg
,
speed
,
duplex
);
if
(
netif_running
(
dev
)
&&
(
tp
->
phy_1000_ctrl_reg
&
PHY_Cap_1000_Full
))
mod_timer
(
&
tp
->
timer
,
jiffies
+
RTL8169_PHY_TIMEOUT
);
return
ret
;
}
static
int
rtl8169_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
ret
=
rtl8169_set_speed
(
dev
,
cmd
->
autoneg
,
cmd
->
speed
,
cmd
->
duplex
);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
return
ret
;
}
static
void
rtl8169_gset_tbi
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
void
*
ioaddr
=
tp
->
mmio_addr
;
u32
status
;
cmd
->
supported
=
SUPPORTED_1000baseT_Full
|
SUPPORTED_Autoneg
|
SUPPORTED_FIBRE
;
cmd
->
port
=
PORT_FIBRE
;
cmd
->
transceiver
=
XCVR_INTERNAL
;
status
=
RTL_R32
(
TBICSR
);
cmd
->
advertising
=
(
status
&
TBINwEnable
)
?
ADVERTISED_Autoneg
:
0
;
cmd
->
autoneg
=
!!
(
status
&
TBINwEnable
);
cmd
->
speed
=
SPEED_1000
;
cmd
->
duplex
=
DUPLEX_FULL
;
/* Always set */
}
static
void
rtl8169_gset_xmii
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
void
*
ioaddr
=
tp
->
mmio_addr
;
u8
status
;
cmd
->
supported
=
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_1000baseT_Full
|
SUPPORTED_Autoneg
|
SUPPORTED_TP
;
cmd
->
autoneg
=
1
;
cmd
->
advertising
=
ADVERTISED_TP
|
ADVERTISED_Autoneg
;
if
(
tp
->
phy_auto_nego_reg
&
PHY_Cap_10_Half
)
cmd
->
advertising
|=
ADVERTISED_10baseT_Half
;
if
(
tp
->
phy_auto_nego_reg
&
PHY_Cap_10_Full
)
cmd
->
advertising
|=
ADVERTISED_10baseT_Full
;
if
(
tp
->
phy_auto_nego_reg
&
PHY_Cap_100_Half
)
cmd
->
advertising
|=
ADVERTISED_100baseT_Half
;
if
(
tp
->
phy_auto_nego_reg
&
PHY_Cap_100_Full
)
cmd
->
advertising
|=
ADVERTISED_100baseT_Full
;
if
(
tp
->
phy_1000_ctrl_reg
&
PHY_Cap_1000_Full
)
cmd
->
advertising
|=
ADVERTISED_1000baseT_Full
;
status
=
RTL_R8
(
PHYstatus
);
if
(
status
&
_1000bpsF
)
cmd
->
speed
=
SPEED_1000
;
else
if
(
status
&
_100bps
)
cmd
->
speed
=
SPEED_100
;
else
if
(
status
&
_10bps
)
cmd
->
speed
=
SPEED_10
;
cmd
->
duplex
=
((
status
&
_1000bpsF
)
||
(
status
&
FullDup
))
?
DUPLEX_FULL
:
DUPLEX_HALF
;
}
static
int
rtl8169_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
tp
->
get_settings
(
dev
,
cmd
);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
return
0
;
}
static
struct
ethtool_ops
rtl8169_ethtool_ops
=
{
static
struct
ethtool_ops
rtl8169_ethtool_ops
=
{
.
get_drvinfo
=
rtl8169_get_drvinfo
,
.
get_drvinfo
=
rtl8169_get_drvinfo
,
.
get_link
=
ethtool_op_get_link
,
.
get_settings
=
rtl8169_get_settings
,
.
set_settings
=
rtl8169_set_settings
,
};
};
static
void
rtl8169_write_gmii_reg_bit
(
void
*
ioaddr
,
int
reg
,
int
bitnum
,
static
void
rtl8169_write_gmii_reg_bit
(
void
*
ioaddr
,
int
reg
,
int
bitnum
,
...
@@ -500,7 +775,7 @@ static void rtl8169_print_phy_version(struct rtl8169_private *tp)
...
@@ -500,7 +775,7 @@ static void rtl8169_print_phy_version(struct rtl8169_private *tp)
static
void
rtl8169_hw_phy_config
(
struct
net_device
*
dev
)
static
void
rtl8169_hw_phy_config
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
struct
{
struct
{
u16
regs
[
5
];
/* Beware of bit-sign propagation */
u16
regs
[
5
];
/* Beware of bit-sign propagation */
...
@@ -566,61 +841,47 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
...
@@ -566,61 +841,47 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
mdio_write
(
ioaddr
,
31
,
0x0000
);
//w 31 2 0 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
)
static
void
rtl8169_phy_timer
(
unsigned
long
__opaque
)
{
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
__opaque
;
struct
net_device
*
dev
=
(
struct
net_device
*
)
__opaque
;
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
timeout
=
RTL8169_PHY_TIMEOUT
;
assert
(
tp
->
mac_version
>
RTL_GIGA_MAC_VER_B
);
assert
(
tp
->
mac_version
>
RTL_GIGA_MAC_VER_B
);
assert
(
tp
->
phy_version
<
RTL_GIGA_PHY_VER_G
);
assert
(
tp
->
phy_version
<
RTL_GIGA_PHY_VER_G
);
if
(
RTL_R8
(
PHYstatus
)
&
LinkStatus
)
if
(
!
(
tp
->
phy_1000_ctrl_reg
&
PHY_Cap_1000_Full
))
tp
->
phy_link_down_cnt
=
0
;
return
;
else
{
tp
->
phy_link_down_cnt
++
;
if
(
tp
->
phy_link_down_cnt
>=
12
)
{
int
reg
;
// If link on 1000, perform phy reset.
spin_lock_irq
(
&
tp
->
lock
);
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
;
if
(
tp
->
phy_reset_pending
(
ioaddr
))
{
}
/*
* A busy loop could burn quite a few cycles on nowadays CPU.
* Let's delay the execution of the timer for a few ticks.
*/
timeout
=
HZ
/
10
;
goto
out_mod_timer
;
}
}
mod_timer
(
timer
,
jiffies
+
RTL8169_PHY_TIMEOUT
);
if
(
tp
->
link_ok
(
ioaddr
))
goto
out_unlock
;
printk
(
KERN_WARNING
PFX
"%s: PHY reset until link up
\n
"
,
dev
->
name
);
tp
->
phy_reset_enable
(
ioaddr
);
out_mod_timer:
mod_timer
(
timer
,
jiffies
+
timeout
);
out_unlock:
spin_unlock_irq
(
&
tp
->
lock
);
}
}
static
inline
void
rtl8169_delete_timer
(
struct
net_device
*
dev
)
static
inline
void
rtl8169_delete_timer
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
...
@@ -628,21 +889,17 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
...
@@ -628,21 +889,17 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
return
;
return
;
del_timer_sync
(
timer
);
del_timer_sync
(
timer
);
tp
->
phy_link_down_cnt
=
0
;
}
}
static
inline
void
rtl8169_request_timer
(
struct
net_device
*
dev
)
static
inline
void
rtl8169_request_timer
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
struct
timer_list
*
timer
=
&
tp
->
timer
;
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
if
((
tp
->
mac_version
<=
RTL_GIGA_MAC_VER_B
)
||
(
tp
->
phy_version
>=
RTL_GIGA_PHY_VER_G
))
(
tp
->
phy_version
>=
RTL_GIGA_PHY_VER_G
))
return
;
return
;
tp
->
phy_link_down_cnt
=
0
;
init_timer
(
timer
);
init_timer
(
timer
);
timer
->
expires
=
jiffies
+
RTL8169_PHY_TIMEOUT
;
timer
->
expires
=
jiffies
+
RTL8169_PHY_TIMEOUT
;
timer
->
data
=
(
unsigned
long
)(
dev
);
timer
->
data
=
(
unsigned
long
)(
dev
);
...
@@ -681,7 +938,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
...
@@ -681,7 +938,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
// enable device (incl. PCI PM wakeup and hotplug setup)
// enable device (incl. PCI PM wakeup and hotplug setup)
rc
=
pci_enable_device
(
pdev
);
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
{
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"%s:
unable to enable devic
e
\n
"
,
pdev
->
slot_name
);
printk
(
KERN_ERR
PFX
"%s:
enable failur
e
\n
"
,
pdev
->
slot_name
);
goto
err_out
;
goto
err_out
;
}
}
...
@@ -693,7 +950,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
...
@@ -693,7 +950,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
pci_read_config_word
(
pdev
,
pm_cap
+
PCI_PM_CTRL
,
&
pwr_command
);
pci_read_config_word
(
pdev
,
pm_cap
+
PCI_PM_CTRL
,
&
pwr_command
);
acpi_idle_state
=
pwr_command
&
PCI_PM_CTRL_STATE_MASK
;
acpi_idle_state
=
pwr_command
&
PCI_PM_CTRL_STATE_MASK
;
}
else
{
}
else
{
printk
(
KERN_ERR
PFX
"Cannot find PowerManagement capability, aborting.
\n
"
);
printk
(
KERN_ERR
PFX
"Cannot find PowerManagement capability, aborting.
\n
"
);
goto
err_out_free_res
;
goto
err_out_free_res
;
}
}
...
@@ -718,7 +976,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
...
@@ -718,7 +976,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
rc
=
pci_request_regions
(
pdev
,
MODULENAME
);
rc
=
pci_request_regions
(
pdev
,
MODULENAME
);
if
(
rc
)
{
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"%s: Could not request regions.
\n
"
,
pdev
->
slot_name
);
printk
(
KERN_ERR
PFX
"%s: could not request regions.
\n
"
,
pdev
->
slot_name
);
goto
err_out_disable
;
goto
err_out_disable
;
}
}
...
@@ -800,8 +1059,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -800,8 +1059,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void
*
ioaddr
=
NULL
;
void
*
ioaddr
=
NULL
;
static
int
board_idx
=
-
1
;
static
int
board_idx
=
-
1
;
static
int
printed_version
=
0
;
static
int
printed_version
=
0
;
u8
autoneg
,
duplex
;
u16
speed
;
int
i
,
rc
;
int
i
,
rc
;
int
option
=
-
1
,
Cap10_100
=
0
,
Cap1000
=
0
;
assert
(
pdev
!=
NULL
);
assert
(
pdev
!=
NULL
);
assert
(
ent
!=
NULL
);
assert
(
ent
!=
NULL
);
...
@@ -822,6 +1082,22 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -822,6 +1082,22 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
assert
(
dev
!=
NULL
);
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
tp
!=
NULL
);
if
(
RTL_R8
(
PHYstatus
)
&
TBI_Enable
)
{
tp
->
set_speed
=
rtl8169_set_speed_tbi
;
tp
->
get_settings
=
rtl8169_gset_tbi
;
tp
->
phy_reset_enable
=
rtl8169_tbi_reset_enable
;
tp
->
phy_reset_pending
=
rtl8169_tbi_reset_pending
;
tp
->
link_ok
=
rtl8169_tbi_link_ok
;
tp
->
phy_1000_ctrl_reg
=
PHY_Cap_1000_Full
;
/* Implied by TBI */
}
else
{
tp
->
set_speed
=
rtl8169_set_speed_xmii
;
tp
->
get_settings
=
rtl8169_gset_xmii
;
tp
->
phy_reset_enable
=
rtl8169_xmii_reset_enable
;
tp
->
phy_reset_pending
=
rtl8169_xmii_reset_pending
;
tp
->
link_ok
=
rtl8169_xmii_link_ok
;
}
// Get MAC address. FIXME: read EEPROM
// Get MAC address. FIXME: read EEPROM
for
(
i
=
0
;
i
<
MAC_ADDR_LEN
;
i
++
)
for
(
i
=
0
;
i
<
MAC_ADDR_LEN
;
i
++
)
dev
->
dev_addr
[
i
]
=
RTL_R8
(
MAC0
+
i
);
dev
->
dev_addr
[
i
]
=
RTL_R8
(
MAC0
+
i
);
...
@@ -836,9 +1112,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -836,9 +1112,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev
->
watchdog_timeo
=
RTL8169_TX_TIMEOUT
;
dev
->
watchdog_timeo
=
RTL8169_TX_TIMEOUT
;
dev
->
irq
=
pdev
->
irq
;
dev
->
irq
=
pdev
->
irq
;
dev
->
base_addr
=
(
unsigned
long
)
ioaddr
;
dev
->
base_addr
=
(
unsigned
long
)
ioaddr
;
// dev->do_ioctl = mii_ioctl;
#ifdef CONFIG_R8169_NAPI
dev
->
poll
=
rtl8169_poll
;
tp
=
dev
->
priv
;
// private data //
dev
->
weight
=
R8169_NAPI_WEIGHT
;
printk
(
KERN_INFO
PFX
"NAPI enabled
\n
"
);
#endif
tp
->
intr_mask
=
0xffff
;
tp
->
pci_dev
=
pdev
;
tp
->
pci_dev
=
pdev
;
tp
->
mmio_addr
=
ioaddr
;
tp
->
mmio_addr
=
ioaddr
;
...
@@ -885,95 +1164,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -885,95 +1164,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
mdio_write
(
ioaddr
,
0x0b
,
0x0000
);
//w 0x0b 15 0 0
mdio_write
(
ioaddr
,
0x0b
,
0x0000
);
//w 0x0b 15 0 0
}
}
// if TBI is not endbled
rtl8169_link_option
(
board_idx
,
&
autoneg
,
&
speed
,
&
duplex
);
if
(
!
(
RTL_R8
(
PHYstatus
)
&
TBI_Enable
))
{
int
val
=
mdio_read
(
ioaddr
,
PHY_AUTO_NEGO_REG
);
option
=
(
board_idx
>=
MAX_UNITS
)
?
0
:
media
[
board_idx
];
// Force RTL8169 in 10/100/1000 Full/Half mode.
if
(
option
>
0
)
{
printk
(
KERN_INFO
"%s: Force-mode Enabled.
\n
"
,
dev
->
name
);
Cap10_100
=
0
,
Cap1000
=
0
;
switch
(
option
)
{
case
_10_Half
:
Cap10_100
=
PHY_Cap_10_Half_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_10_Full
:
Cap10_100
=
PHY_Cap_10_Full_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Half
:
Cap10_100
=
PHY_Cap_100_Half_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Full
:
Cap10_100
=
PHY_Cap_100_Full_Or_Less
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_1000_Full
:
Cap10_100
=
PHY_Cap_100_Full_Or_Less
;
Cap1000
=
PHY_Cap_1000_Full
;
break
;
default:
break
;
}
mdio_write
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
Cap10_100
|
(
val
&
0x1F
));
//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
mdio_write
(
ioaddr
,
PHY_1000_CTRL_REG
,
Cap1000
);
}
else
{
printk
(
KERN_INFO
"%s: Auto-negotiation Enabled.
\n
"
,
dev
->
name
);
// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
mdio_write
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
PHY_Cap_100_Full_Or_Less
|
(
val
&
0x1f
));
// enable 1000 Full Mode
rtl8169_set_speed
(
dev
,
autoneg
,
speed
,
duplex
);
mdio_write
(
ioaddr
,
PHY_1000_CTRL_REG
,
PHY_Cap_1000_Full
);
if
(
RTL_R8
(
PHYstatus
)
&
TBI_Enable
)
printk
(
KERN_INFO
PFX
"%s: TBI auto-negotiating
\n
"
,
dev
->
name
);
}
// Enable auto-negotiation and restart auto-nigotiation
mdio_write
(
ioaddr
,
PHY_CTRL_REG
,
PHY_Enable_Auto_Nego
|
PHY_Restart_Auto_Nego
);
udelay
(
100
);
// wait for auto-negotiation process
for
(
i
=
10000
;
i
>
0
;
i
--
)
{
//check if auto-negotiation complete
if
(
mdio_read
(
ioaddr
,
PHY_STAT_REG
)
&
PHY_Auto_Neco_Comp
)
{
udelay
(
100
);
option
=
RTL_R8
(
PHYstatus
);
if
(
option
&
_1000bpsF
)
{
printk
(
KERN_INFO
"%s: 1000Mbps Full-duplex operation.
\n
"
,
dev
->
name
);
}
else
{
printk
(
KERN_INFO
"%s: %sMbps %s-duplex operation.
\n
"
,
dev
->
name
,
(
option
&
_100bps
)
?
"100"
:
"10"
,
(
option
&
FullDup
)
?
"Full"
:
"Half"
);
}
break
;
}
else
{
udelay
(
100
);
}
}
// end for-loop to wait for auto-negotiation process
}
else
{
udelay
(
100
);
printk
(
KERN_INFO
"%s: 1000Mbps Full-duplex operation, TBI Link %s!
\n
"
,
dev
->
name
,
(
RTL_R32
(
TBICSR
)
&
TBILinkOK
)
?
"OK"
:
"Failed"
);
}
return
0
;
return
0
;
}
}
...
@@ -982,7 +1178,7 @@ static void __devexit
...
@@ -982,7 +1178,7 @@ static void __devexit
rtl8169_remove_one
(
struct
pci_dev
*
pdev
)
rtl8169_remove_one
(
struct
pci_dev
*
pdev
)
{
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
assert
(
dev
!=
NULL
);
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
tp
!=
NULL
);
...
@@ -1001,7 +1197,7 @@ rtl8169_remove_one(struct pci_dev *pdev)
...
@@ -1001,7 +1197,7 @@ rtl8169_remove_one(struct pci_dev *pdev)
static
int
rtl8169_suspend
(
struct
pci_dev
*
pdev
,
u32
state
)
static
int
rtl8169_suspend
(
struct
pci_dev
*
pdev
,
u32
state
)
{
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -1042,7 +1238,7 @@ static int rtl8169_resume(struct pci_dev *pdev)
...
@@ -1042,7 +1238,7 @@ static int rtl8169_resume(struct pci_dev *pdev)
static
int
static
int
rtl8169_open
(
struct
net_device
*
dev
)
rtl8169_open
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
int
retval
;
int
retval
;
...
@@ -1074,6 +1270,8 @@ rtl8169_open(struct net_device *dev)
...
@@ -1074,6 +1270,8 @@ rtl8169_open(struct net_device *dev)
rtl8169_hw_start
(
dev
);
rtl8169_hw_start
(
dev
);
rtl8169_request_timer
(
dev
);
rtl8169_request_timer
(
dev
);
rtl8169_check_link_status
(
dev
,
tp
,
tp
->
mmio_addr
);
out:
out:
return
retval
;
return
retval
;
...
@@ -1091,7 +1289,7 @@ rtl8169_open(struct net_device *dev)
...
@@ -1091,7 +1289,7 @@ rtl8169_open(struct net_device *dev)
static
void
static
void
rtl8169_hw_start
(
struct
net_device
*
dev
)
rtl8169_hw_start
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
u32
i
;
u32
i
;
...
@@ -1102,8 +1300,7 @@ rtl8169_hw_start(struct net_device *dev)
...
@@ -1102,8 +1300,7 @@ rtl8169_hw_start(struct net_device *dev)
for
(
i
=
1000
;
i
>
0
;
i
--
)
{
for
(
i
=
1000
;
i
>
0
;
i
--
)
{
if
((
RTL_R8
(
ChipCmd
)
&
CmdReset
)
==
0
)
if
((
RTL_R8
(
ChipCmd
)
&
CmdReset
)
==
0
)
break
;
break
;
else
udelay
(
10
);
udelay
(
10
);
}
}
RTL_W8
(
Cfg9346
,
Cfg9346_Unlock
);
RTL_W8
(
Cfg9346
,
Cfg9346_Unlock
);
...
@@ -1114,8 +1311,8 @@ rtl8169_hw_start(struct net_device *dev)
...
@@ -1114,8 +1311,8 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W16
(
RxMaxSize
,
RxPacketMaxSize
);
RTL_W16
(
RxMaxSize
,
RxPacketMaxSize
);
// Set Rx Config register
// Set Rx Config register
i
=
rtl8169_rx_config
|
(
RTL_R32
(
RxConfig
)
&
rtl_chip_info
[
tp
->
chipset
].
i
=
rtl8169_rx_config
|
RxConfigMask
);
(
RTL_R32
(
RxConfig
)
&
rtl_chip_info
[
tp
->
chipset
].
RxConfigMask
);
RTL_W32
(
RxConfig
,
i
);
RTL_W32
(
RxConfig
,
i
);
/* Set DMA burst size and Interframe Gap Time */
/* Set DMA burst size and Interframe Gap Time */
...
@@ -1126,7 +1323,8 @@ rtl8169_hw_start(struct net_device *dev)
...
@@ -1126,7 +1323,8 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
if
(
tp
->
mac_version
==
RTL_GIGA_MAC_VER_D
)
{
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
"
);
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
;
tp
->
cp_cmd
|=
(
1
<<
14
)
|
PCIMulRW
;
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
RTL_W16
(
CPlusCmd
,
tp
->
cp_cmd
);
}
}
...
@@ -1151,7 +1349,6 @@ rtl8169_hw_start(struct net_device *dev)
...
@@ -1151,7 +1349,6 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W16
(
IntrMask
,
rtl8169_intr_mask
);
RTL_W16
(
IntrMask
,
rtl8169_intr_mask
);
netif_start_queue
(
dev
);
netif_start_queue
(
dev
);
}
}
static
inline
void
rtl8169_make_unusable_by_asic
(
struct
RxDesc
*
desc
)
static
inline
void
rtl8169_make_unusable_by_asic
(
struct
RxDesc
*
desc
)
...
@@ -1248,7 +1445,7 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
...
@@ -1248,7 +1445,7 @@ static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
static
int
rtl8169_init_ring
(
struct
net_device
*
dev
)
static
int
rtl8169_init_ring
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
tp
->
cur_rx
=
tp
->
dirty_rx
=
0
;
tp
->
cur_rx
=
tp
->
dirty_rx
=
0
;
tp
->
cur_tx
=
tp
->
dirty_tx
=
0
;
tp
->
cur_tx
=
tp
->
dirty_tx
=
0
;
...
@@ -1302,10 +1499,11 @@ rtl8169_tx_clear(struct rtl8169_private *tp)
...
@@ -1302,10 +1499,11 @@ rtl8169_tx_clear(struct rtl8169_private *tp)
static
void
static
void
rtl8169_tx_timeout
(
struct
net_device
*
dev
)
rtl8169_tx_timeout
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
u8
tmp8
;
u8
tmp8
;
printk
(
KERN_INFO
"%s: TX Timeout
\n
"
,
dev
->
name
);
/* disable Tx, if not already */
/* disable Tx, if not already */
tmp8
=
RTL_R8
(
ChipCmd
);
tmp8
=
RTL_R8
(
ChipCmd
);
if
(
tmp8
&
CmdTxEnb
)
if
(
tmp8
&
CmdTxEnb
)
...
@@ -1328,9 +1526,9 @@ rtl8169_tx_timeout(struct net_device *dev)
...
@@ -1328,9 +1526,9 @@ rtl8169_tx_timeout(struct net_device *dev)
static
int
static
int
rtl8169_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
rtl8169_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
entry
=
tp
->
cur_tx
%
NUM_TX_DESC
;
unsigned
int
entry
=
tp
->
cur_tx
%
NUM_TX_DESC
;
u32
len
=
skb
->
len
;
u32
len
=
skb
->
len
;
if
(
unlikely
(
skb
->
len
<
ETH_ZLEN
))
{
if
(
unlikely
(
skb
->
len
<
ETH_ZLEN
))
{
...
@@ -1340,10 +1538,9 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1340,10 +1538,9 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
len
=
ETH_ZLEN
;
len
=
ETH_ZLEN
;
}
}
spin_lock_irq
(
&
tp
->
lock
);
if
(
!
(
le32_to_cpu
(
tp
->
TxDescArray
[
entry
].
status
)
&
OWNbit
))
{
if
(
!
(
le32_to_cpu
(
tp
->
TxDescArray
[
entry
].
status
)
&
OWNbit
))
{
dma_addr_t
mapping
;
dma_addr_t
mapping
;
u32
status
;
mapping
=
pci_map_single
(
tp
->
pci_dev
,
skb
->
data
,
len
,
mapping
=
pci_map_single
(
tp
->
pci_dev
,
skb
->
data
,
len
,
PCI_DMA_TODEVICE
);
PCI_DMA_TODEVICE
);
...
@@ -1351,24 +1548,30 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1351,24 +1548,30 @@ rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
tp
->
Tx_skbuff
[
entry
]
=
skb
;
tp
->
Tx_skbuff
[
entry
]
=
skb
;
tp
->
TxDescArray
[
entry
].
addr
=
cpu_to_le64
(
mapping
);
tp
->
TxDescArray
[
entry
].
addr
=
cpu_to_le64
(
mapping
);
tp
->
TxDescArray
[
entry
].
status
=
cpu_to_le32
(
OWNbit
|
FSbit
|
/* anti gcc 2.95.3 bugware */
LSbit
|
len
|
(
EORbit
*
!
((
entry
+
1
)
%
NUM_TX_DESC
)));
status
=
OWNbit
|
FSbit
|
LSbit
|
len
|
(
EORbit
*
!
((
entry
+
1
)
%
NUM_TX_DESC
));
tp
->
TxDescArray
[
entry
].
status
=
cpu_to_le32
(
status
);
RTL_W8
(
TxPoll
,
0x40
);
//set polling bit
RTL_W8
(
TxPoll
,
0x40
);
//set polling bit
dev
->
trans_start
=
jiffies
;
dev
->
trans_start
=
jiffies
;
tp
->
cur_tx
++
;
tp
->
cur_tx
++
;
smp_wmb
();
}
else
}
else
goto
err_drop
;
goto
err_drop
;
if
((
tp
->
cur_tx
-
NUM_TX_DESC
)
==
tp
->
dirty_tx
)
{
if
((
tp
->
cur_tx
-
NUM_TX_DESC
)
==
tp
->
dirty_tx
)
{
u32
dirty
=
tp
->
dirty_tx
;
netif_stop_queue
(
dev
);
netif_stop_queue
(
dev
);
smp_rmb
();
if
(
dirty
!=
tp
->
dirty_tx
)
netif_wake_queue
(
dev
);
}
}
out:
spin_unlock_irq
(
&
tp
->
lock
);
out:
return
0
;
return
0
;
err_drop:
err_drop:
...
@@ -1382,17 +1585,18 @@ static void
...
@@ -1382,17 +1585,18 @@ static void
rtl8169_tx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
rtl8169_tx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
void
*
ioaddr
)
{
{
unsigned
long
dirty_tx
,
tx_left
;
unsigned
int
dirty_tx
,
tx_left
;
assert
(
dev
!=
NULL
);
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
dirty_tx
=
tp
->
dirty_tx
;
dirty_tx
=
tp
->
dirty_tx
;
smp_rmb
();
tx_left
=
tp
->
cur_tx
-
dirty_tx
;
tx_left
=
tp
->
cur_tx
-
dirty_tx
;
while
(
tx_left
>
0
)
{
while
(
tx_left
>
0
)
{
int
entry
=
dirty_tx
%
NUM_TX_DESC
;
unsigned
int
entry
=
dirty_tx
%
NUM_TX_DESC
;
struct
sk_buff
*
skb
=
tp
->
Tx_skbuff
[
entry
];
struct
sk_buff
*
skb
=
tp
->
Tx_skbuff
[
entry
];
u32
status
;
u32
status
;
...
@@ -1415,6 +1619,7 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
...
@@ -1415,6 +1619,7 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
if
(
tp
->
dirty_tx
!=
dirty_tx
)
{
if
(
tp
->
dirty_tx
!=
dirty_tx
)
{
tp
->
dirty_tx
=
dirty_tx
;
tp
->
dirty_tx
=
dirty_tx
;
smp_wmb
();
if
(
netif_queue_stopped
(
dev
))
if
(
netif_queue_stopped
(
dev
))
netif_wake_queue
(
dev
);
netif_wake_queue
(
dev
);
}
}
...
@@ -1442,11 +1647,11 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
...
@@ -1442,11 +1647,11 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
return
ret
;
return
ret
;
}
}
static
void
static
int
rtl8169_rx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
rtl8169_rx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
void
*
ioaddr
)
{
{
unsigned
long
cur_rx
,
rx_lef
t
;
unsigned
int
cur_rx
,
rx_left
,
coun
t
;
int
delta
;
int
delta
;
assert
(
dev
!=
NULL
);
assert
(
dev
!=
NULL
);
...
@@ -1455,9 +1660,10 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
...
@@ -1455,9 +1660,10 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
cur_rx
=
tp
->
cur_rx
;
cur_rx
=
tp
->
cur_rx
;
rx_left
=
NUM_RX_DESC
+
tp
->
dirty_rx
-
cur_rx
;
rx_left
=
NUM_RX_DESC
+
tp
->
dirty_rx
-
cur_rx
;
rx_left
=
rtl8169_rx_quota
(
rx_left
,
(
u32
)
dev
->
quota
);
while
(
rx_left
>
0
)
{
while
(
rx_left
>
0
)
{
int
entry
=
cur_rx
%
NUM_RX_DESC
;
unsigned
int
entry
=
cur_rx
%
NUM_RX_DESC
;
u32
status
;
u32
status
;
rmb
();
rmb
();
...
@@ -1494,7 +1700,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
...
@@ -1494,7 +1700,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
skb_put
(
skb
,
pkt_size
);
skb_put
(
skb
,
pkt_size
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
netif_rx
(
skb
);
rtl8169_rx_skb
(
skb
);
dev
->
last_rx
=
jiffies
;
dev
->
last_rx
=
jiffies
;
tp
->
stats
.
rx_bytes
+=
pkt_size
;
tp
->
stats
.
rx_bytes
+=
pkt_size
;
...
@@ -1505,13 +1711,15 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
...
@@ -1505,13 +1711,15 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
rx_left
--
;
rx_left
--
;
}
}
count
=
cur_rx
-
tp
->
cur_rx
;
tp
->
cur_rx
=
cur_rx
;
tp
->
cur_rx
=
cur_rx
;
delta
=
rtl8169_rx_fill
(
tp
,
dev
,
tp
->
dirty_rx
,
tp
->
cur_rx
);
delta
=
rtl8169_rx_fill
(
tp
,
dev
,
tp
->
dirty_rx
,
tp
->
cur_rx
);
if
(
delta
>
0
)
if
(
delta
<
0
)
{
tp
->
dirty_rx
+=
delta
;
else
if
(
delta
<
0
)
printk
(
KERN_INFO
"%s: no Rx buffer allocated
\n
"
,
dev
->
name
);
printk
(
KERN_INFO
"%s: no Rx buffer allocated
\n
"
,
dev
->
name
);
delta
=
0
;
}
tp
->
dirty_rx
+=
delta
;
/*
/*
* FIXME: until there is periodic timer to try and refill the ring,
* FIXME: until there is periodic timer to try and refill the ring,
...
@@ -1522,6 +1730,8 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
...
@@ -1522,6 +1730,8 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
*/
*/
if
(
tp
->
dirty_rx
+
NUM_RX_DESC
==
tp
->
cur_rx
)
if
(
tp
->
dirty_rx
+
NUM_RX_DESC
==
tp
->
cur_rx
)
printk
(
KERN_EMERG
"%s: Rx buffers exhausted
\n
"
,
dev
->
name
);
printk
(
KERN_EMERG
"%s: Rx buffers exhausted
\n
"
,
dev
->
name
);
return
count
;
}
}
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
...
@@ -1529,7 +1739,7 @@ static irqreturn_t
...
@@ -1529,7 +1739,7 @@ static irqreturn_t
rtl8169_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
rtl8169_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
int
boguscnt
=
max_interrupt_work
;
int
boguscnt
=
max_interrupt_work
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
status
=
0
;
int
status
=
0
;
...
@@ -1543,26 +1753,37 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
...
@@ -1543,26 +1753,37 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
break
;
break
;
handled
=
1
;
handled
=
1
;
/*
if (status & RxUnderrun)
status
&=
tp
->
intr_mask
;
link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
*/
RTL_W16
(
IntrStatus
,
RTL_W16
(
IntrStatus
,
(
status
&
RxFIFOOver
)
?
(
status
|
RxOverflow
)
:
status
);
(
status
&
RxFIFOOver
)
?
(
status
|
RxOverflow
)
:
status
);
if
(
!
(
status
&
rtl8169_intr_mask
))
if
(
!
(
status
&
rtl8169_intr_mask
))
break
;
break
;
if
(
status
&
LinkChg
)
rtl8169_check_link_status
(
dev
,
tp
,
ioaddr
);
#ifdef CONFIG_R8169_NAPI
RTL_W16
(
IntrMask
,
rtl8169_intr_mask
&
~
rtl8169_napi_event
);
tp
->
intr_mask
=
~
rtl8169_napi_event
;
if
(
likely
(
netif_rx_schedule_prep
(
dev
)))
__netif_rx_schedule
(
dev
);
else
{
printk
(
KERN_INFO
"%s: interrupt %x taken in poll
\n
"
,
dev
->
name
,
status
);
}
break
;
#else
// Rx interrupt
// Rx interrupt
if
(
status
&
(
RxOK
|
Rx
Underrun
|
Rx
Overflow
|
RxFIFOOver
))
{
if
(
status
&
(
RxOK
|
RxOverflow
|
RxFIFOOver
))
{
rtl8169_rx_interrupt
(
dev
,
tp
,
ioaddr
);
rtl8169_rx_interrupt
(
dev
,
tp
,
ioaddr
);
}
}
// Tx interrupt
// Tx interrupt
if
(
status
&
(
TxOK
|
TxErr
))
{
if
(
status
&
(
TxOK
|
TxErr
))
spin_lock
(
&
tp
->
lock
);
rtl8169_tx_interrupt
(
dev
,
tp
,
ioaddr
);
rtl8169_tx_interrupt
(
dev
,
tp
,
ioaddr
);
spin_unlock
(
&
tp
->
lock
);
#endif
}
boguscnt
--
;
boguscnt
--
;
}
while
(
boguscnt
>
0
);
}
while
(
boguscnt
>
0
);
...
@@ -1576,10 +1797,40 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
...
@@ -1576,10 +1797,40 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
return
IRQ_RETVAL
(
handled
);
return
IRQ_RETVAL
(
handled
);
}
}
#ifdef CONFIG_R8169_NAPI
static
int
rtl8169_poll
(
struct
net_device
*
dev
,
int
*
budget
)
{
unsigned
int
work_done
,
work_to_do
=
min
(
*
budget
,
dev
->
quota
);
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
);
void
*
ioaddr
=
tp
->
mmio_addr
;
work_done
=
rtl8169_rx_interrupt
(
dev
,
tp
,
ioaddr
);
rtl8169_tx_interrupt
(
dev
,
tp
,
ioaddr
);
*
budget
-=
work_done
;
dev
->
quota
-=
work_done
;
if
((
work_done
<
work_to_do
)
||
!
netif_running
(
dev
))
{
netif_rx_complete
(
dev
);
tp
->
intr_mask
=
0xffff
;
/*
* 20040426: the barrier is not strictly required but the
* behavior of the irq handler could be less predictable
* without it. Btw, the lack of flush for the posted pci
* write is safe - FR
*/
smp_wmb
();
RTL_W16
(
IntrMask
,
rtl8169_intr_mask
);
}
return
(
work_done
>=
work_to_do
);
}
#endif
static
int
static
int
rtl8169_close
(
struct
net_device
*
dev
)
rtl8169_close
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
struct
pci_dev
*
pdev
=
tp
->
pci_dev
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
...
@@ -1621,7 +1872,7 @@ rtl8169_close(struct net_device *dev)
...
@@ -1621,7 +1872,7 @@ rtl8169_close(struct net_device *dev)
static
void
static
void
rtl8169_set_rx_mode
(
struct
net_device
*
dev
)
rtl8169_set_rx_mode
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
unsigned
long
flags
;
u32
mc_filter
[
2
];
/* Multicast hash filter */
u32
mc_filter
[
2
];
/* Multicast hash filter */
...
@@ -1655,10 +1906,8 @@ rtl8169_set_rx_mode(struct net_device *dev)
...
@@ -1655,10 +1906,8 @@ rtl8169_set_rx_mode(struct net_device *dev)
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
tmp
=
tmp
=
rtl8169_rx_config
|
rx_mode
|
rtl8169_rx_config
|
rx_mode
|
(
RTL_R32
(
RxConfig
)
&
(
RTL_R32
(
RxConfig
)
&
rtl_chip_info
[
tp
->
chipset
].
RxConfigMask
);
rtl_chip_info
[
tp
->
chipset
].
RxConfigMask
);
RTL_W32
(
RxConfig
,
tmp
);
RTL_W32
(
RxConfig
,
tmp
);
RTL_W32
(
MAR0
+
0
,
mc_filter
[
0
]);
RTL_W32
(
MAR0
+
0
,
mc_filter
[
0
]);
...
@@ -1675,7 +1924,7 @@ rtl8169_set_rx_mode(struct net_device *dev)
...
@@ -1675,7 +1924,7 @@ rtl8169_set_rx_mode(struct net_device *dev)
*/
*/
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
dev
)
static
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
dev
)
{
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
struct
rtl8169_private
*
tp
=
netdev_priv
(
dev
)
;
void
*
ioaddr
=
tp
->
mmio_addr
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
unsigned
long
flags
;
...
...
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