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
ed90d9a9
Commit
ed90d9a9
authored
Nov 30, 2002
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[netdrvr] add "r8169", new driver for Realtek 8169 gigabit ethernet
parent
648532a4
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1235 additions
and
0 deletions
+1235
-0
drivers/net/Kconfig
drivers/net/Kconfig
+11
-0
drivers/net/Makefile
drivers/net/Makefile
+1
-0
drivers/net/Makefile.lib
drivers/net/Makefile.lib
+1
-0
drivers/net/r8169.c
drivers/net/r8169.c
+1222
-0
No files found.
drivers/net/Kconfig
View file @
ed90d9a9
...
...
@@ -1719,6 +1719,17 @@ config YELLOWFIN
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called yellowfin.o.
config R8169
tristate "Realtek 8169 gigabit ethernet support"
depends on PCI
---help---
Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called r8169.o.
config SK98LIN
tristate "SysKonnect SK-98xx support"
depends on PCI
...
...
drivers/net/Makefile
View file @
ed90d9a9
...
...
@@ -182,6 +182,7 @@ obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0)
+=
mac89x0.o
obj-$(CONFIG_TUN)
+=
tun.o
obj-$(CONFIG_DL2K)
+=
dl2k.o
obj-$(CONFIG_R8169)
+=
r8169.o
obj-$(CONFIG_ARCH_ACORN)
+=
../acorn/net/
obj-$(CONFIG_NET_FC)
+=
fc
/
...
...
drivers/net/Makefile.lib
View file @
ed90d9a9
...
...
@@ -36,6 +36,7 @@ obj-$(CONFIG_TULIP) += crc32.o
obj-$(CONFIG_VIA_RHINE)
+=
crc32.o
obj-$(CONFIG_YELLOWFIN)
+=
crc32.o
obj-$(CONFIG_WINBOND_840)
+=
crc32.o
obj-$(CONFIG_R8169)
+=
crc32.o
# These rely on drivers/net/7990.o which requires crc32.o
...
...
drivers/net/r8169.c
0 → 100644
View file @
ed90d9a9
/*
=========================================================================
r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
--------------------------------------------------------------------
History:
Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
May 20 2002 - Add link status force-mode and TBI mode support.
=========================================================================
1. The media can be forced in 5 modes.
Command: 'insmod r8169 media = SET_MEDIA'
Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
SET_MEDIA can be:
_10_Half = 0x01
_10_Full = 0x02
_100_Half = 0x04
_100_Full = 0x08
_1000_Full = 0x10
2. Support TBI mode.
//=========================================================================
RTL8169_VERSION "1.1" <2002/10/4>
The bit4:0 of MII register 4 is called "selector field", and have to be
00001b to indicate support of IEEE std 802.3 during NWay process of
exchanging Link Code Word (FLP).
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#define RTL8169_VERSION "1.1"
#define MODULENAME "r8169"
#define RTL8169_DRIVER_NAME MODULENAME " Gigabit Ethernet driver " RTL8169_VERSION
#define PFX MODULENAME ": "
#ifdef RTL8169_DEBUG
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#else
#define assert(expr) do {} while (0)
#endif // end of #ifdef RTL8169_DEBUG
/* media options */
#define MAX_UNITS 8
static
int
media
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static
int
max_interrupt_work
=
20
;
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
static
int
multicast_filter_limit
=
32
;
/* MAC address length*/
#define MAC_ADDR_LEN 6
/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
#define MAX_ETH_FRAME_SIZE 1536
#define TX_FIFO_THRESH 256
/* In bytes */
#define RX_FIFO_THRESH 7
/* 7 means NO threshold, Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 6
/* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST 6
/* Maximum PCI burst, '6' is 1024 */
#define EarlyTxThld 0x3F
/* 0x3F means NO early transmit */
#define RxPacketMaxSize 0x0800
/* Maximum size supported is 16K-1 */
#define InterFrameGap 0x03
/* 3 means InterFrameGap = the shortest one */
#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 RTL_MIN_IO_SIZE 0x80
#define TX_TIMEOUT (6*HZ)
/* write/read MMIO register */
#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
#define RTL_R8(reg) readb (ioaddr + (reg))
#define RTL_R16(reg) readw (ioaddr + (reg))
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
static
struct
{
const
char
*
name
;
}
board_info
[]
__devinitdata
=
{
{
"RealTek RTL8169 Gigabit Ethernet"
},
};
static
struct
pci_device_id
rtl8169_pci_tbl
[]
__devinitdata
=
{
{
0x10ec
,
0x8169
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
{
0
,},
};
MODULE_DEVICE_TABLE
(
pci
,
rtl8169_pci_tbl
);
enum
RTL8169_registers
{
MAC0
=
0
,
/* Ethernet hardware address. */
MAR0
=
8
,
/* Multicast filter. */
TxDescStartAddr
=
0x20
,
TxHDescStartAddr
=
0x28
,
FLASH
=
0x30
,
ERSR
=
0x36
,
ChipCmd
=
0x37
,
TxPoll
=
0x38
,
IntrMask
=
0x3C
,
IntrStatus
=
0x3E
,
TxConfig
=
0x40
,
RxConfig
=
0x44
,
RxMissed
=
0x4C
,
Cfg9346
=
0x50
,
Config0
=
0x51
,
Config1
=
0x52
,
Config2
=
0x53
,
Config3
=
0x54
,
Config4
=
0x55
,
Config5
=
0x56
,
MultiIntr
=
0x5C
,
PHYAR
=
0x60
,
TBICSR
=
0x64
,
TBI_ANAR
=
0x68
,
TBI_LPAR
=
0x6A
,
PHYstatus
=
0x6C
,
RxMaxSize
=
0xDA
,
CPlusCmd
=
0xE0
,
RxDescStartAddr
=
0xE4
,
EarlyTxThres
=
0xEC
,
FuncEvent
=
0xF0
,
FuncEventMask
=
0xF4
,
FuncPresetState
=
0xF8
,
FuncForceEvent
=
0xFC
,
};
enum
RTL8169_register_content
{
/*InterruptStatusBits*/
SYSErr
=
0x8000
,
PCSTimeout
=
0x4000
,
SWInt
=
0x0100
,
TxDescUnavail
=
0x80
,
RxFIFOOver
=
0x40
,
RxUnderrun
=
0x20
,
RxOverflow
=
0x10
,
TxErr
=
0x08
,
TxOK
=
0x04
,
RxErr
=
0x02
,
RxOK
=
0x01
,
/*RxStatusDesc*/
RxRES
=
0x00200000
,
RxCRC
=
0x00080000
,
RxRUNT
=
0x00100000
,
RxRWT
=
0x00400000
,
/*ChipCmdBits*/
CmdReset
=
0x10
,
CmdRxEnb
=
0x08
,
CmdTxEnb
=
0x04
,
RxBufEmpty
=
0x01
,
/*Cfg9346Bits*/
Cfg9346_Lock
=
0x00
,
Cfg9346_Unlock
=
0xC0
,
/*rx_mode_bits*/
AcceptErr
=
0x20
,
AcceptRunt
=
0x10
,
AcceptBroadcast
=
0x08
,
AcceptMulticast
=
0x04
,
AcceptMyPhys
=
0x02
,
AcceptAllPhys
=
0x01
,
/*RxConfigBits*/
RxCfgFIFOShift
=
13
,
RxCfgDMAShift
=
8
,
/*TxConfigBits*/
TxInterFrameGapShift
=
24
,
TxDMAShift
=
8
,
/* DMA burst value (0-7) is shift this many bits */
/*rtl8169_PHYstatus*/
TBI_Enable
=
0x80
,
TxFlowCtrl
=
0x40
,
RxFlowCtrl
=
0x20
,
_1000bpsF
=
0x10
,
_100bps
=
0x08
,
_10bps
=
0x04
,
LinkStatus
=
0x02
,
FullDup
=
0x01
,
/*GIGABIT_PHY_registers*/
PHY_CTRL_REG
=
0
,
PHY_STAT_REG
=
1
,
PHY_AUTO_NEGO_REG
=
4
,
PHY_1000_CTRL_REG
=
9
,
/*GIGABIT_PHY_REG_BIT*/
PHY_Restart_Auto_Nego
=
0x0200
,
PHY_Enable_Auto_Nego
=
0x1000
,
//PHY_STAT_REG = 1;
PHY_Auto_Neco_Comp
=
0x0020
,
//PHY_AUTO_NEGO_REG = 4;
PHY_Cap_10_Half
=
0x0020
,
PHY_Cap_10_Full
=
0x0040
,
PHY_Cap_100_Half
=
0x0080
,
PHY_Cap_100_Full
=
0x0100
,
//PHY_1000_CTRL_REG = 9;
PHY_Cap_1000_Full
=
0x0200
,
PHY_Cap_Null
=
0x0
,
/*_MediaType*/
_10_Half
=
0x01
,
_10_Full
=
0x02
,
_100_Half
=
0x04
,
_100_Full
=
0x08
,
_1000_Full
=
0x10
,
/*_TBICSRBit*/
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
,
FSbit
=
0x20000000
,
LSbit
=
0x10000000
,
};
struct
TxDesc
{
u32
status
;
u32
vlan_tag
;
u32
buf_addr
;
u32
buf_Haddr
;
};
struct
RxDesc
{
u32
status
;
u32
vlan_tag
;
u32
buf_addr
;
u32
buf_Haddr
;
};
struct
rtl8169_private
{
void
*
mmio_addr
;
/* memory map physical address*/
struct
pci_dev
*
pci_dev
;
/* Index of PCI device */
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 */
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 */
struct
sk_buff
*
Tx_skbuff
[
NUM_TX_DESC
];
/* Index of Transmit data buffer */
};
MODULE_AUTHOR
(
"Realtek"
);
MODULE_DESCRIPTION
(
"RealTek RTL-8169 Gigabit Ethernet driver"
);
MODULE_PARM
(
media
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
static
int
rtl8169_open
(
struct
net_device
*
dev
);
static
int
rtl8169_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
void
rtl8169_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
void
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
inline
u32
ether_crc
(
int
length
,
unsigned
char
*
data
);
static
void
rtl8169_set_rx_mode
(
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
const
u16
rtl8169_intr_mask
=
SYSErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
static
const
unsigned
int
rtl8169_rx_config
=
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
)
;
//=================================================================
// PHYAR
// bit Symbol
// 31 Flag
// 30-21 reserved
// 20-16 5-bit GMII/MII register address
// 15-0 16-bit GMII/MII register data
//=================================================================
void
RTL8169_WRITE_GMII_REG
(
void
*
ioaddr
,
int
RegAddr
,
int
value
)
{
int
i
;
RTL_W32
(
PHYAR
,
0x80000000
|
(
RegAddr
&
0xFF
)
<<
16
|
value
);
udelay
(
1000
);
for
(
i
=
2000
;
i
>
0
;
i
--
){
// Check if the RTL8169 has completed writing to the specified MII register
if
(
!
(
RTL_R32
(
PHYAR
)
&
0x80000000
)
){
break
;
}
else
{
udelay
(
100
);
}
// end of if( ! (RTL_R32(PHYAR)&0x80000000) )
}
// end of for() loop
}
//=================================================================
int
RTL8169_READ_GMII_REG
(
void
*
ioaddr
,
int
RegAddr
)
{
int
i
,
value
=
-
1
;
RTL_W32
(
PHYAR
,
0x0
|
(
RegAddr
&
0xFF
)
<<
16
);
udelay
(
1000
);
for
(
i
=
2000
;
i
>
0
;
i
--
){
// Check if the RTL8169 has completed retrieving data from the specified MII register
if
(
RTL_R32
(
PHYAR
)
&
0x80000000
){
value
=
(
int
)(
RTL_R32
(
PHYAR
)
&
0xFFFF
);
break
;
}
else
{
udelay
(
100
);
}
// end of if( RTL_R32(PHYAR) & 0x80000000 )
}
// end of for() loop
return
value
;
}
//======================================================================================================
//======================================================================================================
static
int
__devinit
rtl8169_init_board
(
struct
pci_dev
*
pdev
,
struct
net_device
**
dev_out
,
void
**
ioaddr_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
;
assert
(
pdev
!=
NULL
);
assert
(
ioaddr_out
!=
NULL
);
*
ioaddr_out
=
NULL
;
*
dev_out
=
NULL
;
// dev zeroed in init_etherdev
dev
=
init_etherdev
(
NULL
,
sizeof
(
*
tp
));
if
(
dev
==
NULL
)
{
printk
(
KERN_ERR
PFX
"unable to alloc new ethernet
\n
"
);
return
-
ENOMEM
;
}
SET_MODULE_OWNER
(
dev
);
tp
=
dev
->
priv
;
// enable device (incl. PCI PM wakeup and hotplug setup)
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
goto
err_out
;
mmio_start
=
pci_resource_start
(
pdev
,
1
);
mmio_end
=
pci_resource_end
(
pdev
,
1
);
mmio_flags
=
pci_resource_flags
(
pdev
,
1
);
mmio_len
=
pci_resource_len
(
pdev
,
1
);
// make sure PCI base addr 1 is MMIO
if
(
!
(
mmio_flags
&
IORESOURCE_MEM
))
{
printk
(
KERN_ERR
PFX
"region #1 not an MMIO resource, aborting
\n
"
);
rc
=
-
ENODEV
;
goto
err_out
;
}
// check for weird/broken PCI region reporting
if
(
mmio_len
<
RTL_MIN_IO_SIZE
)
{
printk
(
KERN_ERR
PFX
"Invalid PCI region size(s), aborting
\n
"
);
rc
=
-
ENODEV
;
goto
err_out
;
}
rc
=
pci_request_regions
(
pdev
,
dev
->
name
);
if
(
rc
)
goto
err_out
;
// enable PCI bus-mastering
pci_set_master
(
pdev
);
// ioremap MMIO region
ioaddr
=
ioremap
(
mmio_start
,
mmio_len
);
if
(
ioaddr
==
NULL
)
{
printk
(
KERN_ERR
PFX
"cannot remap MMIO, aborting
\n
"
);
rc
=
-
EIO
;
goto
err_out_free_res
;
}
// Soft reset the chip.
RTL_W8
(
ChipCmd
,
CmdReset
);
// Check that the chip has finished the reset.
for
(
i
=
1000
;
i
>
0
;
i
--
)
if
(
(
RTL_R8
(
ChipCmd
)
&
CmdReset
)
==
0
)
break
;
else
udelay
(
10
);
// identify chip attached to board
tmp
=
RTL_R32
(
TxConfig
);
tmp
=
(
(
tmp
&
0x7c000000
)
+
(
(
tmp
&
0x00800000
)
<<
2
)
)
>>
24
;
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
"
,
pdev
->
slot_name
);
printk
(
KERN_DEBUG
PFX
"PCI device %s: TxConfig = 0x%lx
\n
"
,
pdev
->
slot_name
,
(
unsigned
long
)
RTL_R32
(
TxConfig
));
tp
->
chipset
=
0
;
match:
*
ioaddr_out
=
ioaddr
;
*
dev_out
=
dev
;
return
0
;
//err_out_iounmap:
assert
(
ioaddr
>
0
);
iounmap
(
ioaddr
);
err_out_free_res:
pci_release_regions
(
pdev
);
err_out:
unregister_netdev
(
dev
);
kfree
(
dev
);
return
rc
;
}
//======================================================================================================
static
int
__devinit
rtl8169_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
struct
net_device
*
dev
=
NULL
;
struct
rtl8169_private
*
tp
=
NULL
;
void
*
ioaddr
=
NULL
;
static
int
board_idx
=
-
1
;
static
int
printed_version
=
0
;
int
i
;
int
option
=
-
1
,
Cap10_100
=
0
,
Cap1000
=
0
;
assert
(
pdev
!=
NULL
);
assert
(
ent
!=
NULL
);
board_idx
++
;
if
(
!
printed_version
)
{
printk
(
KERN_INFO
RTL8169_DRIVER_NAME
" loaded
\n
"
);
printed_version
=
1
;
}
i
=
rtl8169_init_board
(
pdev
,
&
dev
,
&
ioaddr
);
if
(
i
<
0
)
{
return
i
;
}
tp
=
dev
->
priv
;
assert
(
ioaddr
!=
NULL
);
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
// Get MAC address //
for
(
i
=
0
;
i
<
MAC_ADDR_LEN
;
i
++
){
dev
->
dev_addr
[
i
]
=
RTL_R8
(
MAC0
+
i
);
}
dev
->
open
=
rtl8169_open
;
dev
->
hard_start_xmit
=
rtl8169_start_xmit
;
dev
->
get_stats
=
rtl8169_get_stats
;
dev
->
stop
=
rtl8169_close
;
dev
->
tx_timeout
=
rtl8169_tx_timeout
;
dev
->
set_multicast_list
=
rtl8169_set_rx_mode
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
dev
->
irq
=
pdev
->
irq
;
dev
->
base_addr
=
(
unsigned
long
)
ioaddr
;
// dev->do_ioctl = mii_ioctl;
tp
=
dev
->
priv
;
// private data //
tp
->
pci_dev
=
pdev
;
tp
->
mmio_addr
=
ioaddr
;
printk
(
KERN_DEBUG
"%s: Identified chip type is '%s'.
\n
"
,
dev
->
name
,
rtl_chip_info
[
tp
->
chipset
].
name
);
spin_lock_init
(
&
tp
->
lock
);
pdev
->
driver_data
=
dev
;
printk
(
KERN_INFO
"%s: %s at 0x%lx, "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d
\n
"
,
dev
->
name
,
board_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
);
// if TBI is not endbled
if
(
!
(
RTL_R8
(
PHYstatus
)
&
TBI_Enable
)
){
int
val
=
RTL8169_READ_GMII_REG
(
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
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_10_Full
:
Cap10_100
=
PHY_Cap_10_Full
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Half
:
Cap10_100
=
PHY_Cap_100_Half
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_100_Full
:
Cap10_100
=
PHY_Cap_100_Full
;
Cap1000
=
PHY_Cap_Null
;
break
;
case
_1000_Full
:
Cap10_100
=
PHY_Cap_Null
;
Cap1000
=
PHY_Cap_1000_Full
;
break
;
default:
break
;
}
RTL8169_WRITE_GMII_REG
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
Cap10_100
|
(
val
&
0x1F
)
);
//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
RTL8169_WRITE_GMII_REG
(
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
RTL8169_WRITE_GMII_REG
(
ioaddr
,
PHY_AUTO_NEGO_REG
,
PHY_Cap_10_Half
|
PHY_Cap_10_Full
|
PHY_Cap_100_Half
|
PHY_Cap_100_Full
|
(
val
&
0x1F
)
);
// enable 1000 Full Mode
RTL8169_WRITE_GMII_REG
(
ioaddr
,
PHY_1000_CTRL_REG
,
PHY_Cap_1000_Full
);
}
// end of if( option > 0 )
// Enable auto-negotiation and restart auto-nigotiation
RTL8169_WRITE_GMII_REG
(
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
(
RTL8169_READ_GMII_REG
(
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 of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 )
}
// end for-loop to wait for auto-negotiation process
}
// end of TBI is not enabled
else
{
udelay
(
100
);
printk
(
KERN_INFO
"%s: 1000Mbps Full-duplex operation, TBI Link %s!
\n
"
,
dev
->
name
,
(
RTL_R32
(
TBICSR
)
&
TBILinkOK
)
?
"OK"
:
"Failed"
);
}
// end of TBI is not enabled
return
0
;
}
//======================================================================================================
static
void
__devexit
rtl8169_remove_one
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pdev
->
driver_data
;
struct
rtl8169_private
*
tp
=
(
struct
rtl8169_private
*
)
(
dev
->
priv
);
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
unregister_netdev
(
dev
);
iounmap
(
tp
->
mmio_addr
);
pci_release_regions
(
pdev
);
// poison memory before freeing
memset
(
dev
,
0xBC
,
sizeof
(
struct
net_device
)
+
sizeof
(
struct
rtl8169_private
));
kfree
(
dev
);
pdev
->
driver_data
=
NULL
;
}
//======================================================================================================
static
int
rtl8169_open
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
int
retval
;
u8
diff
;
u32
TxPhyAddr
,
RxPhyAddr
;
retval
=
request_irq
(
dev
->
irq
,
rtl8169_interrupt
,
SA_SHIRQ
,
dev
->
name
,
dev
);
if
(
retval
)
{
return
retval
;
}
//////////////////////////////////////////////////////////////////////////////
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
"
);
}
//////////////////////////////////////////////////////////////////////////////
rtl8169_init_ring
(
dev
);
rtl8169_hw_start
(
dev
);
return
0
;
}
//end of rtl8169_open (struct net_device *dev)
//======================================================================================================
static
void
rtl8169_hw_start
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
u32
i
;
/* Soft reset the chip. */
RTL_W8
(
ChipCmd
,
CmdReset
);
/* Check that the chip has finished the reset. */
for
(
i
=
1000
;
i
>
0
;
i
--
){
if
((
RTL_R8
(
ChipCmd
)
&
CmdReset
)
==
0
)
break
;
else
udelay
(
10
);
}
RTL_W8
(
Cfg9346
,
Cfg9346_Unlock
);
RTL_W8
(
ChipCmd
,
CmdTxEnb
|
CmdRxEnb
);
RTL_W8
(
EarlyTxThres
,
EarlyTxThld
);
// For gigabit rtl8169
RTL_W16
(
RxMaxSize
,
RxPacketMaxSize
);
// Set Rx Config register
i
=
rtl8169_rx_config
|
(
RTL_R32
(
RxConfig
)
&
rtl_chip_info
[
tp
->
chipset
].
RxConfigMask
);
RTL_W32
(
RxConfig
,
i
);
/* Set DMA burst size and Interframe Gap Time */
RTL_W32
(
TxConfig
,
(
TX_DMA_BURST
<<
TxDMAShift
)
|
(
InterFrameGap
<<
TxInterFrameGapShift
)
);
tp
->
cur_rx
=
0
;
RTL_W32
(
TxDescStartAddr
,
virt_to_bus
(
tp
->
TxDescArray
));
RTL_W32
(
RxDescStartAddr
,
virt_to_bus
(
tp
->
RxDescArray
));
RTL_W8
(
Cfg9346
,
Cfg9346_Lock
);
udelay
(
10
);
RTL_W32
(
RxMissed
,
0
);
rtl8169_set_rx_mode
(
dev
);
/* no early-rx interrupts */
RTL_W16
(
MultiIntr
,
RTL_R16
(
MultiIntr
)
&
0xF000
);
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16
(
IntrMask
,
rtl8169_intr_mask
);
netif_start_queue
(
dev
);
}
//end of rtl8169_hw_start (struct net_device *dev)
//======================================================================================================
static
void
rtl8169_init_ring
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
int
i
;
tp
->
cur_rx
=
0
;
tp
->
cur_tx
=
0
;
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
;
tp
->
RxBufferRing
[
i
]
=
&
(
tp
->
RxBufferRings
[
i
*
RX_BUF_SIZE
]);
tp
->
RxDescArray
[
i
].
buf_addr
=
virt_to_bus
(
tp
->
RxBufferRing
[
i
]);
}
}
//======================================================================================================
static
void
rtl8169_tx_clear
(
struct
rtl8169_private
*
tp
)
{
int
i
;
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
;
tp
->
stats
.
tx_dropped
++
;
}
}
}
//======================================================================================================
static
void
rtl8169_tx_timeout
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
u8
tmp8
;
/* disable Tx, if not already */
tmp8
=
RTL_R8
(
ChipCmd
);
if
(
tmp8
&
CmdTxEnb
){
RTL_W8
(
ChipCmd
,
tmp8
&
~
CmdTxEnb
);
}
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16
(
IntrMask
,
0x0000
);
/* Stop a shared interrupt from scavenging while we are. */
spin_lock_irq
(
&
tp
->
lock
);
rtl8169_tx_clear
(
tp
);
spin_unlock_irq
(
&
tp
->
lock
);
/* ...and finally, reset everything */
rtl8169_hw_start
(
dev
);
netif_wake_queue
(
dev
);
}
//======================================================================================================
static
int
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
;
spin_lock_irq
(
&
tp
->
lock
);
if
(
(
tp
->
TxDescArray
[
entry
].
status
&
OWNbit
)
==
0
){
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
);
RTL_W8
(
TxPoll
,
0x40
);
//set polling bit
dev
->
trans_start
=
jiffies
;
tp
->
cur_tx
++
;
}
//end of if( (tp->TxDescArray[entry].status & 0x80000000)==0 )
spin_unlock_irq
(
&
tp
->
lock
);
if
(
(
tp
->
cur_tx
-
NUM_TX_DESC
)
==
tp
->
dirty_tx
){
netif_stop_queue
(
dev
);
}
return
0
;
}
//======================================================================================================
static
void
rtl8169_tx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8169_private
*
tp
,
void
*
ioaddr
)
{
unsigned
long
dirty_tx
,
tx_left
=
0
;
int
entry
=
tp
->
cur_tx
%
NUM_TX_DESC
;
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
dirty_tx
=
tp
->
dirty_tx
;
tx_left
=
tp
->
cur_tx
-
dirty_tx
;
while
(
tx_left
>
0
)
{
if
(
(
tp
->
TxDescArray
[
entry
].
status
&
OWNbit
)
==
0
){
dev_kfree_skb_irq
(
tp
->
Tx_skbuff
[
dirty_tx
%
NUM_TX_DESC
]
);
tp
->
Tx_skbuff
[
dirty_tx
%
NUM_TX_DESC
]
=
NULL
;
tp
->
stats
.
tx_packets
++
;
dirty_tx
++
;
tx_left
--
;
entry
++
;
}
}
if
(
tp
->
dirty_tx
!=
dirty_tx
)
{
tp
->
dirty_tx
=
dirty_tx
;
if
(
netif_queue_stopped
(
dev
))
netif_wake_queue
(
dev
);
}
}
//======================================================================================================
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
;
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
cur_rx
=
tp
->
cur_rx
;
while
(
(
tp
->
RxDescArray
[
cur_rx
].
status
&
OWNbit
)
==
0
)
{
if
(
tp
->
RxDescArray
[
cur_rx
].
status
&
RxRES
){
printk
(
KERN_INFO
"%s: Rx ERROR!!!
\n
"
,
dev
->
name
);
tp
->
stats
.
rx_errors
++
;
if
(
tp
->
RxDescArray
[
cur_rx
].
status
&
(
RxRWT
|
RxRUNT
)
)
tp
->
stats
.
rx_length_errors
++
;
if
(
tp
->
RxDescArray
[
cur_rx
].
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
++
;
}
// end of if (skb != NULL)
}
// end of if( tp->RxDescArray[cur_rx].status & RxRES )
cur_rx
=
(
cur_rx
+
1
)
%
NUM_RX_DESC
;
}
// end of while ( (tp->RxDescArray[cur_rx].status & 0x80000000)== 0)
tp
->
cur_rx
=
cur_rx
;
}
//======================================================================================================
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
static
void
rtl8169_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
rtl8169_private
*
tp
=
dev
->
priv
;
int
boguscnt
=
max_interrupt_work
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
status
=
0
;
do
{
status
=
RTL_R16
(
IntrStatus
);
/* h/w no longer present (hotplug?) or major error, bail */
if
(
status
==
0xFFFF
)
break
;
/*
if (status & RxUnderrun)
link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
*/
RTL_W16
(
IntrStatus
,
(
status
&
RxFIFOOver
)
?
(
status
|
RxOverflow
)
:
status
);
if
(
(
status
&
(
SYSErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
)
)
==
0
)
break
;
// Rx interrupt
if
(
status
&
(
RxOK
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
)){
rtl8169_rx_interrupt
(
dev
,
tp
,
ioaddr
);
}
// Tx interrupt
if
(
status
&
(
TxOK
|
TxErr
))
{
spin_lock
(
&
tp
->
lock
);
rtl8169_tx_interrupt
(
dev
,
tp
,
ioaddr
);
spin_unlock
(
&
tp
->
lock
);
}
boguscnt
--
;
}
while
(
boguscnt
>
0
);
if
(
boguscnt
<=
0
)
{
printk
(
KERN_WARNING
"%s: Too much work at interrupt!
\n
"
,
dev
->
name
);
/* Clear all interrupt sources. */
RTL_W16
(
IntrStatus
,
0xffff
);
}
}
//======================================================================================================
static
int
rtl8169_close
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
i
;
netif_stop_queue
(
dev
);
spin_lock_irq
(
&
tp
->
lock
);
/* Stop the chip's Tx and Rx DMA processes. */
RTL_W8
(
ChipCmd
,
0x00
);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16
(
IntrMask
,
0x0000
);
/* Update the error counts. */
tp
->
stats
.
rx_missed_errors
+=
RTL_R32
(
RxMissed
);
RTL_W32
(
RxMissed
,
0
);
spin_unlock_irq
(
&
tp
->
lock
);
synchronize_irq
();
free_irq
(
dev
->
irq
,
dev
);
rtl8169_tx_clear
(
tp
);
kfree
(
tp
->
TxDescArrays
);
kfree
(
tp
->
RxDescArrays
);
tp
->
TxDescArrays
=
NULL
;
tp
->
RxDescArrays
=
NULL
;
tp
->
TxDescArray
=
NULL
;
tp
->
RxDescArray
=
NULL
;
kfree
(
tp
->
RxBufferRings
);
for
(
i
=
0
;
i
<
NUM_RX_DESC
;
i
++
){
tp
->
RxBufferRing
[
i
]
=
NULL
;
}
return
0
;
}
//======================================================================================================
static
unsigned
const
ethernet_polynomial
=
0x04c11db7U
;
static
inline
u32
ether_crc
(
int
length
,
unsigned
char
*
data
)
{
int
crc
=
-
1
;
while
(
--
length
>=
0
)
{
unsigned
char
current_octet
=
*
data
++
;
int
bit
;
for
(
bit
=
0
;
bit
<
8
;
bit
++
,
current_octet
>>=
1
)
crc
=
(
crc
<<
1
)
^
((
crc
<
0
)
^
(
current_octet
&
1
)
?
ethernet_polynomial
:
0
);
}
return
crc
;
}
//======================================================================================================
static
void
rtl8169_set_rx_mode
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
unsigned
long
flags
;
u32
mc_filter
[
2
];
/* Multicast hash filter */
int
i
,
rx_mode
;
u32
tmp
=
0
;
if
(
dev
->
flags
&
IFF_PROMISC
)
{
/* Unconditionally log net taps. */
printk
(
KERN_NOTICE
"%s: Promiscuous mode enabled.
\n
"
,
dev
->
name
);
rx_mode
=
AcceptBroadcast
|
AcceptMulticast
|
AcceptMyPhys
|
AcceptAllPhys
;
mc_filter
[
1
]
=
mc_filter
[
0
]
=
0xffffffff
;
}
else
if
((
dev
->
mc_count
>
multicast_filter_limit
)
||
(
dev
->
flags
&
IFF_ALLMULTI
))
{
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode
=
AcceptBroadcast
|
AcceptMulticast
|
AcceptMyPhys
;
mc_filter
[
1
]
=
mc_filter
[
0
]
=
0xffffffff
;
}
else
{
struct
dev_mc_list
*
mclist
;
rx_mode
=
AcceptBroadcast
|
AcceptMulticast
|
AcceptMyPhys
;
mc_filter
[
1
]
=
mc_filter
[
0
]
=
0
;
for
(
i
=
0
,
mclist
=
dev
->
mc_list
;
mclist
&&
i
<
dev
->
mc_count
;
i
++
,
mclist
=
mclist
->
next
)
set_bit
(
ether_crc
(
ETH_ALEN
,
mclist
->
dmi_addr
)
>>
26
,
mc_filter
);
}
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
tmp
=
rtl8169_rx_config
|
rx_mode
|
(
RTL_R32
(
RxConfig
)
&
rtl_chip_info
[
tp
->
chipset
].
RxConfigMask
);
RTL_W32
(
RxConfig
,
tmp
);
RTL_W32
(
MAR0
+
0
,
mc_filter
[
0
]);
RTL_W32
(
MAR0
+
4
,
mc_filter
[
1
]);
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
}
//end of rtl8169_set_rx_mode (struct net_device *dev)
//================================================================================
struct
net_device_stats
*
rtl8169_get_stats
(
struct
net_device
*
dev
)
{
struct
rtl8169_private
*
tp
=
dev
->
priv
;
return
&
tp
->
stats
;
}
//================================================================================
static
struct
pci_driver
rtl8169_pci_driver
=
{
name:
MODULENAME
,
id_table:
rtl8169_pci_tbl
,
probe:
rtl8169_init_one
,
remove:
rtl8169_remove_one
,
suspend:
NULL
,
resume:
NULL
,
};
//======================================================================================================
static
int
__init
rtl8169_init_module
(
void
)
{
return
pci_module_init
(
&
rtl8169_pci_driver
);
// pci_register_driver (drv)
}
//======================================================================================================
static
void
__exit
rtl8169_cleanup_module
(
void
)
{
pci_unregister_driver
(
&
rtl8169_pci_driver
);
}
//======================================================================================================
module_init
(
rtl8169_init_module
);
module_exit
(
rtl8169_cleanup_module
);
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