2005-04-17 02:20:36 +04:00
/*
drivers / net / pci - skeleton . c
Maintained by Jeff Garzik < jgarzik @ pobox . com >
Original code came from 8139 too . c , which in turns was based
originally on Donald Becker ' s rtl8139 . c driver , versions 1.11
and older . This driver was originally based on rtl8139 . c
version 1.07 . Header of rtl8139 . c version 1.11 :
- - - - - < snip > - - - - -
2010-02-17 18:01:55 +03:00
Written 1997 - 2000 by Donald Becker .
2005-04-17 02:20:36 +04:00
This software may be used and distributed according to the
terms of the GNU General Public License ( GPL ) , incorporated
herein by reference . Drivers based on or derived from this
code fall under the GPL and must retain the authorship ,
copyright and license notice . This file is not a complete
program and may only be used when the entire operating
system is licensed under the GPL .
This driver is for boards based on the RTL8129 and RTL8139
PCI ethernet chips .
The author may be reached as becker @ scyld . com , or C / O Scyld
Computing Corporation 410 Severn Ave . , Suite 210 Annapolis
MD 21403
Support and updates available at
http : //www.scyld.com/network/rtl8139.html
Twister - tuning table provided by Kinston
< shangh @ realtek . com . tw > .
- - - - - < snip > - - - - -
This software may be used and distributed according to the terms
of the GNU General Public License , incorporated herein by reference .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Theory of Operation
I . Board Compatibility
This device driver is designed for the RealTek RTL8139 series , the RealTek
Fast Ethernet controllers for PCI and CardBus . This chip is used on many
low - end boards , sometimes with its markings changed .
II . Board - specific settings
PCI bus devices are configured by the system at boot time , so no jumpers
need to be set on the board . The system BIOS will assign the
PCI INTA signal to a ( preferably otherwise unused ) system IRQ line .
III . Driver operation
IIIa . Rx Ring buffers
The receive unit uses a single linear ring buffer rather than the more
common ( and more efficient ) descriptor - based architecture . Incoming frames
are sequentially stored into the Rx region , and the host copies them into
skbuffs .
Comment : While it is theoretically possible to process many frames in place ,
any delay in Rx processing would cause us to drop frames . More importantly ,
the Linux protocol stack is not designed to operate in this manner .
IIIb . Tx operation
The RTL8139 uses a fixed set of four Tx descriptors in register space .
In a stunningly bad design choice , Tx frames must be 32 bit aligned . Linux
aligns the IP header on word boundaries , and 14 byte ethernet header means
that almost all frames will need to be copied to an alignment buffer .
IVb . References
2010-10-18 13:03:14 +04:00
http : //www.realtek.com.tw/
2005-04-17 02:20:36 +04:00
http : //www.scyld.com/expert/NWay.html
IVc . Errata
*/
2010-02-17 18:01:55 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/delay.h>
# include <linux/ethtool.h>
# include <linux/mii.h>
# include <linux/crc32.h>
2010-02-17 18:01:55 +03:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
2006-09-12 01:39:18 +04:00
# define NETDRV_VERSION "1.0.1"
2005-04-17 02:20:36 +04:00
# define MODNAME "netdrv"
# define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
static char version [ ] __devinitdata =
2010-02-17 18:01:55 +03:00
KERN_INFO NETDRV_DRIVER_LOAD_MSG " \n "
" Support available from http://foo.com/bar/baz.html \n " ;
2005-04-17 02:20:36 +04:00
/* define to 1 to enable PIO instead of MMIO */
# undef USE_IO_OPS
/* define to 1 to enable copious debugging info */
# undef NETDRV_DEBUG
/* define to 1 to disable lightweight runtime debugging checks */
# undef NETDRV_NDEBUG
# ifdef NETDRV_DEBUG
/* note: prints function name for you */
2010-02-17 18:01:55 +03:00
# define DPRINTK(fmt, args...) \
printk ( KERN_DEBUG " %s: " fmt , __func__ , # # args )
2005-04-17 02:20:36 +04:00
# else
2010-02-17 18:01:55 +03:00
# define DPRINTK(fmt, args...) \
do { \
if ( 0 ) \
printk ( KERN_DEBUG fmt , # # args ) ; \
} while ( 0 )
2005-04-17 02:20:36 +04:00
# endif
# ifdef NETDRV_NDEBUG
2010-02-17 18:01:55 +03:00
# define assert(expr) do {} while (0)
2005-04-17 02:20:36 +04:00
# else
2010-02-17 18:01:55 +03:00
# define assert(expr) \
if ( ! ( expr ) ) { \
printk ( " Assertion failed! %s,%s,%s,line=%d \n " , \
# expr, __FILE__, __func__, __LINE__); \
}
2005-04-17 02:20:36 +04:00
# endif
/* A few user-configurable values. */
/* media options */
static int media [ ] = { - 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 ;
/* Size of the in-memory receive ring. */
# define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */
2010-02-17 18:01:55 +03:00
# define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
# define RX_BUF_PAD 16
2005-04-17 02:20:36 +04:00
# define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
2010-02-17 18:01:55 +03:00
# define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
2005-04-17 02:20:36 +04:00
/* Number of Tx descriptor registers. */
# define NUM_TX_DESC 4
/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
# define MAX_ETH_FRAME_SIZE 1536
/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
# define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
# define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts . */
2010-02-17 18:01:55 +03:00
# define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
/* The following settings are log_2(bytes)-4:
0 = = 16 bytes 1 = = 32 2 = = 64 3 = = 128 4 = = 256 5 = = 512 6 = = 1024 7 = = end of packet .
*/
2005-04-17 02:20:36 +04:00
# define RX_FIFO_THRESH 6 /* 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 */
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
2010-02-17 18:01:55 +03:00
# define TX_TIMEOUT (6 * HZ)
2005-04-17 02:20:36 +04:00
enum {
HAS_CHIP_XCVR = 0x020000 ,
HAS_LNK_CHNG = 0x040000 ,
} ;
# define NETDRV_MIN_IO_SIZE 0x80
# define RTL8139B_IO_SIZE 256
2010-02-17 18:01:55 +03:00
# define NETDRV_CAPS (HAS_CHIP_XCVR | HAS_LNK_CHNG)
2005-04-17 02:20:36 +04:00
typedef enum {
RTL8139 = 0 ,
NETDRV_CB ,
SMC1211TX ,
/*MPX5030,*/
DELTA8139 ,
ADDTRON8139 ,
} board_t ;
/* indexed by board_t, above */
static struct {
const char * name ;
} board_info [ ] __devinitdata = {
{ " RealTek RTL8139 Fast Ethernet " } ,
{ " RealTek RTL8139B PCI/CardBus " } ,
{ " SMC1211TX EZCard 10/100 (RealTek RTL8139) " } ,
/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/
{ " Delta Electronics 8139 10/100BaseTX " } ,
2011-03-31 05:57:33 +04:00
{ " Addtron Technology 8139 10/100BaseTX " } ,
2005-04-17 02:20:36 +04:00
} ;
2010-01-07 14:58:11 +03:00
static DEFINE_PCI_DEVICE_TABLE ( netdrv_pci_tbl ) = {
2005-04-17 02:20:36 +04:00
{ 0x10ec , 0x8139 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , RTL8139 } ,
{ 0x10ec , 0x8138 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , NETDRV_CB } ,
{ 0x1113 , 0x1211 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , SMC1211TX } ,
/* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
{ 0x1500 , 0x1360 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , DELTA8139 } ,
{ 0x4033 , 0x1360 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , ADDTRON8139 } ,
{ 0 , }
} ;
2010-02-17 18:01:55 +03:00
MODULE_DEVICE_TABLE ( pci , netdrv_pci_tbl ) ;
2005-04-17 02:20:36 +04:00
/* The rest of these values should never change. */
/* Symbolic offsets to registers. */
enum NETDRV_registers {
MAC0 = 0 , /* Ethernet hardware address. */
MAR0 = 8 , /* Multicast filter. */
TxStatus0 = 0x10 , /* Transmit status (Four 32bit registers). */
TxAddr0 = 0x20 , /* Tx descriptors (also four 32bit). */
RxBuf = 0x30 ,
RxEarlyCnt = 0x34 ,
RxEarlyStatus = 0x36 ,
ChipCmd = 0x37 ,
RxBufPtr = 0x38 ,
RxBufAddr = 0x3A ,
IntrMask = 0x3C ,
IntrStatus = 0x3E ,
TxConfig = 0x40 ,
ChipVersion = 0x43 ,
RxConfig = 0x44 ,
Timer = 0x48 , /* A general-purpose counter. */
RxMissed = 0x4C , /* 24 bits valid, write clears. */
Cfg9346 = 0x50 ,
Config0 = 0x51 ,
Config1 = 0x52 ,
FlashReg = 0x54 ,
MediaStatus = 0x58 ,
Config3 = 0x59 ,
Config4 = 0x5A , /* absent on RTL-8139A */
HltClk = 0x5B ,
MultiIntr = 0x5C ,
TxSummary = 0x60 ,
BasicModeCtrl = 0x62 ,
BasicModeStatus = 0x64 ,
NWayAdvert = 0x66 ,
NWayLPAR = 0x68 ,
NWayExpansion = 0x6A ,
/* Undocumented registers, but required for proper operation. */
FIFOTMS = 0x70 , /* FIFO Control and test. */
CSCR = 0x74 , /* Chip Status and Configuration Register. */
PARA78 = 0x78 ,
PARA7c = 0x7c , /* Magic transceiver parameter register. */
Config5 = 0xD8 , /* absent on RTL-8139A */
} ;
enum ClearBitMasks {
MultiIntrClear = 0xF000 ,
ChipCmdClear = 0xE2 ,
2010-02-17 18:01:55 +03:00
Config1Clear = ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ,
2005-04-17 02:20:36 +04:00
} ;
enum ChipCmdBits {
CmdReset = 0x10 ,
CmdRxEnb = 0x08 ,
CmdTxEnb = 0x04 ,
RxBufEmpty = 0x01 ,
} ;
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
PCIErr = 0x8000 ,
PCSTimeout = 0x4000 ,
RxFIFOOver = 0x40 ,
RxUnderrun = 0x20 ,
RxOverflow = 0x10 ,
TxErr = 0x08 ,
TxOK = 0x04 ,
RxErr = 0x02 ,
RxOK = 0x01 ,
} ;
enum TxStatusBits {
TxHostOwns = 0x2000 ,
TxUnderrun = 0x4000 ,
TxStatOK = 0x8000 ,
TxOutOfWindow = 0x20000000 ,
TxAborted = 0x40000000 ,
TxCarrierLost = 0x80000000 ,
} ;
enum RxStatusBits {
RxMulticast = 0x8000 ,
RxPhysical = 0x4000 ,
RxBroadcast = 0x2000 ,
RxBadSymbol = 0x0020 ,
RxRunt = 0x0010 ,
RxTooLong = 0x0008 ,
RxCRCErr = 0x0004 ,
RxBadAlign = 0x0002 ,
RxStatusOK = 0x0001 ,
} ;
/* Bits in RxConfig. */
enum rx_mode_bits {
AcceptErr = 0x20 ,
AcceptRunt = 0x10 ,
AcceptBroadcast = 0x08 ,
AcceptMulticast = 0x04 ,
AcceptMyPhys = 0x02 ,
AcceptAllPhys = 0x01 ,
} ;
/* Bits in TxConfig. */
enum tx_config_bits {
TxIFG1 = ( 1 < < 25 ) , /* Interframe Gap Time */
TxIFG0 = ( 1 < < 24 ) , /* Enabling these bits violates IEEE 802.3 */
TxLoopBack = ( 1 < < 18 ) | ( 1 < < 17 ) , /* enable loopback test mode */
TxCRC = ( 1 < < 16 ) , /* DISABLE appending CRC to end of Tx packets */
TxClearAbt = ( 1 < < 0 ) , /* Clear abort (WO) */
2010-02-17 18:01:55 +03:00
TxDMAShift = 8 , /* DMA burst value(0-7) is shift this many bits */
2005-04-17 02:20:36 +04:00
TxVersionMask = 0x7C800000 , /* mask out version bits 30-26, 23 */
} ;
/* Bits in Config1 */
enum Config1Bits {
Cfg1_PM_Enable = 0x01 ,
Cfg1_VPD_Enable = 0x02 ,
Cfg1_PIO = 0x04 ,
Cfg1_MMIO = 0x08 ,
Cfg1_LWAKE = 0x10 ,
Cfg1_Driver_Load = 0x20 ,
Cfg1_LED0 = 0x40 ,
Cfg1_LED1 = 0x80 ,
} ;
enum RxConfigBits {
/* Early Rx threshold, none or X/16 */
RxCfgEarlyRxNone = 0 ,
RxCfgEarlyRxShift = 24 ,
/* rx fifo threshold */
RxCfgFIFOShift = 13 ,
RxCfgFIFONone = ( 7 < < RxCfgFIFOShift ) ,
/* Max DMA burst */
RxCfgDMAShift = 8 ,
RxCfgDMAUnlimited = ( 7 < < RxCfgDMAShift ) ,
/* rx ring buffer length */
RxCfgRcv8K = 0 ,
RxCfgRcv16K = ( 1 < < 11 ) ,
RxCfgRcv32K = ( 1 < < 12 ) ,
RxCfgRcv64K = ( 1 < < 11 ) | ( 1 < < 12 ) ,
/* Disable packet wrap at end of Rx buffer */
RxNoWrap = ( 1 < < 7 ) ,
} ;
/* Twister tuning parameters from RealTek.
Completely undocumented , but required to tune bad links . */
enum CSCRBits {
CSCR_LinkOKBit = 0x0400 ,
CSCR_LinkChangeBit = 0x0800 ,
CSCR_LinkStatusBits = 0x0f000 ,
CSCR_LinkDownOffCmd = 0x003c0 ,
CSCR_LinkDownCmd = 0x0f3c0 ,
} ;
enum Cfg9346Bits {
Cfg9346_Lock = 0x00 ,
Cfg9346_Unlock = 0xC0 ,
} ;
# define PARA78_default 0x78fa8388
# define PARA7c_default 0xcb38de43 /* param[0][3] */
# define PARA7c_xxx 0xcb38de43
static const unsigned long param [ 4 ] [ 4 ] = {
{ 0xcb39de43 , 0xcb39ce43 , 0xfb38de03 , 0xcb38de43 } ,
{ 0xcb39de43 , 0xcb39ce43 , 0xcb39ce83 , 0xcb39ce83 } ,
{ 0xcb39de43 , 0xcb39ce43 , 0xcb39ce83 , 0xcb39ce83 } ,
{ 0xbb39de43 , 0xbb39ce43 , 0xbb39ce83 , 0xbb39ce83 }
} ;
struct ring_info {
struct sk_buff * skb ;
dma_addr_t mapping ;
} ;
typedef enum {
CH_8139 = 0 ,
CH_8139_K ,
CH_8139A ,
CH_8139B ,
CH_8130 ,
CH_8139C ,
} chip_t ;
/* directly indexed by chip_t, above */
2006-01-10 07:54:01 +03:00
static const struct {
2005-04-17 02:20:36 +04:00
const char * name ;
u8 version ; /* from RTL8139C docs */
u32 RxConfigMask ; /* should clear the bits supported by this chip */
} rtl_chip_info [ ] = {
{ " RTL-8139 " ,
0x40 ,
0xf0fe0040 , /* XXX copied from RTL8139A, verify */
} ,
{ " RTL-8139 rev K " ,
0x60 ,
0xf0fe0040 ,
} ,
{ " RTL-8139A " ,
0x70 ,
0xf0fe0040 ,
} ,
{ " RTL-8139B " ,
0x78 ,
0xf0fc0040
} ,
{ " RTL-8130 " ,
0x7C ,
0xf0fe0040 , /* XXX copied from RTL8139A, verify */
} ,
{ " RTL-8139C " ,
0x74 ,
0xf0fc0040 , /* XXX copied from RTL8139B, verify */
} ,
} ;
struct netdrv_private {
board_t board ;
void * mmio_addr ;
int drv_flags ;
struct pci_dev * pci_dev ;
struct timer_list timer ; /* Media selection timer. */
unsigned char * rx_ring ;
unsigned int cur_rx ; /* Index into the Rx buffer of next Rx pkt. */
unsigned int tx_flag ;
atomic_t cur_tx ;
atomic_t dirty_tx ;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct ring_info tx_info [ NUM_TX_DESC ] ;
unsigned char * tx_buf [ NUM_TX_DESC ] ; /* Tx bounce buffers */
unsigned char * tx_bufs ; /* Tx bounce buffer region. */
dma_addr_t rx_ring_dma ;
dma_addr_t tx_bufs_dma ;
char phys [ 4 ] ; /* MII device addresses. */
char twistie , twist_row , twist_col ; /* Twister tune state. */
unsigned int full_duplex : 1 ; /* Full-duplex operation requested. */
unsigned int duplex_lock : 1 ;
unsigned int default_port : 4 ; /* Last dev->if_port value. */
unsigned int media2 : 4 ; /* Secondary monitored media port. */
unsigned int medialock : 1 ; /* Don't sense media type. */
unsigned int mediasense : 1 ; /* Media sensing in progress. */
spinlock_t lock ;
chip_t chipset ;
} ;
2010-02-17 18:01:55 +03:00
MODULE_AUTHOR ( " Jeff Garzik <jgarzik@pobox.com> " ) ;
MODULE_DESCRIPTION ( " Skeleton for a PCI Fast Ethernet driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2005-07-01 02:03:12 +04:00
module_param ( multicast_filter_limit , int , 0 ) ;
module_param ( max_interrupt_work , int , 0 ) ;
module_param_array ( media , int , NULL , 0 ) ;
2010-02-17 18:01:55 +03:00
MODULE_PARM_DESC ( multicast_filter_limit ,
MODNAME " maximum number of filtered multicast addresses " ) ;
MODULE_PARM_DESC ( max_interrupt_work ,
MODNAME " maximum events handled per interrupt " ) ;
MODULE_PARM_DESC ( media ,
MODNAME " Bits 0-3: media type, bit 17: full duplex " ) ;
static int read_eeprom ( void * ioaddr , int location , int addr_len ) ;
static int netdrv_open ( struct net_device * dev ) ;
static int mdio_read ( struct net_device * dev , int phy_id , int location ) ;
static void mdio_write ( struct net_device * dev , int phy_id , int location ,
int val ) ;
static void netdrv_timer ( unsigned long data ) ;
static void netdrv_tx_timeout ( struct net_device * dev ) ;
static void netdrv_init_ring ( struct net_device * dev ) ;
static int netdrv_start_xmit ( struct sk_buff * skb ,
struct net_device * dev ) ;
static irqreturn_t netdrv_interrupt ( int irq , void * dev_instance ) ;
static int netdrv_close ( struct net_device * dev ) ;
static int netdrv_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd ) ;
static void netdrv_set_rx_mode ( struct net_device * dev ) ;
static void netdrv_hw_start ( struct net_device * dev ) ;
2005-04-17 02:20:36 +04:00
# ifdef USE_IO_OPS
2010-02-17 18:01:55 +03:00
# define NETDRV_R8(reg) inb(((unsigned long)ioaddr) + (reg))
# define NETDRV_R16(reg) inw(((unsigned long)ioaddr) + (reg))
# define NETDRV_R32(reg) ((unsigned long)inl(((unsigned long)ioaddr) + (reg)))
# define NETDRV_W8(reg, val8) outb((val8), ((unsigned long)ioaddr) + (reg))
# define NETDRV_W16(reg, val16) outw((val16), ((unsigned long)ioaddr) + (reg))
# define NETDRV_W32(reg, val32) outl((val32), ((unsigned long)ioaddr) + (reg))
2005-04-17 02:20:36 +04:00
# define NETDRV_W8_F NETDRV_W8
# define NETDRV_W16_F NETDRV_W16
# define NETDRV_W32_F NETDRV_W32
# undef readb
# undef readw
# undef readl
# undef writeb
# undef writew
# undef writel
# define readb(addr) inb((unsigned long)(addr))
# define readw(addr) inw((unsigned long)(addr))
# define readl(addr) inl((unsigned long)(addr))
2010-02-17 18:01:55 +03:00
# define writeb(val, addr) outb((val), (unsigned long)(addr))
# define writew(val, addr) outw((val), (unsigned long)(addr))
# define writel(val, addr) outl((val), (unsigned long)(addr))
2005-04-17 02:20:36 +04:00
# else
/* write MMIO register, with flush */
/* Flush avoids rtl8139 bug w/ posted MMIO writes */
2010-02-17 18:01:55 +03:00
# define NETDRV_W8_F(reg, val8) \
do { \
writeb ( ( val8 ) , ioaddr + ( reg ) ) ; \
readb ( ioaddr + ( reg ) ) ; \
} while ( 0 )
# define NETDRV_W16_F(reg, val16) \
do { \
writew ( ( val16 ) , ioaddr + ( reg ) ) ; \
readw ( ioaddr + ( reg ) ) ; \
} while ( 0 )
# define NETDRV_W32_F(reg, val32) \
do { \
writel ( ( val32 ) , ioaddr + ( reg ) ) ; \
readl ( ioaddr + ( reg ) ) ; \
} while ( 0 )
2005-04-17 02:20:36 +04:00
2008-01-24 09:51:36 +03:00
# ifdef MMIO_FLUSH_AUDIT_COMPLETE
2005-04-17 02:20:36 +04:00
/* write MMIO register */
2010-02-17 18:01:55 +03:00
# define NETDRV_W8(reg, val8) writeb((val8), ioaddr + (reg))
# define NETDRV_W16(reg, val16) writew((val16), ioaddr + (reg))
# define NETDRV_W32(reg, val32) writel((val32), ioaddr + (reg))
2005-04-17 02:20:36 +04:00
# else
/* write MMIO register, then flush */
# define NETDRV_W8 NETDRV_W8_F
# define NETDRV_W16 NETDRV_W16_F
# define NETDRV_W32 NETDRV_W32_F
# endif /* MMIO_FLUSH_AUDIT_COMPLETE */
/* read MMIO register */
2010-02-17 18:01:55 +03:00
# define NETDRV_R8(reg) readb(ioaddr + (reg))
# define NETDRV_R16(reg) readw(ioaddr + (reg))
# define NETDRV_R32(reg) ((unsigned long) readl(ioaddr + (reg)))
2005-04-17 02:20:36 +04:00
# endif /* USE_IO_OPS */
static const u16 netdrv_intr_mask =
PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
TxErr | TxOK | RxErr | RxOK ;
static const unsigned int netdrv_rx_config =
2010-02-17 18:01:55 +03:00
RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap |
( RX_FIFO_THRESH < < RxCfgFIFOShift ) |
( RX_DMA_BURST < < RxCfgDMAShift ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
static int __devinit netdrv_init_board ( struct pci_dev * pdev ,
struct net_device * * dev_out ,
void * * ioaddr_out )
2005-04-17 02:20:36 +04:00
{
void * ioaddr = NULL ;
struct net_device * dev ;
struct netdrv_private * tp ;
int rc , i ;
u32 pio_start , pio_end , pio_flags , pio_len ;
unsigned long mmio_start , mmio_end , mmio_flags , mmio_len ;
u32 tmp ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( pdev ! = NULL ) ;
assert ( ioaddr_out ! = NULL ) ;
2005-04-17 02:20:36 +04:00
* ioaddr_out = NULL ;
* dev_out = NULL ;
/* dev zeroed in alloc_etherdev */
2010-02-17 18:01:55 +03:00
dev = alloc_etherdev ( sizeof ( * tp ) ) ;
2005-04-17 02:20:36 +04:00
if ( dev = = NULL ) {
2006-06-27 19:39:50 +04:00
dev_err ( & pdev - > dev , " unable to alloc new ethernet \n " ) ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning -ENOMEM \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
2008-01-24 09:51:36 +03:00
tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
/* enable device(incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
goto err_out ;
2010-02-17 18:01:55 +03:00
pio_start = pci_resource_start ( pdev , 0 ) ;
pio_end = pci_resource_end ( pdev , 0 ) ;
pio_flags = pci_resource_flags ( pdev , 0 ) ;
pio_len = pci_resource_len ( pdev , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
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 ) ;
2005-04-17 02:20:36 +04:00
/* set this immediately, we need to know before
* we talk to the chip directly */
2010-02-17 18:01:55 +03:00
DPRINTK ( " PIO region size == %#02X \n " , pio_len ) ;
DPRINTK ( " MMIO region size == %#02lX \n " , mmio_len ) ;
2005-04-17 02:20:36 +04:00
/* make sure PCI base addr 0 is PIO */
if ( ! ( pio_flags & IORESOURCE_IO ) ) {
2006-06-27 19:39:50 +04:00
dev_err ( & pdev - > dev , " region #0 not a PIO resource, aborting \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - ENODEV ;
goto err_out ;
}
/* make sure PCI base addr 1 is MMIO */
if ( ! ( mmio_flags & IORESOURCE_MEM ) ) {
2006-06-27 19:39:50 +04:00
dev_err ( & pdev - > dev , " region #1 not an MMIO resource, aborting \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - ENODEV ;
goto err_out ;
}
/* check for weird/broken PCI region reporting */
if ( ( pio_len < NETDRV_MIN_IO_SIZE ) | |
( mmio_len < NETDRV_MIN_IO_SIZE ) ) {
2006-06-27 19:39:50 +04:00
dev_err ( & pdev - > dev , " Invalid PCI region size(s), aborting \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - ENODEV ;
goto err_out ;
}
2010-02-17 18:01:55 +03:00
rc = pci_request_regions ( pdev , MODNAME ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
goto err_out ;
2010-02-17 18:01:55 +03:00
pci_set_master ( pdev ) ;
2005-04-17 02:20:36 +04:00
# ifdef USE_IO_OPS
2010-02-17 18:01:55 +03:00
ioaddr = ( void * ) pio_start ;
2005-04-17 02:20:36 +04:00
# else
/* ioremap MMIO region */
2010-02-17 18:01:55 +03:00
ioaddr = ioremap ( mmio_start , mmio_len ) ;
2005-04-17 02:20:36 +04:00
if ( ioaddr = = NULL ) {
2006-06-27 19:39:50 +04:00
dev_err ( & pdev - > dev , " cannot remap MMIO, aborting \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - EIO ;
goto err_out_free_res ;
}
# endif /* USE_IO_OPS */
/* Soft reset the chip. */
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) | CmdReset ) ;
2005-04-17 02:20:36 +04:00
/* Check that the chip has finished the reset. */
for ( i = 1000 ; i > 0 ; i - - )
2010-02-17 18:01:55 +03:00
if ( ( NETDRV_R8 ( ChipCmd ) & CmdReset ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
else
2010-02-17 18:01:55 +03:00
udelay ( 10 ) ;
2005-04-17 02:20:36 +04:00
/* Bring the chip out of low-power mode. */
/* <insert device-specific code here> */
# ifndef USE_IO_OPS
/* sanity checks -- ensure PIO and MMIO registers agree */
2010-02-17 18:01:55 +03:00
assert ( inb ( pio_start + Config0 ) = = readb ( ioaddr + Config0 ) ) ;
assert ( inb ( pio_start + Config1 ) = = readb ( ioaddr + Config1 ) ) ;
assert ( inb ( pio_start + TxConfig ) = = readb ( ioaddr + TxConfig ) ) ;
assert ( inb ( pio_start + RxConfig ) = = readb ( ioaddr + RxConfig ) ) ;
2005-04-17 02:20:36 +04:00
# endif /* !USE_IO_OPS */
/* identify chip attached to board */
2010-02-17 18:01:55 +03:00
tmp = NETDRV_R8 ( ChipVersion ) ;
for ( i = ARRAY_SIZE ( rtl_chip_info ) - 1 ; i > = 0 ; i - - )
2005-04-17 02:20:36 +04:00
if ( tmp = = rtl_chip_info [ i ] . version ) {
tp - > chipset = i ;
goto match ;
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
2010-02-17 18:01:55 +03:00
dev_printk ( KERN_DEBUG , & pdev - > dev ,
" unknown chip version, assuming RTL-8139 \n " ) ;
dev_printk ( KERN_DEBUG , & pdev - > dev , " TxConfig = %#lx \n " ,
NETDRV_R32 ( TxConfig ) ) ;
2005-04-17 02:20:36 +04:00
tp - > chipset = 0 ;
match :
2010-02-17 18:01:55 +03:00
DPRINTK ( " chipset id(%d) == index %d, '%s' \n " ,
tmp , tp - > chipset , rtl_chip_info [ tp - > chipset ] . name ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
rc = register_netdev ( dev ) ;
2007-03-17 01:00:21 +03:00
if ( rc )
2005-04-17 02:20:36 +04:00
goto err_out_unmap ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
* ioaddr_out = ioaddr ;
* dev_out = dev ;
return 0 ;
err_out_unmap :
# ifndef USE_IO_OPS
iounmap ( ioaddr ) ;
err_out_free_res :
# endif
2010-02-17 18:01:55 +03:00
pci_release_regions ( pdev ) ;
2005-04-17 02:20:36 +04:00
err_out :
2010-02-17 18:01:55 +03:00
free_netdev ( dev ) ;
DPRINTK ( " EXIT, returning %d \n " , rc ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2009-04-15 16:52:55 +04:00
static const struct net_device_ops netdrv_netdev_ops = {
. ndo_open = netdrv_open ,
. ndo_stop = netdrv_close ,
. ndo_start_xmit = netdrv_start_xmit ,
. ndo_set_multicast_list = netdrv_set_rx_mode ,
. ndo_do_ioctl = netdrv_ioctl ,
. ndo_tx_timeout = netdrv_tx_timeout ,
. ndo_change_mtu = eth_change_mtu ,
. ndo_validate_addr = eth_validate_addr ,
. ndo_set_mac_address = eth_mac_addr ,
} ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
static int __devinit netdrv_init_one ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev = NULL ;
struct netdrv_private * tp ;
int i , addr_len , option ;
void * ioaddr = NULL ;
static int board_idx = - 1 ;
/* when built into the kernel, we only print version if device is found */
# ifndef MODULE
static int printed_version ;
if ( ! printed_version + + )
printk ( version ) ;
# endif
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( pdev ! = NULL ) ;
assert ( ent ! = NULL ) ;
2005-04-17 02:20:36 +04:00
board_idx + + ;
2010-02-17 18:01:55 +03:00
i = netdrv_init_board ( pdev , & dev , & ioaddr ) ;
2005-04-17 02:20:36 +04:00
if ( i < 0 ) {
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning %d \n " , i ) ;
2005-04-17 02:20:36 +04:00
return i ;
}
2008-01-24 09:51:36 +03:00
tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( ioaddr ! = NULL ) ;
assert ( dev ! = NULL ) ;
assert ( tp ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
addr_len = read_eeprom ( ioaddr , 0 , 8 ) = = 0x8129 ? 8 : 6 ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 3 ; i + + )
2010-02-17 18:01:55 +03:00
( ( u16 * ) ( dev - > dev_addr ) ) [ i ] =
le16_to_cpu ( read_eeprom ( ioaddr , i + 7 , addr_len ) ) ;
2005-04-17 02:20:36 +04:00
2009-04-15 16:52:55 +04:00
dev - > netdev_ops = & netdrv_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > watchdog_timeo = TX_TIMEOUT ;
dev - > irq = pdev - > irq ;
dev - > base_addr = ( unsigned long ) ioaddr ;
2008-12-08 12:14:16 +03:00
/* netdev_priv()/tp zeroed and aligned in alloc_etherdev */
2008-01-24 09:51:36 +03:00
tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
/* note: tp->chipset set in netdrv_init_board */
tp - > drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
2010-02-17 18:01:55 +03:00
PCI_COMMAND_MASTER | NETDRV_CAPS ;
2005-04-17 02:20:36 +04:00
tp - > pci_dev = pdev ;
tp - > board = ent - > driver_data ;
tp - > mmio_addr = ioaddr ;
spin_lock_init ( & tp - > lock ) ;
pci_set_drvdata ( pdev , dev ) ;
tp - > phys [ 0 ] = 32 ;
2010-02-17 18:01:55 +03:00
netdev_info ( dev , " %s at %#lx, %pM IRQ %d \n " ,
board_info [ ent - > driver_data ] . name ,
dev - > base_addr , dev - > dev_addr , dev - > irq ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_printk ( KERN_DEBUG , dev , " Identified 8139 chip type '%s' \n " ,
rtl_chip_info [ tp - > chipset ] . name ) ;
2005-04-17 02:20:36 +04:00
/* Put the chip into low-power mode. */
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( Cfg9346 , Cfg9346_Unlock ) ;
2005-04-17 02:20:36 +04:00
/* The lower four bits are the media type. */
option = ( board_idx > 7 ) ? 0 : media [ board_idx ] ;
if ( option > 0 ) {
tp - > full_duplex = ( option & 0x200 ) ? 1 : 0 ;
tp - > default_port = option & 15 ;
if ( tp - > default_port )
tp - > medialock = 1 ;
}
if ( tp - > full_duplex ) {
2010-02-17 18:01:55 +03:00
netdev_info ( dev , " Media type forced to Full Duplex \n " ) ;
mdio_write ( dev , tp - > phys [ 0 ] , MII_ADVERTISE , ADVERTISE_FULL ) ;
2005-04-17 02:20:36 +04:00
tp - > duplex_lock = 1 ;
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT - returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-02-17 18:01:55 +03:00
static void __devexit netdrv_remove_one ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2010-02-17 18:01:55 +03:00
struct net_device * dev = pci_get_drvdata ( pdev ) ;
2005-04-17 02:20:36 +04:00
struct netdrv_private * np ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( dev ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2008-01-24 09:51:36 +03:00
np = netdev_priv ( dev ) ;
2010-02-17 18:01:55 +03:00
assert ( np ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
unregister_netdev ( dev ) ;
2005-04-17 02:20:36 +04:00
# ifndef USE_IO_OPS
2010-02-17 18:01:55 +03:00
iounmap ( np - > mmio_addr ) ;
2005-04-17 02:20:36 +04:00
# endif /* !USE_IO_OPS */
2010-02-17 18:01:55 +03:00
pci_release_regions ( pdev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
free_netdev ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
pci_set_drvdata ( pdev , NULL ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
pci_disable_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
# define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
2010-02-17 18:01:55 +03:00
# define EE_CS 0x08 /* EEPROM chip select. */
2005-04-17 02:20:36 +04:00
# define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
2010-02-17 18:01:55 +03:00
# define EE_WRITE_0 0x00
# define EE_WRITE_1 0x02
2005-04-17 02:20:36 +04:00
# define EE_DATA_READ 0x01 /* EEPROM chip data out. */
2010-02-17 18:01:55 +03:00
# define EE_ENB (0x80 | EE_CS)
2005-04-17 02:20:36 +04:00
/* Delay between EEPROM clock transitions.
No extra delay is needed with 33 Mhz PCI , but 66 Mhz may change this .
2010-02-17 18:01:55 +03:00
*/
2005-04-17 02:20:36 +04:00
# define eeprom_delay() readl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
# define EE_WRITE_CMD (5)
2010-02-17 18:01:55 +03:00
# define EE_READ_CMD (6)
2005-04-17 02:20:36 +04:00
# define EE_ERASE_CMD (7)
2010-02-17 18:01:55 +03:00
static int __devinit read_eeprom ( void * ioaddr , int location , int addr_len )
2005-04-17 02:20:36 +04:00
{
int i ;
unsigned retval = 0 ;
void * ee_addr = ioaddr + Cfg9346 ;
int read_cmd = location | ( EE_READ_CMD < < addr_len ) ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
writeb ( EE_ENB & ~ EE_CS , ee_addr ) ;
writeb ( EE_ENB , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
/* Shift the read command bits out. */
for ( i = 4 + addr_len ; i > = 0 ; i - - ) {
int dataval = ( read_cmd & ( 1 < < i ) ) ? EE_DATA_WRITE : 0 ;
2010-02-17 18:01:55 +03:00
writeb ( EE_ENB | dataval , ee_addr ) ;
eeprom_delay ( ) ;
writeb ( EE_ENB | dataval | EE_SHIFT_CLK , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
writeb ( EE_ENB , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
for ( i = 16 ; i > 0 ; i - - ) {
2010-02-17 18:01:55 +03:00
writeb ( EE_ENB | EE_SHIFT_CLK , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
retval =
2010-02-17 18:01:55 +03:00
( retval < < 1 ) | ( ( readb ( ee_addr ) & EE_DATA_READ ) ? 1 :
0 ) ;
writeb ( EE_ENB , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
/* Terminate the EEPROM access. */
2010-02-17 18:01:55 +03:00
writeb ( ~ EE_CS , ee_addr ) ;
eeprom_delay ( ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT - returning %d \n " , retval ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
/* MII serial management: mostly bogus for now. */
/* Read and write the MII management registers using software-generated
serial MDIO protocol .
The maximum data clock rate is 2.5 Mhz . The minimum timing is usually
met by back - to - back PCI I / O cycles , but we insert a delay to avoid
" overclocking " issues . */
2010-02-17 18:01:55 +03:00
# define MDIO_DIR 0x80
2005-04-17 02:20:36 +04:00
# define MDIO_DATA_OUT 0x04
# define MDIO_DATA_IN 0x02
2010-02-17 18:01:55 +03:00
# define MDIO_CLK 0x01
# define MDIO_WRITE0 (MDIO_DIR)
# define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
2005-04-17 02:20:36 +04:00
# define mdio_delay() readb(mdio_addr)
static char mii_2_8139_map [ 8 ] = {
BasicModeCtrl ,
BasicModeStatus ,
0 ,
0 ,
NWayAdvert ,
NWayLPAR ,
NWayExpansion ,
0
} ;
/* Syncronize the MII management interface by shifting 32 one bits out. */
2010-02-17 18:01:55 +03:00
static void mdio_sync ( void * mdio_addr )
2005-04-17 02:20:36 +04:00
{
int i ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 32 ; i > = 0 ; i - - ) {
2010-02-17 18:01:55 +03:00
writeb ( MDIO_WRITE1 , mdio_addr ) ;
mdio_delay ( ) ;
writeb ( MDIO_WRITE1 | MDIO_CLK , mdio_addr ) ;
mdio_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static int mdio_read ( struct net_device * dev , int phy_id , int location )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * mdio_addr = tp - > mmio_addr + Config4 ;
int mii_cmd = ( 0xf6 < < 10 ) | ( phy_id < < 5 ) | location ;
int retval = 0 ;
int i ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( phy_id > 31 ) { /* Really a 8139. Use internal registers. */
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT after directly using 8139 internal regs \n " ) ;
2005-04-17 02:20:36 +04:00
return location < 8 & & mii_2_8139_map [ location ] ?
2010-02-17 18:01:55 +03:00
readw ( tp - > mmio_addr + mii_2_8139_map [ location ] ) : 0 ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
mdio_sync ( mdio_addr ) ;
2005-04-17 02:20:36 +04:00
/* Shift the read command bits out. */
for ( i = 15 ; i > = 0 ; i - - ) {
int dataval = ( mii_cmd & ( 1 < < i ) ) ? MDIO_DATA_OUT : 0 ;
2010-02-17 18:01:55 +03:00
writeb ( MDIO_DIR | dataval , mdio_addr ) ;
mdio_delay ( ) ;
writeb ( MDIO_DIR | dataval | MDIO_CLK , mdio_addr ) ;
mdio_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
/* Read the two transition, 16 data, and wire-idle bits. */
for ( i = 19 ; i > 0 ; i - - ) {
2010-02-17 18:01:55 +03:00
writeb ( 0 , mdio_addr ) ;
mdio_delay ( ) ;
retval = ( ( retval < < 1 ) | ( ( readb ( mdio_addr ) & MDIO_DATA_IN ) )
? 1 : 0 ) ;
writeb ( MDIO_CLK , mdio_addr ) ;
mdio_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning %d \n " , ( retval > > 1 ) & 0xffff ) ;
2005-04-17 02:20:36 +04:00
return ( retval > > 1 ) & 0xffff ;
}
2010-02-17 18:01:55 +03:00
static void mdio_write ( struct net_device * dev , int phy_id , int location ,
int value )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * mdio_addr = tp - > mmio_addr + Config4 ;
int mii_cmd =
2010-02-17 18:01:55 +03:00
( 0x5002 < < 16 ) | ( phy_id < < 23 ) | ( location < < 18 ) | value ;
2005-04-17 02:20:36 +04:00
int i ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( phy_id > 31 ) { /* Really a 8139. Use internal registers. */
if ( location < 8 & & mii_2_8139_map [ location ] ) {
2010-02-17 18:01:55 +03:00
writew ( value ,
tp - > mmio_addr + mii_2_8139_map [ location ] ) ;
readw ( tp - > mmio_addr + mii_2_8139_map [ location ] ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT after directly using 8139 internal regs \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2010-02-17 18:01:55 +03:00
mdio_sync ( mdio_addr ) ;
2005-04-17 02:20:36 +04:00
/* Shift the command bits out. */
for ( i = 31 ; i > = 0 ; i - - ) {
int dataval =
2010-02-17 18:01:55 +03:00
( mii_cmd & ( 1 < < i ) ) ? MDIO_WRITE1 : MDIO_WRITE0 ;
writeb ( dataval , mdio_addr ) ;
mdio_delay ( ) ;
writeb ( dataval | MDIO_CLK , mdio_addr ) ;
mdio_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
/* Clear out extra bits. */
for ( i = 2 ; i > 0 ; i - - ) {
2010-02-17 18:01:55 +03:00
writeb ( 0 , mdio_addr ) ;
mdio_delay ( ) ;
writeb ( MDIO_CLK , mdio_addr ) ;
mdio_delay ( ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static int netdrv_open ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
int retval ;
void * ioaddr = tp - > mmio_addr ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
retval = request_irq ( dev - > irq , netdrv_interrupt , IRQF_SHARED , dev - > name , dev ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning %d \n " , retval ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
tp - > tx_bufs = pci_alloc_consistent ( tp - > pci_dev , TX_BUF_TOT_LEN ,
& tp - > tx_bufs_dma ) ;
tp - > rx_ring = pci_alloc_consistent ( tp - > pci_dev , RX_BUF_TOT_LEN ,
& tp - > rx_ring_dma ) ;
if ( tp - > tx_bufs = = NULL | | tp - > rx_ring = = NULL ) {
free_irq ( dev - > irq , dev ) ;
if ( tp - > tx_bufs )
pci_free_consistent ( tp - > pci_dev , TX_BUF_TOT_LEN ,
tp - > tx_bufs , tp - > tx_bufs_dma ) ;
if ( tp - > rx_ring )
pci_free_consistent ( tp - > pci_dev , RX_BUF_TOT_LEN ,
tp - > rx_ring , tp - > rx_ring_dma ) ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning -ENOMEM \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
tp - > full_duplex = tp - > duplex_lock ;
tp - > tx_flag = ( TX_FIFO_THRESH < < 11 ) & 0x003f0000 ;
2010-02-17 18:01:55 +03:00
netdrv_init_ring ( dev ) ;
netdrv_hw_start ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " ioaddr %#llx IRQ %d GP Pins %02x %s-duplex \n " ,
( unsigned long long ) pci_resource_start ( tp - > pci_dev , 1 ) ,
dev - > irq , NETDRV_R8 ( MediaStatus ) ,
tp - > full_duplex ? " full " : " half " ) ;
2005-04-17 02:20:36 +04:00
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type . */
2010-02-17 18:01:55 +03:00
init_timer ( & tp - > timer ) ;
2005-04-17 02:20:36 +04:00
tp - > timer . expires = jiffies + 3 * HZ ;
tp - > timer . data = ( unsigned long ) dev ;
2010-08-23 22:20:03 +04:00
tp - > timer . function = netdrv_timer ;
2010-02-17 18:01:55 +03:00
add_timer ( & tp - > timer ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Start the hardware at open or resume. */
2010-02-17 18:01:55 +03:00
static void netdrv_hw_start ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
u32 i ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
/* Soft reset the chip. */
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) | CmdReset ) ;
udelay ( 100 ) ;
2005-04-17 02:20:36 +04:00
/* Check that the chip has finished the reset. */
for ( i = 1000 ; i > 0 ; i - - )
2010-02-17 18:01:55 +03:00
if ( ( NETDRV_R8 ( ChipCmd ) & CmdReset ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
/* Restore our idea of the MAC address. */
2010-02-17 18:01:55 +03:00
NETDRV_W32_F ( MAC0 + 0 , cpu_to_le32 ( * ( u32 * ) ( dev - > dev_addr + 0 ) ) ) ;
NETDRV_W32_F ( MAC0 + 4 , cpu_to_le32 ( * ( u32 * ) ( dev - > dev_addr + 4 ) ) ) ;
2005-04-17 02:20:36 +04:00
/* Must enable Tx/Rx before setting transfer thresholds! */
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) |
CmdRxEnb | CmdTxEnb ) ;
2005-04-17 02:20:36 +04:00
i = netdrv_rx_config |
2010-02-17 18:01:55 +03:00
( NETDRV_R32 ( RxConfig ) & rtl_chip_info [ tp - > chipset ] . RxConfigMask ) ;
NETDRV_W32_F ( RxConfig , i ) ;
2005-04-17 02:20:36 +04:00
/* Check this value: the documentation for IFG contradicts ifself. */
2010-02-17 18:01:55 +03:00
NETDRV_W32 ( TxConfig , ( TX_DMA_BURST < < TxDMAShift ) ) ;
2005-04-17 02:20:36 +04:00
/* unlock Config[01234] and BMCR register writes */
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( Cfg9346 , Cfg9346_Unlock ) ;
udelay ( 10 ) ;
2005-04-17 02:20:36 +04:00
tp - > cur_rx = 0 ;
/* Lock Config[01234] and BMCR register writes */
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( Cfg9346 , Cfg9346_Lock ) ;
udelay ( 10 ) ;
2005-04-17 02:20:36 +04:00
/* init Rx ring buffer DMA address */
2010-02-17 18:01:55 +03:00
NETDRV_W32_F ( RxBuf , tp - > rx_ring_dma ) ;
2005-04-17 02:20:36 +04:00
/* init Tx buffer DMA addresses */
for ( i = 0 ; i < NUM_TX_DESC ; i + + )
2010-02-17 18:01:55 +03:00
NETDRV_W32_F ( TxAddr0 + ( i * 4 ) , tp - > tx_bufs_dma + ( tp - > tx_buf [ i ] - tp - > tx_bufs ) ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
NETDRV_W32_F ( RxMissed , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdrv_set_rx_mode ( dev ) ;
2005-04-17 02:20:36 +04:00
/* no early-rx interrupts */
2010-02-17 18:01:55 +03:00
NETDRV_W16 ( MultiIntr , NETDRV_R16 ( MultiIntr ) & MultiIntrClear ) ;
2005-04-17 02:20:36 +04:00
/* make sure RxTx has started */
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) |
CmdRxEnb | CmdTxEnb ) ;
2005-04-17 02:20:36 +04:00
/* Enable all known interrupts by setting the interrupt mask. */
2010-02-17 18:01:55 +03:00
NETDRV_W16_F ( IntrMask , netdrv_intr_mask ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netif_start_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
2010-02-17 18:01:55 +03:00
static void netdrv_init_ring ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
int i ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
tp - > cur_rx = 0 ;
2010-02-17 18:01:55 +03:00
atomic_set ( & tp - > cur_tx , 0 ) ;
atomic_set ( & tp - > dirty_tx , 0 ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < NUM_TX_DESC ; i + + ) {
tp - > tx_info [ i ] . skb = NULL ;
tp - > tx_info [ i ] . mapping = 0 ;
tp - > tx_buf [ i ] = & tp - > tx_bufs [ i * TX_BUF_SIZE ] ;
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static void netdrv_timer ( unsigned long data )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev = ( struct net_device * ) data ;
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
int next_tick = 60 * HZ ;
int mii_lpa ;
2010-02-17 18:01:55 +03:00
mii_lpa = mdio_read ( dev , tp - > phys [ 0 ] , MII_LPA ) ;
2005-04-17 02:20:36 +04:00
if ( ! tp - > duplex_lock & & mii_lpa ! = 0xffff ) {
2009-12-03 10:58:21 +03:00
int duplex = ( ( mii_lpa & LPA_100FULL ) | |
2010-02-17 18:01:55 +03:00
( mii_lpa & 0x01C0 ) = = 0x0040 ) ;
2005-04-17 02:20:36 +04:00
if ( tp - > full_duplex ! = duplex ) {
tp - > full_duplex = duplex ;
2010-02-17 18:01:55 +03:00
netdev_info ( dev , " Setting %s-duplex based on MII #%d link partner ability of %04x \n " ,
tp - > full_duplex ? " full " : " half " ,
tp - > phys [ 0 ] , mii_lpa ) ;
NETDRV_W8 ( Cfg9346 , Cfg9346_Unlock ) ;
NETDRV_W8 ( Config1 , tp - > full_duplex ? 0x60 : 0x20 ) ;
NETDRV_W8 ( Cfg9346 , Cfg9346_Lock ) ;
2005-04-17 02:20:36 +04:00
}
}
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Media selection tick, Link partner %04x \n " ,
NETDRV_R16 ( NWayLPAR ) ) ;
netdev_dbg ( dev , " Other registers are IntMask %04x IntStatus %04x RxStatus %04lx \n " ,
NETDRV_R16 ( IntrMask ) ,
NETDRV_R16 ( IntrStatus ) ,
NETDRV_R32 ( RxEarlyStatus ) ) ;
netdev_dbg ( dev , " Chip config %02x %02x \n " ,
NETDRV_R8 ( Config0 ) , NETDRV_R8 ( Config1 ) ) ;
2005-04-17 02:20:36 +04:00
tp - > timer . expires = jiffies + next_tick ;
2010-02-17 18:01:55 +03:00
add_timer ( & tp - > timer ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static void netdrv_tx_clear ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
atomic_set ( & tp - > cur_tx , 0 ) ;
atomic_set ( & tp - > dirty_tx , 0 ) ;
2005-04-17 02:20:36 +04:00
/* Dump the unsent Tx packets. */
for ( i = 0 ; i < NUM_TX_DESC ; i + + ) {
struct ring_info * rp = & tp - > tx_info [ i ] ;
if ( rp - > mapping ! = 0 ) {
2010-02-17 18:01:55 +03:00
pci_unmap_single ( tp - > pci_dev , rp - > mapping ,
rp - > skb - > len , PCI_DMA_TODEVICE ) ;
2005-04-17 02:20:36 +04:00
rp - > mapping = 0 ;
}
if ( rp - > skb ) {
2010-02-17 18:01:55 +03:00
dev_kfree_skb ( rp - > skb ) ;
2005-04-17 02:20:36 +04:00
rp - > skb = NULL ;
2007-10-04 04:41:50 +04:00
dev - > stats . tx_dropped + + ;
2005-04-17 02:20:36 +04:00
}
}
}
2010-02-17 18:01:55 +03:00
static void netdrv_tx_timeout ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
int i ;
u8 tmp8 ;
unsigned long flags ;
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Transmit timeout, status %02x %04x media %02x \n " ,
NETDRV_R8 ( ChipCmd ) ,
NETDRV_R16 ( IntrStatus ) ,
NETDRV_R8 ( MediaStatus ) ) ;
2005-04-17 02:20:36 +04:00
/* disable Tx ASAP, if not already */
2010-02-17 18:01:55 +03:00
tmp8 = NETDRV_R8 ( ChipCmd ) ;
2005-04-17 02:20:36 +04:00
if ( tmp8 & CmdTxEnb )
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( ChipCmd , tmp8 & ~ CmdTxEnb ) ;
2005-04-17 02:20:36 +04:00
/* Disable interrupts by clearing the interrupt mask. */
2010-02-17 18:01:55 +03:00
NETDRV_W16 ( IntrMask , 0x0000 ) ;
2005-04-17 02:20:36 +04:00
/* Emit info to figure out what went wrong. */
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Tx queue start entry %d dirty entry %d \n " ,
atomic_read ( & tp - > cur_tx ) ,
atomic_read ( & tp - > dirty_tx ) ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < NUM_TX_DESC ; i + + )
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Tx descriptor %d is %08lx%s \n " ,
i , NETDRV_R32 ( TxStatus0 + ( i * 4 ) ) ,
i = = atomic_read ( & tp - > dirty_tx ) % NUM_TX_DESC ?
" (queue head) " : " " ) ;
2005-04-17 02:20:36 +04:00
/* Stop a shared interrupt from scavenging while we are. */
2010-02-17 18:01:55 +03:00
spin_lock_irqsave ( & tp - > lock , flags ) ;
2006-09-13 21:24:59 +04:00
2010-02-17 18:01:55 +03:00
netdrv_tx_clear ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
spin_unlock_irqrestore ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* ...and finally, reset everything */
2010-02-17 18:01:55 +03:00
netdrv_hw_start ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netif_wake_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static int netdrv_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
int entry ;
/* Calculate the next Tx descriptor entry. */
2010-02-17 18:01:55 +03:00
entry = atomic_read ( & tp - > cur_tx ) % NUM_TX_DESC ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( tp - > tx_info [ entry ] . skb = = NULL ) ;
assert ( tp - > tx_info [ entry ] . mapping = = 0 ) ;
2005-04-17 02:20:36 +04:00
tp - > tx_info [ entry ] . skb = skb ;
/* tp->tx_info[entry].mapping = 0; */
2007-03-28 01:55:52 +04:00
skb_copy_from_linear_data ( skb , tp - > tx_buf [ entry ] , skb - > len ) ;
2005-04-17 02:20:36 +04:00
/* Note: the chip doesn't have auto-pad! */
2010-02-17 18:01:55 +03:00
NETDRV_W32 ( TxStatus0 + ( entry * sizeof ( u32 ) ) ,
tp - > tx_flag | ( skb - > len > = ETH_ZLEN ? skb - > len : ETH_ZLEN ) ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
atomic_inc ( & tp - > cur_tx ) ;
if ( ( atomic_read ( & tp - > cur_tx ) - atomic_read ( & tp - > dirty_tx ) ) > = NUM_TX_DESC )
netif_stop_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Queued Tx packet at %p size %u to slot %d \n " ,
skb - > data , skb - > len , entry ) ;
2005-04-17 02:20:36 +04:00
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static void netdrv_tx_interrupt ( struct net_device * dev ,
struct netdrv_private * tp ,
void * ioaddr )
2005-04-17 02:20:36 +04:00
{
int cur_tx , dirty_tx , tx_left ;
2010-02-17 18:01:55 +03:00
assert ( dev ! = NULL ) ;
assert ( tp ! = NULL ) ;
assert ( ioaddr ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
dirty_tx = atomic_read ( & tp - > dirty_tx ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
cur_tx = atomic_read ( & tp - > cur_tx ) ;
2005-04-17 02:20:36 +04:00
tx_left = cur_tx - dirty_tx ;
while ( tx_left > 0 ) {
int entry = dirty_tx % NUM_TX_DESC ;
int txstatus ;
2010-02-17 18:01:55 +03:00
txstatus = NETDRV_R32 ( TxStatus0 + ( entry * sizeof ( u32 ) ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( txstatus & ( TxStatOK | TxUnderrun | TxAborted ) ) )
break ; /* It still hasn't been Txed */
/* Note: TxCarrierLost is always asserted at 100mbps. */
if ( txstatus & ( TxOutOfWindow | TxAborted ) ) {
/* There was an major error, log it. */
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Transmit error, Tx status %#08x \n " ,
txstatus ) ;
2007-10-04 04:41:50 +04:00
dev - > stats . tx_errors + + ;
2005-04-17 02:20:36 +04:00
if ( txstatus & TxAborted ) {
2007-10-04 04:41:50 +04:00
dev - > stats . tx_aborted_errors + + ;
2010-02-17 18:01:55 +03:00
NETDRV_W32 ( TxConfig , TxClearAbt | ( TX_DMA_BURST < < TxDMAShift ) ) ;
2005-04-17 02:20:36 +04:00
}
if ( txstatus & TxCarrierLost )
2007-10-04 04:41:50 +04:00
dev - > stats . tx_carrier_errors + + ;
2005-04-17 02:20:36 +04:00
if ( txstatus & TxOutOfWindow )
2007-10-04 04:41:50 +04:00
dev - > stats . tx_window_errors + + ;
2005-04-17 02:20:36 +04:00
} else {
if ( txstatus & TxUnderrun ) {
/* Add 64 to the Tx FIFO threshold. */
if ( tp - > tx_flag < 0x00300000 )
tp - > tx_flag + = 0x00020000 ;
2007-10-04 04:41:50 +04:00
dev - > stats . tx_fifo_errors + + ;
2005-04-17 02:20:36 +04:00
}
2007-10-04 04:41:50 +04:00
dev - > stats . collisions + = ( txstatus > > 24 ) & 15 ;
dev - > stats . tx_bytes + = txstatus & 0x7ff ;
dev - > stats . tx_packets + + ;
2005-04-17 02:20:36 +04:00
}
/* Free the original skb. */
if ( tp - > tx_info [ entry ] . mapping ! = 0 ) {
pci_unmap_single ( tp - > pci_dev ,
tp - > tx_info [ entry ] . mapping ,
tp - > tx_info [ entry ] . skb - > len ,
PCI_DMA_TODEVICE ) ;
tp - > tx_info [ entry ] . mapping = 0 ;
}
2010-02-17 18:01:55 +03:00
dev_kfree_skb_irq ( tp - > tx_info [ entry ] . skb ) ;
2005-04-17 02:20:36 +04:00
tp - > tx_info [ entry ] . skb = NULL ;
dirty_tx + + ;
if ( dirty_tx < 0 ) { /* handle signed int overflow */
2010-02-17 18:01:55 +03:00
atomic_sub ( cur_tx , & tp - > cur_tx ) ; /* XXX racy? */
2005-04-17 02:20:36 +04:00
dirty_tx = cur_tx - tx_left + 1 ;
}
2010-02-17 18:01:55 +03:00
if ( netif_queue_stopped ( dev ) )
netif_wake_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
cur_tx = atomic_read ( & tp - > cur_tx ) ;
2005-04-17 02:20:36 +04:00
tx_left = cur_tx - dirty_tx ;
}
# ifndef NETDRV_NDEBUG
2010-02-17 18:01:55 +03:00
if ( atomic_read ( & tp - > cur_tx ) - dirty_tx > NUM_TX_DESC ) {
netdev_err ( dev , " Out-of-sync dirty pointer, %d vs. %d \n " ,
dirty_tx , atomic_read ( & tp - > cur_tx ) ) ;
2005-04-17 02:20:36 +04:00
dirty_tx + = NUM_TX_DESC ;
}
# endif /* NETDRV_NDEBUG */
2010-02-17 18:01:55 +03:00
atomic_set ( & tp - > dirty_tx , dirty_tx ) ;
2005-04-17 02:20:36 +04:00
}
/* TODO: clean this up! Rx reset need not be this intensive */
2010-02-17 18:01:55 +03:00
static void netdrv_rx_err ( u32 rx_status , struct net_device * dev ,
struct netdrv_private * tp , void * ioaddr )
2005-04-17 02:20:36 +04:00
{
u8 tmp8 ;
int tmp_work = 1000 ;
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Ethernet frame had errors, status %08x \n " , rx_status ) ;
if ( rx_status & RxTooLong )
netdev_dbg ( dev , " Oversized Ethernet frame, status %04x! \n " ,
rx_status ) ;
2005-04-17 02:20:36 +04:00
/* A.C.: The chip hangs here. */
2007-10-04 04:41:50 +04:00
dev - > stats . rx_errors + + ;
2005-04-17 02:20:36 +04:00
if ( rx_status & ( RxBadSymbol | RxBadAlign ) )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_frame_errors + + ;
2005-04-17 02:20:36 +04:00
if ( rx_status & ( RxRunt | RxTooLong ) )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_length_errors + + ;
2005-04-17 02:20:36 +04:00
if ( rx_status & RxCRCErr )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_crc_errors + + ;
2010-02-17 18:01:55 +03:00
/* Reset the receiver, based on RealTek recommendation.(Bug?) */
2005-04-17 02:20:36 +04:00
tp - > cur_rx = 0 ;
/* disable receive */
2010-02-17 18:01:55 +03:00
tmp8 = NETDRV_R8 ( ChipCmd ) & ChipCmdClear ;
NETDRV_W8_F ( ChipCmd , tmp8 | CmdTxEnb ) ;
2005-04-17 02:20:36 +04:00
/* A.C.: Reset the multicast list. */
2010-02-17 18:01:55 +03:00
netdrv_set_rx_mode ( dev ) ;
2005-04-17 02:20:36 +04:00
/* XXX potentially temporary hack to
* restart hung receiver */
while ( - - tmp_work > 0 ) {
2010-02-17 18:01:55 +03:00
tmp8 = NETDRV_R8 ( ChipCmd ) ;
2005-04-17 02:20:36 +04:00
if ( ( tmp8 & CmdRxEnb ) & & ( tmp8 & CmdTxEnb ) )
break ;
2010-02-17 18:01:55 +03:00
NETDRV_W8_F ( ChipCmd ,
( tmp8 & ChipCmdClear ) | CmdRxEnb | CmdTxEnb ) ;
2005-04-17 02:20:36 +04:00
}
/* G.S.: Re-enable receiver */
/* XXX temporary hack to work around receiver hang */
2010-02-17 18:01:55 +03:00
netdrv_set_rx_mode ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( tmp_work < = 0 )
2010-02-17 18:01:55 +03:00
netdev_warn ( dev , " tx/rx enable wait too long \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
field alignments and semantics . */
2010-02-17 18:01:55 +03:00
static void netdrv_rx_interrupt ( struct net_device * dev ,
struct netdrv_private * tp , void * ioaddr )
2005-04-17 02:20:36 +04:00
{
unsigned char * rx_ring ;
u16 cur_rx ;
2010-02-17 18:01:55 +03:00
assert ( dev ! = NULL ) ;
assert ( tp ! = NULL ) ;
assert ( ioaddr ! = NULL ) ;
2005-04-17 02:20:36 +04:00
rx_ring = tp - > rx_ring ;
cur_rx = tp - > cur_rx ;
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " In netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x \n " ,
cur_rx , NETDRV_R16 ( RxBufAddr ) ,
NETDRV_R16 ( RxBufPtr ) , NETDRV_R8 ( ChipCmd ) ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
while ( ( NETDRV_R8 ( ChipCmd ) & RxBufEmpty ) = = 0 ) {
2005-04-17 02:20:36 +04:00
int ring_offset = cur_rx % RX_BUF_LEN ;
u32 rx_status ;
unsigned int rx_size ;
unsigned int pkt_size ;
struct sk_buff * skb ;
/* read size+status of next frame from DMA ring buffer */
2010-02-17 18:01:55 +03:00
rx_status = le32_to_cpu ( * ( u32 * ) ( rx_ring + ring_offset ) ) ;
2005-04-17 02:20:36 +04:00
rx_size = rx_status > > 16 ;
pkt_size = rx_size - 4 ;
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " netdrv_rx() status %04x, size %04x, cur %04x \n " ,
rx_status , rx_size , cur_rx ) ;
2008-01-24 09:51:36 +03:00
# if defined(NETDRV_DEBUG) && (NETDRV_DEBUG > 2)
2010-02-17 18:01:55 +03:00
print_hex_dump_bytes ( " Frame contents: " , HEX_DUMP_OFFSET ,
& rx_ring [ ring_offset ] , 70 ) ;
2005-04-17 02:20:36 +04:00
# endif
/* If Rx err or invalid rx_size/rx_status received
2010-02-17 18:01:55 +03:00
* ( which happens if we get lost in the ring ) ,
2005-04-17 02:20:36 +04:00
* Rx process gets reset , so we abort any further
* Rx processing .
*/
if ( ( rx_size > ( MAX_ETH_FRAME_SIZE + 4 ) ) | |
( ! ( rx_status & RxStatusOK ) ) ) {
2010-02-17 18:01:55 +03:00
netdrv_rx_err ( rx_status , dev , tp , ioaddr ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
/* TODO: consider allocating skb's outside of
* interrupt context , both to speed interrupt processing ,
* and also to reduce the chances of having to
* drop packets here under memory pressure .
*/
2010-02-17 18:01:55 +03:00
skb = dev_alloc_skb ( pkt_size + 2 ) ;
2005-04-17 02:20:36 +04:00
if ( skb ) {
2010-02-17 18:01:55 +03:00
skb_reserve ( skb , 2 ) ; /* 16 byte align the IP fields. */
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
skb_copy_to_linear_data ( skb , & rx_ring [ ring_offset + 4 ] , pkt_size ) ;
skb_put ( skb , pkt_size ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
skb - > protocol = eth_type_trans ( skb , dev ) ;
netif_rx ( skb ) ;
2007-10-04 04:41:50 +04:00
dev - > stats . rx_bytes + = pkt_size ;
dev - > stats . rx_packets + + ;
2005-04-17 02:20:36 +04:00
} else {
2010-02-17 18:01:55 +03:00
netdev_warn ( dev , " Memory squeeze, dropping packet \n " ) ;
2007-10-04 04:41:50 +04:00
dev - > stats . rx_dropped + + ;
2005-04-17 02:20:36 +04:00
}
cur_rx = ( cur_rx + rx_size + 4 + 3 ) & ~ 3 ;
2010-02-17 18:01:55 +03:00
NETDRV_W16_F ( RxBufPtr , cur_rx - 16 ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Done netdrv_rx(), current %04x BufAddr %04x, free to %04x, Cmd %02x \n " ,
cur_rx , NETDRV_R16 ( RxBufAddr ) ,
NETDRV_R16 ( RxBufPtr ) , NETDRV_R8 ( ChipCmd ) ) ;
2005-04-17 02:20:36 +04:00
tp - > cur_rx = cur_rx ;
}
2010-02-17 18:01:55 +03:00
static void netdrv_weird_interrupt ( struct net_device * dev ,
struct netdrv_private * tp ,
void * ioaddr ,
int status , int link_changed )
2005-04-17 02:20:36 +04:00
{
2010-02-17 18:01:55 +03:00
netdev_printk ( KERN_DEBUG , dev , " Abnormal interrupt, status %08x \n " ,
status ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
assert ( dev ! = NULL ) ;
assert ( tp ! = NULL ) ;
assert ( ioaddr ! = NULL ) ;
2005-04-17 02:20:36 +04:00
/* Update the error count. */
2010-02-17 18:01:55 +03:00
dev - > stats . rx_missed_errors + = NETDRV_R32 ( RxMissed ) ;
NETDRV_W32 ( RxMissed , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ( status & RxUnderrun ) & & link_changed & &
( tp - > drv_flags & HAS_LNK_CHNG ) ) {
/* Really link-change on new chips. */
2010-02-17 18:01:55 +03:00
int lpar = NETDRV_R16 ( NWayLPAR ) ;
2009-12-03 10:58:21 +03:00
int duplex = ( ( lpar & 0x0100 ) | | ( lpar & 0x01C0 ) = = 0x0040 | |
2010-02-17 18:01:55 +03:00
tp - > duplex_lock ) ;
2005-04-17 02:20:36 +04:00
if ( tp - > full_duplex ! = duplex ) {
tp - > full_duplex = duplex ;
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( Cfg9346 , Cfg9346_Unlock ) ;
NETDRV_W8 ( Config1 , tp - > full_duplex ? 0x60 : 0x20 ) ;
NETDRV_W8 ( Cfg9346 , Cfg9346_Lock ) ;
2005-04-17 02:20:36 +04:00
}
status & = ~ RxUnderrun ;
}
/* XXX along with netdrv_rx_err, are we double-counting errors? */
2010-02-17 18:01:55 +03:00
if ( status & ( RxUnderrun | RxOverflow | RxErr | RxFIFOOver ) )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_errors + + ;
2005-04-17 02:20:36 +04:00
if ( status & ( PCSTimeout ) )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_length_errors + + ;
2005-04-17 02:20:36 +04:00
if ( status & ( RxUnderrun | RxFIFOOver ) )
2007-10-04 04:41:50 +04:00
dev - > stats . rx_fifo_errors + + ;
2005-04-17 02:20:36 +04:00
if ( status & RxOverflow ) {
2007-10-04 04:41:50 +04:00
dev - > stats . rx_over_errors + + ;
2010-02-17 18:01:55 +03:00
tp - > cur_rx = NETDRV_R16 ( RxBufAddr ) % RX_BUF_LEN ;
NETDRV_W16_F ( RxBufPtr , tp - > cur_rx - 16 ) ;
2005-04-17 02:20:36 +04:00
}
if ( status & PCIErr ) {
u16 pci_cmd_status ;
2010-02-17 18:01:55 +03:00
pci_read_config_word ( tp - > pci_dev , PCI_STATUS , & pci_cmd_status ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_err ( dev , " PCI Bus error %04x \n " , pci_cmd_status ) ;
2005-04-17 02:20:36 +04:00
}
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread . */
2010-02-17 18:01:55 +03:00
static irqreturn_t netdrv_interrupt ( int irq , void * dev_instance )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev = ( struct net_device * ) dev_instance ;
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
int boguscnt = max_interrupt_work ;
void * ioaddr = tp - > mmio_addr ;
int status = 0 , link_changed = 0 ; /* avoid bogus "uninit" warning */
int handled = 0 ;
2010-02-17 18:01:55 +03:00
spin_lock ( & tp - > lock ) ;
2005-04-17 02:20:36 +04:00
do {
2010-02-17 18:01:55 +03:00
status = NETDRV_R16 ( IntrStatus ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
/* h/w no longer present(hotplug?) or major error, bail */
2005-04-17 02:20:36 +04:00
if ( status = = 0xFFFF )
break ;
handled = 1 ;
/* Acknowledge all of the current interrupt sources ASAP */
2010-02-17 18:01:55 +03:00
NETDRV_W16_F ( IntrStatus , status ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " interrupt status=%#04x new intstat=%#04x \n " ,
status , NETDRV_R16 ( IntrStatus ) ) ;
2005-04-17 02:20:36 +04:00
if ( ( status &
( PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
RxFIFOOver | TxErr | TxOK | RxErr | RxOK ) ) = = 0 )
break ;
/* Check uncommon events with one test. */
if ( status & ( PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
2010-02-17 18:01:55 +03:00
RxFIFOOver | TxErr | RxErr ) )
netdrv_weird_interrupt ( dev , tp , ioaddr ,
status , link_changed ) ;
2005-04-17 02:20:36 +04:00
if ( status & ( RxOK | RxUnderrun | RxOverflow | RxFIFOOver ) ) /* Rx interrupt */
2010-02-17 18:01:55 +03:00
netdrv_rx_interrupt ( dev , tp , ioaddr ) ;
2005-04-17 02:20:36 +04:00
if ( status & ( TxOK | TxErr ) )
2010-02-17 18:01:55 +03:00
netdrv_tx_interrupt ( dev , tp , ioaddr ) ;
2005-04-17 02:20:36 +04:00
boguscnt - - ;
} while ( boguscnt > 0 ) ;
if ( boguscnt < = 0 ) {
2010-02-17 18:01:55 +03:00
netdev_warn ( dev , " Too much work at interrupt, IntrStatus=%#04x \n " ,
status ) ;
2005-04-17 02:20:36 +04:00
/* Clear all interrupt sources. */
2010-02-17 18:01:55 +03:00
NETDRV_W16 ( IntrStatus , 0xffff ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
spin_unlock ( & tp - > lock ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " exiting interrupt, intr_status=%#04x \n " ,
NETDRV_R16 ( IntrStatus ) ) ;
2005-04-17 02:20:36 +04:00
return IRQ_RETVAL ( handled ) ;
}
2010-02-17 18:01:55 +03:00
static int netdrv_close ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
unsigned long flags ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netif_stop_queue ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " Shutting down ethercard, status was %#04x \n " ,
NETDRV_R16 ( IntrStatus ) ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
del_timer_sync ( & tp - > timer ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
spin_lock_irqsave ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* Stop the chip's Tx and Rx DMA processes. */
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) ) ;
2005-04-17 02:20:36 +04:00
/* Disable interrupts by clearing the interrupt mask. */
2010-02-17 18:01:55 +03:00
NETDRV_W16 ( IntrMask , 0x0000 ) ;
2005-04-17 02:20:36 +04:00
/* Update the error counts. */
2010-02-17 18:01:55 +03:00
dev - > stats . rx_missed_errors + = NETDRV_R32 ( RxMissed ) ;
NETDRV_W32 ( RxMissed , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
spin_unlock_irqrestore ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
free_irq ( dev - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdrv_tx_clear ( dev ) ;
2005-04-17 02:20:36 +04:00
pci_free_consistent ( tp - > pci_dev , RX_BUF_TOT_LEN ,
tp - > rx_ring , tp - > rx_ring_dma ) ;
pci_free_consistent ( tp - > pci_dev , TX_BUF_TOT_LEN ,
tp - > tx_bufs , tp - > tx_bufs_dma ) ;
tp - > rx_ring = NULL ;
tp - > tx_bufs = NULL ;
/* Green! Put the chip in low-power mode. */
2010-02-17 18:01:55 +03:00
NETDRV_W8 ( Cfg9346 , Cfg9346_Unlock ) ;
NETDRV_W8 ( Config1 , 0x03 ) ;
NETDRV_W8 ( Cfg9346 , Cfg9346_Lock ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-02-17 18:01:55 +03:00
static int netdrv_ioctl ( struct net_device * dev , struct ifreq * rq , int cmd )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
struct mii_ioctl_data * data = if_mii ( rq ) ;
unsigned long flags ;
int rc = 0 ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
switch ( cmd ) {
case SIOCGMIIPHY : /* Get address of MII PHY in use. */
data - > phy_id = tp - > phys [ 0 ] & 0x3f ;
/* Fall Through */
case SIOCGMIIREG : /* Read MII PHY register. */
2010-02-17 18:01:55 +03:00
spin_lock_irqsave ( & tp - > lock , flags ) ;
data - > val_out = mdio_read ( dev , data - > phy_id & 0x1f , data - > reg_num & 0x1f ) ;
spin_unlock_irqrestore ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
break ;
case SIOCSMIIREG : /* Write MII PHY register. */
2010-02-17 18:01:55 +03:00
spin_lock_irqsave ( & tp - > lock , flags ) ;
mdio_write ( dev , data - > phy_id & 0x1f , data - > reg_num & 0x1f , data - > val_in ) ;
spin_unlock_irqrestore ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
rc = - EOPNOTSUPP ;
break ;
}
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT, returning %d \n " , rc ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked . */
2010-02-17 18:01:55 +03:00
static void netdrv_set_rx_mode ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
u32 mc_filter [ 2 ] ; /* Multicast hash filter */
2010-02-23 12:19:49 +03:00
int rx_mode ;
2005-04-17 02:20:36 +04:00
u32 tmp ;
2010-02-17 18:01:55 +03:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
netdev_dbg ( dev , " %s(%04x) done -- Rx config %08lx \n " ,
__func__ , dev - > flags , NETDRV_R32 ( RxConfig ) ) ;
2005-04-17 02:20:36 +04:00
/* Note: do not reorder, GCC is clever about common statements. */
if ( dev - > flags & IFF_PROMISC ) {
rx_mode =
2010-02-17 18:01:55 +03:00
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys ;
2005-04-17 02:20:36 +04:00
mc_filter [ 1 ] = mc_filter [ 0 ] = 0xffffffff ;
2010-02-08 07:30:35 +03:00
} else if ( ( netdev_mc_count ( dev ) > multicast_filter_limit ) | |
2009-12-03 10:58:21 +03:00
( dev - > flags & IFF_ALLMULTI ) ) {
2005-04-17 02:20:36 +04:00
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys ;
mc_filter [ 1 ] = mc_filter [ 0 ] = 0xffffffff ;
} else {
2010-04-02 01:22:57 +04:00
struct netdev_hw_addr * ha ;
2010-02-23 12:19:49 +03:00
2005-04-17 02:20:36 +04:00
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys ;
mc_filter [ 1 ] = mc_filter [ 0 ] = 0 ;
2010-04-02 01:22:57 +04:00
netdev_for_each_mc_addr ( ha , dev ) {
int bit_nr = ether_crc ( ETH_ALEN , ha - > addr ) > > 26 ;
2005-04-17 02:20:36 +04:00
mc_filter [ bit_nr > > 5 ] | = 1 < < ( bit_nr & 31 ) ;
}
}
/* if called from irq handler, lock already acquired */
2010-02-17 18:01:55 +03:00
if ( ! in_irq ( ) )
spin_lock_irq ( & tp - > lock ) ;
2005-04-17 02:20:36 +04:00
/* We can safely update without stopping the chip. */
tmp = netdrv_rx_config | rx_mode |
2010-02-17 18:01:55 +03:00
( NETDRV_R32 ( RxConfig ) & rtl_chip_info [ tp - > chipset ] . RxConfigMask ) ;
NETDRV_W32_F ( RxConfig , tmp ) ;
NETDRV_W32_F ( MAR0 + 0 , mc_filter [ 0 ] ) ;
NETDRV_W32_F ( MAR0 + 4 , mc_filter [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
if ( ! in_irq ( ) )
spin_unlock_irq ( & tp - > lock ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_PM
2010-02-17 18:01:55 +03:00
static int netdrv_suspend ( struct pci_dev * pdev , pm_message_t state )
2005-04-17 02:20:36 +04:00
{
2010-02-17 18:01:55 +03:00
struct net_device * dev = pci_get_drvdata ( pdev ) ;
2008-01-24 09:51:36 +03:00
struct netdrv_private * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
void * ioaddr = tp - > mmio_addr ;
unsigned long flags ;
if ( ! netif_running ( dev ) )
return 0 ;
2010-02-17 18:01:55 +03:00
netif_device_detach ( dev ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
spin_lock_irqsave ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* Disable interrupts, stop Tx and Rx. */
2010-02-17 18:01:55 +03:00
NETDRV_W16 ( IntrMask , 0x0000 ) ;
NETDRV_W8 ( ChipCmd , ( NETDRV_R8 ( ChipCmd ) & ChipCmdClear ) ) ;
2005-04-17 02:20:36 +04:00
/* Update the error counts. */
2010-02-17 18:01:55 +03:00
dev - > stats . rx_missed_errors + = NETDRV_R32 ( RxMissed ) ;
NETDRV_W32 ( RxMissed , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
spin_unlock_irqrestore ( & tp - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2010-02-17 18:01:55 +03:00
pci_save_state ( pdev ) ;
pci_set_power_state ( pdev , PCI_D3hot ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-02-17 18:01:55 +03:00
static int netdrv_resume ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2010-02-17 18:01:55 +03:00
struct net_device * dev = pci_get_drvdata ( pdev ) ;
2008-01-24 09:51:36 +03:00
/*struct netdrv_private *tp = netdev_priv(dev);*/
2005-04-17 02:20:36 +04:00
if ( ! netif_running ( dev ) )
return 0 ;
2010-02-17 18:01:55 +03:00
pci_set_power_state ( pdev , PCI_D0 ) ;
pci_restore_state ( pdev ) ;
netif_device_attach ( dev ) ;
netdrv_hw_start ( dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# endif /* CONFIG_PM */
static struct pci_driver netdrv_pci_driver = {
. name = MODNAME ,
. id_table = netdrv_pci_tbl ,
. probe = netdrv_init_one ,
. remove = __devexit_p ( netdrv_remove_one ) ,
# ifdef CONFIG_PM
. suspend = netdrv_suspend ,
. resume = netdrv_resume ,
# endif /* CONFIG_PM */
} ;
2010-02-17 18:01:55 +03:00
static int __init netdrv_init_module ( void )
2005-04-17 02:20:36 +04:00
{
/* when a module, this is printed whether or not devices are found in probe */
# ifdef MODULE
printk ( version ) ;
# endif
2006-08-20 01:48:59 +04:00
return pci_register_driver ( & netdrv_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
2010-02-17 18:01:55 +03:00
static void __exit netdrv_cleanup_module ( void )
2005-04-17 02:20:36 +04:00
{
2010-02-17 18:01:55 +03:00
pci_unregister_driver ( & netdrv_pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( netdrv_init_module ) ;
module_exit ( netdrv_cleanup_module ) ;