11b6b7172SCesar Eduardo Barros /* Silan SC92031 PCI Fast Ethernet Adapter driver 21b6b7172SCesar Eduardo Barros * 31b6b7172SCesar Eduardo Barros * Based on vendor drivers: 41b6b7172SCesar Eduardo Barros * Silan Fast Ethernet Netcard Driver: 51b6b7172SCesar Eduardo Barros * MODULE_AUTHOR ("gaoyonghong"); 61b6b7172SCesar Eduardo Barros * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver"); 71b6b7172SCesar Eduardo Barros * MODULE_LICENSE("GPL"); 81b6b7172SCesar Eduardo Barros * 8139D Fast Ethernet driver: 91b6b7172SCesar Eduardo Barros * (C) 2002 by gaoyonghong 101b6b7172SCesar Eduardo Barros * MODULE_AUTHOR ("gaoyonghong"); 111b6b7172SCesar Eduardo Barros * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver"); 121b6b7172SCesar Eduardo Barros * MODULE_LICENSE("GPL"); 131b6b7172SCesar Eduardo Barros * Both are almost identical and seem to be based on pci-skeleton.c 141b6b7172SCesar Eduardo Barros * 151b6b7172SCesar Eduardo Barros * Rewritten for 2.6 by Cesar Eduardo Barros 161b6b7172SCesar Eduardo Barros * 171b6b7172SCesar Eduardo Barros * A datasheet for this chip can be found at 181b6b7172SCesar Eduardo Barros * http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf 191b6b7172SCesar Eduardo Barros */ 201b6b7172SCesar Eduardo Barros 211b6b7172SCesar Eduardo Barros /* Note about set_mac_address: I don't know how to change the hardware 221b6b7172SCesar Eduardo Barros * matching, so you need to enable IFF_PROMISC when using it. 231b6b7172SCesar Eduardo Barros */ 241b6b7172SCesar Eduardo Barros 251b6b7172SCesar Eduardo Barros #include <linux/interrupt.h> 261b6b7172SCesar Eduardo Barros #include <linux/module.h> 271b6b7172SCesar Eduardo Barros #include <linux/kernel.h> 281b6b7172SCesar Eduardo Barros #include <linux/delay.h> 291b6b7172SCesar Eduardo Barros #include <linux/pci.h> 301b6b7172SCesar Eduardo Barros #include <linux/dma-mapping.h> 311b6b7172SCesar Eduardo Barros #include <linux/netdevice.h> 321b6b7172SCesar Eduardo Barros #include <linux/etherdevice.h> 331b6b7172SCesar Eduardo Barros #include <linux/ethtool.h> 341b6b7172SCesar Eduardo Barros #include <linux/mii.h> 351b6b7172SCesar Eduardo Barros #include <linux/crc32.h> 361b6b7172SCesar Eduardo Barros 371b6b7172SCesar Eduardo Barros #include <asm/irq.h> 381b6b7172SCesar Eduardo Barros 391b6b7172SCesar Eduardo Barros #define SC92031_NAME "sc92031" 401b6b7172SCesar Eduardo Barros 411b6b7172SCesar Eduardo Barros /* BAR 0 is MMIO, BAR 1 is PIO */ 42c4a9f085SFrancois Romieu #define SC92031_USE_PIO 0 431b6b7172SCesar Eduardo Barros 441b6b7172SCesar Eduardo Barros /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ 451b6b7172SCesar Eduardo Barros static int multicast_filter_limit = 64; 461b6b7172SCesar Eduardo Barros module_param(multicast_filter_limit, int, 0); 471b6b7172SCesar Eduardo Barros MODULE_PARM_DESC(multicast_filter_limit, 481b6b7172SCesar Eduardo Barros "Maximum number of filtered multicast addresses"); 491b6b7172SCesar Eduardo Barros 501b6b7172SCesar Eduardo Barros static int media; 511b6b7172SCesar Eduardo Barros module_param(media, int, 0); 521b6b7172SCesar Eduardo Barros MODULE_PARM_DESC(media, "Media type (0x00 = autodetect," 531b6b7172SCesar Eduardo Barros " 0x01 = 10M half, 0x02 = 10M full," 541b6b7172SCesar Eduardo Barros " 0x04 = 100M half, 0x08 = 100M full)"); 551b6b7172SCesar Eduardo Barros 561b6b7172SCesar Eduardo Barros /* Size of the in-memory receive ring. */ 571b6b7172SCesar Eduardo Barros #define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/ 581b6b7172SCesar Eduardo Barros #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) 591b6b7172SCesar Eduardo Barros 601b6b7172SCesar Eduardo Barros /* Number of Tx descriptor registers. */ 611b6b7172SCesar Eduardo Barros #define NUM_TX_DESC 4 621b6b7172SCesar Eduardo Barros 631b6b7172SCesar Eduardo Barros /* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ 641b6b7172SCesar Eduardo Barros #define MAX_ETH_FRAME_SIZE 1536 651b6b7172SCesar Eduardo Barros 661b6b7172SCesar Eduardo Barros /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ 671b6b7172SCesar Eduardo Barros #define TX_BUF_SIZE MAX_ETH_FRAME_SIZE 681b6b7172SCesar Eduardo Barros #define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) 691b6b7172SCesar Eduardo Barros 701b6b7172SCesar Eduardo Barros /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ 711b6b7172SCesar Eduardo Barros #define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ 721b6b7172SCesar Eduardo Barros 731b6b7172SCesar Eduardo Barros /* Time in jiffies before concluding the transmitter is hung. */ 741b6b7172SCesar Eduardo Barros #define TX_TIMEOUT (4*HZ) 751b6b7172SCesar Eduardo Barros 761b6b7172SCesar Eduardo Barros #define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */ 771b6b7172SCesar Eduardo Barros 781b6b7172SCesar Eduardo Barros /* media options */ 791b6b7172SCesar Eduardo Barros #define AUTOSELECT 0x00 801b6b7172SCesar Eduardo Barros #define M10_HALF 0x01 811b6b7172SCesar Eduardo Barros #define M10_FULL 0x02 821b6b7172SCesar Eduardo Barros #define M100_HALF 0x04 831b6b7172SCesar Eduardo Barros #define M100_FULL 0x08 841b6b7172SCesar Eduardo Barros 851b6b7172SCesar Eduardo Barros /* Symbolic offsets to registers. */ 861b6b7172SCesar Eduardo Barros enum silan_registers { 871b6b7172SCesar Eduardo Barros Config0 = 0x00, // Config0 881b6b7172SCesar Eduardo Barros Config1 = 0x04, // Config1 891b6b7172SCesar Eduardo Barros RxBufWPtr = 0x08, // Rx buffer writer poiter 901b6b7172SCesar Eduardo Barros IntrStatus = 0x0C, // Interrupt status 911b6b7172SCesar Eduardo Barros IntrMask = 0x10, // Interrupt mask 921b6b7172SCesar Eduardo Barros RxbufAddr = 0x14, // Rx buffer start address 931b6b7172SCesar Eduardo Barros RxBufRPtr = 0x18, // Rx buffer read pointer 941b6b7172SCesar Eduardo Barros Txstatusall = 0x1C, // Transmit status of all descriptors 951b6b7172SCesar Eduardo Barros TxStatus0 = 0x20, // Transmit status (Four 32bit registers). 961b6b7172SCesar Eduardo Barros TxAddr0 = 0x30, // Tx descriptors (also four 32bit). 971b6b7172SCesar Eduardo Barros RxConfig = 0x40, // Rx configuration 981b6b7172SCesar Eduardo Barros MAC0 = 0x44, // Ethernet hardware address. 991b6b7172SCesar Eduardo Barros MAR0 = 0x4C, // Multicast filter. 1001b6b7172SCesar Eduardo Barros RxStatus0 = 0x54, // Rx status 1011b6b7172SCesar Eduardo Barros TxConfig = 0x5C, // Tx configuration 1021b6b7172SCesar Eduardo Barros PhyCtrl = 0x60, // physical control 1031b6b7172SCesar Eduardo Barros FlowCtrlConfig = 0x64, // flow control 1041b6b7172SCesar Eduardo Barros Miicmd0 = 0x68, // Mii command0 register 1051b6b7172SCesar Eduardo Barros Miicmd1 = 0x6C, // Mii command1 register 1061b6b7172SCesar Eduardo Barros Miistatus = 0x70, // Mii status register 1071b6b7172SCesar Eduardo Barros Timercnt = 0x74, // Timer counter register 1081b6b7172SCesar Eduardo Barros TimerIntr = 0x78, // Timer interrupt register 1091b6b7172SCesar Eduardo Barros PMConfig = 0x7C, // Power Manager configuration 1101b6b7172SCesar Eduardo Barros CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers) 1111b6b7172SCesar Eduardo Barros Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser) 1121b6b7172SCesar Eduardo Barros LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser) 1131b6b7172SCesar Eduardo Barros TestD0 = 0xD0, 1141b6b7172SCesar Eduardo Barros TestD4 = 0xD4, 1151b6b7172SCesar Eduardo Barros TestD8 = 0xD8, 1161b6b7172SCesar Eduardo Barros }; 1171b6b7172SCesar Eduardo Barros 1181b6b7172SCesar Eduardo Barros #define MII_JAB 16 1191b6b7172SCesar Eduardo Barros #define MII_OutputStatus 24 1201b6b7172SCesar Eduardo Barros 1211b6b7172SCesar Eduardo Barros #define PHY_16_JAB_ENB 0x1000 1221b6b7172SCesar Eduardo Barros #define PHY_16_PORT_ENB 0x1 1231b6b7172SCesar Eduardo Barros 1241b6b7172SCesar Eduardo Barros enum IntrStatusBits { 1251b6b7172SCesar Eduardo Barros LinkFail = 0x80000000, 1261b6b7172SCesar Eduardo Barros LinkOK = 0x40000000, 1271b6b7172SCesar Eduardo Barros TimeOut = 0x20000000, 1281b6b7172SCesar Eduardo Barros RxOverflow = 0x0040, 1291b6b7172SCesar Eduardo Barros RxOK = 0x0020, 1301b6b7172SCesar Eduardo Barros TxOK = 0x0001, 1311b6b7172SCesar Eduardo Barros IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK, 1321b6b7172SCesar Eduardo Barros }; 1331b6b7172SCesar Eduardo Barros 1341b6b7172SCesar Eduardo Barros enum TxStatusBits { 1351b6b7172SCesar Eduardo Barros TxCarrierLost = 0x20000000, 1361b6b7172SCesar Eduardo Barros TxAborted = 0x10000000, 1371b6b7172SCesar Eduardo Barros TxOutOfWindow = 0x08000000, 1381b6b7172SCesar Eduardo Barros TxNccShift = 22, 1391b6b7172SCesar Eduardo Barros EarlyTxThresShift = 16, 1401b6b7172SCesar Eduardo Barros TxStatOK = 0x8000, 1411b6b7172SCesar Eduardo Barros TxUnderrun = 0x4000, 1421b6b7172SCesar Eduardo Barros TxOwn = 0x2000, 1431b6b7172SCesar Eduardo Barros }; 1441b6b7172SCesar Eduardo Barros 1451b6b7172SCesar Eduardo Barros enum RxStatusBits { 1461b6b7172SCesar Eduardo Barros RxStatesOK = 0x80000, 1471b6b7172SCesar Eduardo Barros RxBadAlign = 0x40000, 1481b6b7172SCesar Eduardo Barros RxHugeFrame = 0x20000, 1491b6b7172SCesar Eduardo Barros RxSmallFrame = 0x10000, 1501b6b7172SCesar Eduardo Barros RxCRCOK = 0x8000, 1511b6b7172SCesar Eduardo Barros RxCrlFrame = 0x4000, 1521b6b7172SCesar Eduardo Barros Rx_Broadcast = 0x2000, 1531b6b7172SCesar Eduardo Barros Rx_Multicast = 0x1000, 1541b6b7172SCesar Eduardo Barros RxAddrMatch = 0x0800, 1551b6b7172SCesar Eduardo Barros MiiErr = 0x0400, 1561b6b7172SCesar Eduardo Barros }; 1571b6b7172SCesar Eduardo Barros 1581b6b7172SCesar Eduardo Barros enum RxConfigBits { 1591b6b7172SCesar Eduardo Barros RxFullDx = 0x80000000, 1601b6b7172SCesar Eduardo Barros RxEnb = 0x40000000, 1611b6b7172SCesar Eduardo Barros RxSmall = 0x20000000, 1621b6b7172SCesar Eduardo Barros RxHuge = 0x10000000, 1631b6b7172SCesar Eduardo Barros RxErr = 0x08000000, 1641b6b7172SCesar Eduardo Barros RxAllphys = 0x04000000, 1651b6b7172SCesar Eduardo Barros RxMulticast = 0x02000000, 1661b6b7172SCesar Eduardo Barros RxBroadcast = 0x01000000, 1671b6b7172SCesar Eduardo Barros RxLoopBack = (1 << 23) | (1 << 22), 1681b6b7172SCesar Eduardo Barros LowThresholdShift = 12, 1691b6b7172SCesar Eduardo Barros HighThresholdShift = 2, 1701b6b7172SCesar Eduardo Barros }; 1711b6b7172SCesar Eduardo Barros 1721b6b7172SCesar Eduardo Barros enum TxConfigBits { 1731b6b7172SCesar Eduardo Barros TxFullDx = 0x80000000, 1741b6b7172SCesar Eduardo Barros TxEnb = 0x40000000, 1751b6b7172SCesar Eduardo Barros TxEnbPad = 0x20000000, 1761b6b7172SCesar Eduardo Barros TxEnbHuge = 0x10000000, 1771b6b7172SCesar Eduardo Barros TxEnbFCS = 0x08000000, 1781b6b7172SCesar Eduardo Barros TxNoBackOff = 0x04000000, 1791b6b7172SCesar Eduardo Barros TxEnbPrem = 0x02000000, 1801b6b7172SCesar Eduardo Barros TxCareLostCrs = 0x1000000, 1811b6b7172SCesar Eduardo Barros TxExdCollNum = 0xf00000, 1821b6b7172SCesar Eduardo Barros TxDataRate = 0x80000, 1831b6b7172SCesar Eduardo Barros }; 1841b6b7172SCesar Eduardo Barros 1851b6b7172SCesar Eduardo Barros enum PhyCtrlconfigbits { 1861b6b7172SCesar Eduardo Barros PhyCtrlAne = 0x80000000, 1871b6b7172SCesar Eduardo Barros PhyCtrlSpd100 = 0x40000000, 1881b6b7172SCesar Eduardo Barros PhyCtrlSpd10 = 0x20000000, 1891b6b7172SCesar Eduardo Barros PhyCtrlPhyBaseAddr = 0x1f000000, 1901b6b7172SCesar Eduardo Barros PhyCtrlDux = 0x800000, 1911b6b7172SCesar Eduardo Barros PhyCtrlReset = 0x400000, 1921b6b7172SCesar Eduardo Barros }; 1931b6b7172SCesar Eduardo Barros 1941b6b7172SCesar Eduardo Barros enum FlowCtrlConfigBits { 1951b6b7172SCesar Eduardo Barros FlowCtrlFullDX = 0x80000000, 1961b6b7172SCesar Eduardo Barros FlowCtrlEnb = 0x40000000, 1971b6b7172SCesar Eduardo Barros }; 1981b6b7172SCesar Eduardo Barros 1991b6b7172SCesar Eduardo Barros enum Config0Bits { 2001b6b7172SCesar Eduardo Barros Cfg0_Reset = 0x80000000, 2011b6b7172SCesar Eduardo Barros Cfg0_Anaoff = 0x40000000, 2021b6b7172SCesar Eduardo Barros Cfg0_LDPS = 0x20000000, 2031b6b7172SCesar Eduardo Barros }; 2041b6b7172SCesar Eduardo Barros 2051b6b7172SCesar Eduardo Barros enum Config1Bits { 2061b6b7172SCesar Eduardo Barros Cfg1_EarlyRx = 1 << 31, 2071b6b7172SCesar Eduardo Barros Cfg1_EarlyTx = 1 << 30, 2081b6b7172SCesar Eduardo Barros 2091b6b7172SCesar Eduardo Barros //rx buffer size 2101b6b7172SCesar Eduardo Barros Cfg1_Rcv8K = 0x0, 2111b6b7172SCesar Eduardo Barros Cfg1_Rcv16K = 0x1, 2121b6b7172SCesar Eduardo Barros Cfg1_Rcv32K = 0x3, 2131b6b7172SCesar Eduardo Barros Cfg1_Rcv64K = 0x7, 2141b6b7172SCesar Eduardo Barros Cfg1_Rcv128K = 0xf, 2151b6b7172SCesar Eduardo Barros }; 2161b6b7172SCesar Eduardo Barros 2171b6b7172SCesar Eduardo Barros enum MiiCmd0Bits { 2181b6b7172SCesar Eduardo Barros Mii_Divider = 0x20000000, 2191b6b7172SCesar Eduardo Barros Mii_WRITE = 0x400000, 2201b6b7172SCesar Eduardo Barros Mii_READ = 0x200000, 2211b6b7172SCesar Eduardo Barros Mii_SCAN = 0x100000, 2221b6b7172SCesar Eduardo Barros Mii_Tamod = 0x80000, 2231b6b7172SCesar Eduardo Barros Mii_Drvmod = 0x40000, 2241b6b7172SCesar Eduardo Barros Mii_mdc = 0x20000, 2251b6b7172SCesar Eduardo Barros Mii_mdoen = 0x10000, 2261b6b7172SCesar Eduardo Barros Mii_mdo = 0x8000, 2271b6b7172SCesar Eduardo Barros Mii_mdi = 0x4000, 2281b6b7172SCesar Eduardo Barros }; 2291b6b7172SCesar Eduardo Barros 2301b6b7172SCesar Eduardo Barros enum MiiStatusBits { 2311b6b7172SCesar Eduardo Barros Mii_StatusBusy = 0x80000000, 2321b6b7172SCesar Eduardo Barros }; 2331b6b7172SCesar Eduardo Barros 2341b6b7172SCesar Eduardo Barros enum PMConfigBits { 2351b6b7172SCesar Eduardo Barros PM_Enable = 1 << 31, 2361b6b7172SCesar Eduardo Barros PM_LongWF = 1 << 30, 2371b6b7172SCesar Eduardo Barros PM_Magic = 1 << 29, 2381b6b7172SCesar Eduardo Barros PM_LANWake = 1 << 28, 2391b6b7172SCesar Eduardo Barros PM_LWPTN = (1 << 27 | 1<< 26), 2401b6b7172SCesar Eduardo Barros PM_LinkUp = 1 << 25, 2411b6b7172SCesar Eduardo Barros PM_WakeUp = 1 << 24, 2421b6b7172SCesar Eduardo Barros }; 2431b6b7172SCesar Eduardo Barros 2441b6b7172SCesar Eduardo Barros /* Locking rules: 2451b6b7172SCesar Eduardo Barros * priv->lock protects most of the fields of priv and most of the 2461b6b7172SCesar Eduardo Barros * hardware registers. It does not have to protect against softirqs 2471b6b7172SCesar Eduardo Barros * between sc92031_disable_interrupts and sc92031_enable_interrupts; 2481b6b7172SCesar Eduardo Barros * it also does not need to be used in ->open and ->stop while the 2491b6b7172SCesar Eduardo Barros * device interrupts are off. 2501b6b7172SCesar Eduardo Barros * Not having to protect against softirqs is very useful due to heavy 2511b6b7172SCesar Eduardo Barros * use of mdelay() at _sc92031_reset. 2521b6b7172SCesar Eduardo Barros * Functions prefixed with _sc92031_ must be called with the lock held; 2531b6b7172SCesar Eduardo Barros * functions prefixed with sc92031_ must be called without the lock held. 2541b6b7172SCesar Eduardo Barros * Use mmiowb() before unlocking if the hardware was written to. 2551b6b7172SCesar Eduardo Barros */ 2561b6b7172SCesar Eduardo Barros 2571b6b7172SCesar Eduardo Barros /* Locking rules for the interrupt: 2581b6b7172SCesar Eduardo Barros * - the interrupt and the tasklet never run at the same time 2591b6b7172SCesar Eduardo Barros * - neither run between sc92031_disable_interrupts and 2601b6b7172SCesar Eduardo Barros * sc92031_enable_interrupt 2611b6b7172SCesar Eduardo Barros */ 2621b6b7172SCesar Eduardo Barros 2631b6b7172SCesar Eduardo Barros struct sc92031_priv { 2641b6b7172SCesar Eduardo Barros spinlock_t lock; 2651b6b7172SCesar Eduardo Barros /* iomap.h cookie */ 2661b6b7172SCesar Eduardo Barros void __iomem *port_base; 2671b6b7172SCesar Eduardo Barros /* pci device structure */ 2681b6b7172SCesar Eduardo Barros struct pci_dev *pdev; 2691b6b7172SCesar Eduardo Barros /* tasklet */ 2701b6b7172SCesar Eduardo Barros struct tasklet_struct tasklet; 2711b6b7172SCesar Eduardo Barros 2721b6b7172SCesar Eduardo Barros /* CPU address of rx ring */ 2731b6b7172SCesar Eduardo Barros void *rx_ring; 2741b6b7172SCesar Eduardo Barros /* PCI address of rx ring */ 2751b6b7172SCesar Eduardo Barros dma_addr_t rx_ring_dma_addr; 2761b6b7172SCesar Eduardo Barros /* PCI address of rx ring read pointer */ 2771b6b7172SCesar Eduardo Barros dma_addr_t rx_ring_tail; 2781b6b7172SCesar Eduardo Barros 2791b6b7172SCesar Eduardo Barros /* tx ring write index */ 2801b6b7172SCesar Eduardo Barros unsigned tx_head; 2811b6b7172SCesar Eduardo Barros /* tx ring read index */ 2821b6b7172SCesar Eduardo Barros unsigned tx_tail; 2831b6b7172SCesar Eduardo Barros /* CPU address of tx bounce buffer */ 2841b6b7172SCesar Eduardo Barros void *tx_bufs; 2851b6b7172SCesar Eduardo Barros /* PCI address of tx bounce buffer */ 2861b6b7172SCesar Eduardo Barros dma_addr_t tx_bufs_dma_addr; 2871b6b7172SCesar Eduardo Barros 2881b6b7172SCesar Eduardo Barros /* copies of some hardware registers */ 2891b6b7172SCesar Eduardo Barros u32 intr_status; 2901b6b7172SCesar Eduardo Barros atomic_t intr_mask; 2911b6b7172SCesar Eduardo Barros u32 rx_config; 2921b6b7172SCesar Eduardo Barros u32 tx_config; 2931b6b7172SCesar Eduardo Barros u32 pm_config; 2941b6b7172SCesar Eduardo Barros 2951b6b7172SCesar Eduardo Barros /* copy of some flags from dev->flags */ 2961b6b7172SCesar Eduardo Barros unsigned int mc_flags; 2971b6b7172SCesar Eduardo Barros 2981b6b7172SCesar Eduardo Barros /* for ETHTOOL_GSTATS */ 2991b6b7172SCesar Eduardo Barros u64 tx_timeouts; 3001b6b7172SCesar Eduardo Barros u64 rx_loss; 3011b6b7172SCesar Eduardo Barros 3021b6b7172SCesar Eduardo Barros /* for dev->get_stats */ 3031b6b7172SCesar Eduardo Barros long rx_value; 3041b6b7172SCesar Eduardo Barros }; 3051b6b7172SCesar Eduardo Barros 3061b6b7172SCesar Eduardo Barros /* I don't know which registers can be safely read; however, I can guess 3071b6b7172SCesar Eduardo Barros * MAC0 is one of them. */ 3081b6b7172SCesar Eduardo Barros static inline void _sc92031_dummy_read(void __iomem *port_base) 3091b6b7172SCesar Eduardo Barros { 3101b6b7172SCesar Eduardo Barros ioread32(port_base + MAC0); 3111b6b7172SCesar Eduardo Barros } 3121b6b7172SCesar Eduardo Barros 3131b6b7172SCesar Eduardo Barros static u32 _sc92031_mii_wait(void __iomem *port_base) 3141b6b7172SCesar Eduardo Barros { 3151b6b7172SCesar Eduardo Barros u32 mii_status; 3161b6b7172SCesar Eduardo Barros 3171b6b7172SCesar Eduardo Barros do { 3181b6b7172SCesar Eduardo Barros udelay(10); 3191b6b7172SCesar Eduardo Barros mii_status = ioread32(port_base + Miistatus); 3201b6b7172SCesar Eduardo Barros } while (mii_status & Mii_StatusBusy); 3211b6b7172SCesar Eduardo Barros 3221b6b7172SCesar Eduardo Barros return mii_status; 3231b6b7172SCesar Eduardo Barros } 3241b6b7172SCesar Eduardo Barros 3251b6b7172SCesar Eduardo Barros static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1) 3261b6b7172SCesar Eduardo Barros { 3271b6b7172SCesar Eduardo Barros iowrite32(Mii_Divider, port_base + Miicmd0); 3281b6b7172SCesar Eduardo Barros 3291b6b7172SCesar Eduardo Barros _sc92031_mii_wait(port_base); 3301b6b7172SCesar Eduardo Barros 3311b6b7172SCesar Eduardo Barros iowrite32(cmd1, port_base + Miicmd1); 3321b6b7172SCesar Eduardo Barros iowrite32(Mii_Divider | cmd0, port_base + Miicmd0); 3331b6b7172SCesar Eduardo Barros 3341b6b7172SCesar Eduardo Barros return _sc92031_mii_wait(port_base); 3351b6b7172SCesar Eduardo Barros } 3361b6b7172SCesar Eduardo Barros 3371b6b7172SCesar Eduardo Barros static void _sc92031_mii_scan(void __iomem *port_base) 3381b6b7172SCesar Eduardo Barros { 3391b6b7172SCesar Eduardo Barros _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6); 3401b6b7172SCesar Eduardo Barros } 3411b6b7172SCesar Eduardo Barros 3421b6b7172SCesar Eduardo Barros static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg) 3431b6b7172SCesar Eduardo Barros { 3441b6b7172SCesar Eduardo Barros return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13; 3451b6b7172SCesar Eduardo Barros } 3461b6b7172SCesar Eduardo Barros 3471b6b7172SCesar Eduardo Barros static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val) 3481b6b7172SCesar Eduardo Barros { 3491b6b7172SCesar Eduardo Barros _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11)); 3501b6b7172SCesar Eduardo Barros } 3511b6b7172SCesar Eduardo Barros 3521b6b7172SCesar Eduardo Barros static void sc92031_disable_interrupts(struct net_device *dev) 3531b6b7172SCesar Eduardo Barros { 3541b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 3551b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 3561b6b7172SCesar Eduardo Barros 3571b6b7172SCesar Eduardo Barros /* tell the tasklet/interrupt not to enable interrupts */ 3581b6b7172SCesar Eduardo Barros atomic_set(&priv->intr_mask, 0); 3591b6b7172SCesar Eduardo Barros wmb(); 3601b6b7172SCesar Eduardo Barros 3611b6b7172SCesar Eduardo Barros /* stop interrupts */ 3621b6b7172SCesar Eduardo Barros iowrite32(0, port_base + IntrMask); 3631b6b7172SCesar Eduardo Barros _sc92031_dummy_read(port_base); 3641b6b7172SCesar Eduardo Barros mmiowb(); 3651b6b7172SCesar Eduardo Barros 3661b6b7172SCesar Eduardo Barros /* wait for any concurrent interrupt/tasklet to finish */ 367c4a9f085SFrancois Romieu synchronize_irq(priv->pdev->irq); 3681b6b7172SCesar Eduardo Barros tasklet_disable(&priv->tasklet); 3691b6b7172SCesar Eduardo Barros } 3701b6b7172SCesar Eduardo Barros 3711b6b7172SCesar Eduardo Barros static void sc92031_enable_interrupts(struct net_device *dev) 3721b6b7172SCesar Eduardo Barros { 3731b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 3741b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 3751b6b7172SCesar Eduardo Barros 3761b6b7172SCesar Eduardo Barros tasklet_enable(&priv->tasklet); 3771b6b7172SCesar Eduardo Barros 3781b6b7172SCesar Eduardo Barros atomic_set(&priv->intr_mask, IntrBits); 3791b6b7172SCesar Eduardo Barros wmb(); 3801b6b7172SCesar Eduardo Barros 3811b6b7172SCesar Eduardo Barros iowrite32(IntrBits, port_base + IntrMask); 3821b6b7172SCesar Eduardo Barros mmiowb(); 3831b6b7172SCesar Eduardo Barros } 3841b6b7172SCesar Eduardo Barros 3851b6b7172SCesar Eduardo Barros static void _sc92031_disable_tx_rx(struct net_device *dev) 3861b6b7172SCesar Eduardo Barros { 3871b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 3881b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 3891b6b7172SCesar Eduardo Barros 3901b6b7172SCesar Eduardo Barros priv->rx_config &= ~RxEnb; 3911b6b7172SCesar Eduardo Barros priv->tx_config &= ~TxEnb; 3921b6b7172SCesar Eduardo Barros iowrite32(priv->rx_config, port_base + RxConfig); 3931b6b7172SCesar Eduardo Barros iowrite32(priv->tx_config, port_base + TxConfig); 3941b6b7172SCesar Eduardo Barros } 3951b6b7172SCesar Eduardo Barros 3961b6b7172SCesar Eduardo Barros static void _sc92031_enable_tx_rx(struct net_device *dev) 3971b6b7172SCesar Eduardo Barros { 3981b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 3991b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 4001b6b7172SCesar Eduardo Barros 4011b6b7172SCesar Eduardo Barros priv->rx_config |= RxEnb; 4021b6b7172SCesar Eduardo Barros priv->tx_config |= TxEnb; 4031b6b7172SCesar Eduardo Barros iowrite32(priv->rx_config, port_base + RxConfig); 4041b6b7172SCesar Eduardo Barros iowrite32(priv->tx_config, port_base + TxConfig); 4051b6b7172SCesar Eduardo Barros } 4061b6b7172SCesar Eduardo Barros 4071b6b7172SCesar Eduardo Barros static void _sc92031_tx_clear(struct net_device *dev) 4081b6b7172SCesar Eduardo Barros { 4091b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 4101b6b7172SCesar Eduardo Barros 4111b6b7172SCesar Eduardo Barros while (priv->tx_head - priv->tx_tail > 0) { 4121b6b7172SCesar Eduardo Barros priv->tx_tail++; 4131b6b7172SCesar Eduardo Barros dev->stats.tx_dropped++; 4141b6b7172SCesar Eduardo Barros } 4151b6b7172SCesar Eduardo Barros priv->tx_head = priv->tx_tail = 0; 4161b6b7172SCesar Eduardo Barros } 4171b6b7172SCesar Eduardo Barros 4181b6b7172SCesar Eduardo Barros static void _sc92031_set_mar(struct net_device *dev) 4191b6b7172SCesar Eduardo Barros { 4201b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 4211b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 4221b6b7172SCesar Eduardo Barros u32 mar0 = 0, mar1 = 0; 4231b6b7172SCesar Eduardo Barros 4241b6b7172SCesar Eduardo Barros if ((dev->flags & IFF_PROMISC) || 4251b6b7172SCesar Eduardo Barros netdev_mc_count(dev) > multicast_filter_limit || 4261b6b7172SCesar Eduardo Barros (dev->flags & IFF_ALLMULTI)) 4271b6b7172SCesar Eduardo Barros mar0 = mar1 = 0xffffffff; 4281b6b7172SCesar Eduardo Barros else if (dev->flags & IFF_MULTICAST) { 4291b6b7172SCesar Eduardo Barros struct netdev_hw_addr *ha; 4301b6b7172SCesar Eduardo Barros 4311b6b7172SCesar Eduardo Barros netdev_for_each_mc_addr(ha, dev) { 4321b6b7172SCesar Eduardo Barros u32 crc; 4331b6b7172SCesar Eduardo Barros unsigned bit = 0; 4341b6b7172SCesar Eduardo Barros 4351b6b7172SCesar Eduardo Barros crc = ~ether_crc(ETH_ALEN, ha->addr); 4361b6b7172SCesar Eduardo Barros crc >>= 24; 4371b6b7172SCesar Eduardo Barros 4381b6b7172SCesar Eduardo Barros if (crc & 0x01) bit |= 0x02; 4391b6b7172SCesar Eduardo Barros if (crc & 0x02) bit |= 0x01; 4401b6b7172SCesar Eduardo Barros if (crc & 0x10) bit |= 0x20; 4411b6b7172SCesar Eduardo Barros if (crc & 0x20) bit |= 0x10; 4421b6b7172SCesar Eduardo Barros if (crc & 0x40) bit |= 0x08; 4431b6b7172SCesar Eduardo Barros if (crc & 0x80) bit |= 0x04; 4441b6b7172SCesar Eduardo Barros 4451b6b7172SCesar Eduardo Barros if (bit > 31) 4461b6b7172SCesar Eduardo Barros mar0 |= 0x1 << (bit - 32); 4471b6b7172SCesar Eduardo Barros else 4481b6b7172SCesar Eduardo Barros mar1 |= 0x1 << bit; 4491b6b7172SCesar Eduardo Barros } 4501b6b7172SCesar Eduardo Barros } 4511b6b7172SCesar Eduardo Barros 4521b6b7172SCesar Eduardo Barros iowrite32(mar0, port_base + MAR0); 4531b6b7172SCesar Eduardo Barros iowrite32(mar1, port_base + MAR0 + 4); 4541b6b7172SCesar Eduardo Barros } 4551b6b7172SCesar Eduardo Barros 4561b6b7172SCesar Eduardo Barros static void _sc92031_set_rx_config(struct net_device *dev) 4571b6b7172SCesar Eduardo Barros { 4581b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 4591b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 4601b6b7172SCesar Eduardo Barros unsigned int old_mc_flags; 4611b6b7172SCesar Eduardo Barros u32 rx_config_bits = 0; 4621b6b7172SCesar Eduardo Barros 4631b6b7172SCesar Eduardo Barros old_mc_flags = priv->mc_flags; 4641b6b7172SCesar Eduardo Barros 4651b6b7172SCesar Eduardo Barros if (dev->flags & IFF_PROMISC) 4661b6b7172SCesar Eduardo Barros rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast 4671b6b7172SCesar Eduardo Barros | RxMulticast | RxAllphys; 4681b6b7172SCesar Eduardo Barros 4691b6b7172SCesar Eduardo Barros if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) 4701b6b7172SCesar Eduardo Barros rx_config_bits |= RxMulticast; 4711b6b7172SCesar Eduardo Barros 4721b6b7172SCesar Eduardo Barros if (dev->flags & IFF_BROADCAST) 4731b6b7172SCesar Eduardo Barros rx_config_bits |= RxBroadcast; 4741b6b7172SCesar Eduardo Barros 4751b6b7172SCesar Eduardo Barros priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast 4761b6b7172SCesar Eduardo Barros | RxMulticast | RxAllphys); 4771b6b7172SCesar Eduardo Barros priv->rx_config |= rx_config_bits; 4781b6b7172SCesar Eduardo Barros 4791b6b7172SCesar Eduardo Barros priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI 4801b6b7172SCesar Eduardo Barros | IFF_MULTICAST | IFF_BROADCAST); 4811b6b7172SCesar Eduardo Barros 4821b6b7172SCesar Eduardo Barros if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags) 4831b6b7172SCesar Eduardo Barros iowrite32(priv->rx_config, port_base + RxConfig); 4841b6b7172SCesar Eduardo Barros } 4851b6b7172SCesar Eduardo Barros 4861b6b7172SCesar Eduardo Barros static bool _sc92031_check_media(struct net_device *dev) 4871b6b7172SCesar Eduardo Barros { 4881b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 4891b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 4901b6b7172SCesar Eduardo Barros u16 bmsr; 4911b6b7172SCesar Eduardo Barros 4921b6b7172SCesar Eduardo Barros bmsr = _sc92031_mii_read(port_base, MII_BMSR); 4931b6b7172SCesar Eduardo Barros rmb(); 4941b6b7172SCesar Eduardo Barros if (bmsr & BMSR_LSTATUS) { 4951b6b7172SCesar Eduardo Barros bool speed_100, duplex_full; 4961b6b7172SCesar Eduardo Barros u32 flow_ctrl_config = 0; 4971b6b7172SCesar Eduardo Barros u16 output_status = _sc92031_mii_read(port_base, 4981b6b7172SCesar Eduardo Barros MII_OutputStatus); 4991b6b7172SCesar Eduardo Barros _sc92031_mii_scan(port_base); 5001b6b7172SCesar Eduardo Barros 5011b6b7172SCesar Eduardo Barros speed_100 = output_status & 0x2; 5021b6b7172SCesar Eduardo Barros duplex_full = output_status & 0x4; 5031b6b7172SCesar Eduardo Barros 5041b6b7172SCesar Eduardo Barros /* Initial Tx/Rx configuration */ 5051b6b7172SCesar Eduardo Barros priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift); 5061b6b7172SCesar Eduardo Barros priv->tx_config = 0x48800000; 5071b6b7172SCesar Eduardo Barros 5081b6b7172SCesar Eduardo Barros /* NOTE: vendor driver had dead code here to enable tx padding */ 5091b6b7172SCesar Eduardo Barros 5101b6b7172SCesar Eduardo Barros if (!speed_100) 5111b6b7172SCesar Eduardo Barros priv->tx_config |= 0x80000; 5121b6b7172SCesar Eduardo Barros 5131b6b7172SCesar Eduardo Barros // configure rx mode 5141b6b7172SCesar Eduardo Barros _sc92031_set_rx_config(dev); 5151b6b7172SCesar Eduardo Barros 5161b6b7172SCesar Eduardo Barros if (duplex_full) { 5171b6b7172SCesar Eduardo Barros priv->rx_config |= RxFullDx; 5181b6b7172SCesar Eduardo Barros priv->tx_config |= TxFullDx; 5191b6b7172SCesar Eduardo Barros flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb; 5201b6b7172SCesar Eduardo Barros } else { 5211b6b7172SCesar Eduardo Barros priv->rx_config &= ~RxFullDx; 5221b6b7172SCesar Eduardo Barros priv->tx_config &= ~TxFullDx; 5231b6b7172SCesar Eduardo Barros } 5241b6b7172SCesar Eduardo Barros 5251b6b7172SCesar Eduardo Barros _sc92031_set_mar(dev); 5261b6b7172SCesar Eduardo Barros _sc92031_set_rx_config(dev); 5271b6b7172SCesar Eduardo Barros _sc92031_enable_tx_rx(dev); 5281b6b7172SCesar Eduardo Barros iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig); 5291b6b7172SCesar Eduardo Barros 5301b6b7172SCesar Eduardo Barros netif_carrier_on(dev); 5311b6b7172SCesar Eduardo Barros 5321b6b7172SCesar Eduardo Barros if (printk_ratelimit()) 5331b6b7172SCesar Eduardo Barros printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", 5341b6b7172SCesar Eduardo Barros dev->name, 5351b6b7172SCesar Eduardo Barros speed_100 ? "100" : "10", 5361b6b7172SCesar Eduardo Barros duplex_full ? "full" : "half"); 5371b6b7172SCesar Eduardo Barros return true; 5381b6b7172SCesar Eduardo Barros } else { 5391b6b7172SCesar Eduardo Barros _sc92031_mii_scan(port_base); 5401b6b7172SCesar Eduardo Barros 5411b6b7172SCesar Eduardo Barros netif_carrier_off(dev); 5421b6b7172SCesar Eduardo Barros 5431b6b7172SCesar Eduardo Barros _sc92031_disable_tx_rx(dev); 5441b6b7172SCesar Eduardo Barros 5451b6b7172SCesar Eduardo Barros if (printk_ratelimit()) 5461b6b7172SCesar Eduardo Barros printk(KERN_INFO "%s: link down\n", dev->name); 5471b6b7172SCesar Eduardo Barros return false; 5481b6b7172SCesar Eduardo Barros } 5491b6b7172SCesar Eduardo Barros } 5501b6b7172SCesar Eduardo Barros 5511b6b7172SCesar Eduardo Barros static void _sc92031_phy_reset(struct net_device *dev) 5521b6b7172SCesar Eduardo Barros { 5531b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 5541b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 5551b6b7172SCesar Eduardo Barros u32 phy_ctrl; 5561b6b7172SCesar Eduardo Barros 5571b6b7172SCesar Eduardo Barros phy_ctrl = ioread32(port_base + PhyCtrl); 5581b6b7172SCesar Eduardo Barros phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10); 5591b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlAne | PhyCtrlReset; 5601b6b7172SCesar Eduardo Barros 5611b6b7172SCesar Eduardo Barros switch (media) { 5621b6b7172SCesar Eduardo Barros default: 5631b6b7172SCesar Eduardo Barros case AUTOSELECT: 5641b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; 5651b6b7172SCesar Eduardo Barros break; 5661b6b7172SCesar Eduardo Barros case M10_HALF: 5671b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd10; 5681b6b7172SCesar Eduardo Barros break; 5691b6b7172SCesar Eduardo Barros case M10_FULL: 5701b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10; 5711b6b7172SCesar Eduardo Barros break; 5721b6b7172SCesar Eduardo Barros case M100_HALF: 5731b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd100; 5741b6b7172SCesar Eduardo Barros break; 5751b6b7172SCesar Eduardo Barros case M100_FULL: 5761b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; 5771b6b7172SCesar Eduardo Barros break; 5781b6b7172SCesar Eduardo Barros } 5791b6b7172SCesar Eduardo Barros 5801b6b7172SCesar Eduardo Barros iowrite32(phy_ctrl, port_base + PhyCtrl); 5811b6b7172SCesar Eduardo Barros mdelay(10); 5821b6b7172SCesar Eduardo Barros 5831b6b7172SCesar Eduardo Barros phy_ctrl &= ~PhyCtrlReset; 5841b6b7172SCesar Eduardo Barros iowrite32(phy_ctrl, port_base + PhyCtrl); 5851b6b7172SCesar Eduardo Barros mdelay(1); 5861b6b7172SCesar Eduardo Barros 5871b6b7172SCesar Eduardo Barros _sc92031_mii_write(port_base, MII_JAB, 5881b6b7172SCesar Eduardo Barros PHY_16_JAB_ENB | PHY_16_PORT_ENB); 5891b6b7172SCesar Eduardo Barros _sc92031_mii_scan(port_base); 5901b6b7172SCesar Eduardo Barros 5911b6b7172SCesar Eduardo Barros netif_carrier_off(dev); 5921b6b7172SCesar Eduardo Barros netif_stop_queue(dev); 5931b6b7172SCesar Eduardo Barros } 5941b6b7172SCesar Eduardo Barros 5951b6b7172SCesar Eduardo Barros static void _sc92031_reset(struct net_device *dev) 5961b6b7172SCesar Eduardo Barros { 5971b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 5981b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 5991b6b7172SCesar Eduardo Barros 6001b6b7172SCesar Eduardo Barros /* disable PM */ 6011b6b7172SCesar Eduardo Barros iowrite32(0, port_base + PMConfig); 6021b6b7172SCesar Eduardo Barros 6031b6b7172SCesar Eduardo Barros /* soft reset the chip */ 6041b6b7172SCesar Eduardo Barros iowrite32(Cfg0_Reset, port_base + Config0); 6051b6b7172SCesar Eduardo Barros mdelay(200); 6061b6b7172SCesar Eduardo Barros 6071b6b7172SCesar Eduardo Barros iowrite32(0, port_base + Config0); 6081b6b7172SCesar Eduardo Barros mdelay(10); 6091b6b7172SCesar Eduardo Barros 6101b6b7172SCesar Eduardo Barros /* disable interrupts */ 6111b6b7172SCesar Eduardo Barros iowrite32(0, port_base + IntrMask); 6121b6b7172SCesar Eduardo Barros 6131b6b7172SCesar Eduardo Barros /* clear multicast address */ 6141b6b7172SCesar Eduardo Barros iowrite32(0, port_base + MAR0); 6151b6b7172SCesar Eduardo Barros iowrite32(0, port_base + MAR0 + 4); 6161b6b7172SCesar Eduardo Barros 6171b6b7172SCesar Eduardo Barros /* init rx ring */ 6181b6b7172SCesar Eduardo Barros iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr); 6191b6b7172SCesar Eduardo Barros priv->rx_ring_tail = priv->rx_ring_dma_addr; 6201b6b7172SCesar Eduardo Barros 6211b6b7172SCesar Eduardo Barros /* init tx ring */ 6221b6b7172SCesar Eduardo Barros _sc92031_tx_clear(dev); 6231b6b7172SCesar Eduardo Barros 6241b6b7172SCesar Eduardo Barros /* clear old register values */ 6251b6b7172SCesar Eduardo Barros priv->intr_status = 0; 6261b6b7172SCesar Eduardo Barros atomic_set(&priv->intr_mask, 0); 6271b6b7172SCesar Eduardo Barros priv->rx_config = 0; 6281b6b7172SCesar Eduardo Barros priv->tx_config = 0; 6291b6b7172SCesar Eduardo Barros priv->mc_flags = 0; 6301b6b7172SCesar Eduardo Barros 6311b6b7172SCesar Eduardo Barros /* configure rx buffer size */ 6321b6b7172SCesar Eduardo Barros /* NOTE: vendor driver had dead code here to enable early tx/rx */ 6331b6b7172SCesar Eduardo Barros iowrite32(Cfg1_Rcv64K, port_base + Config1); 6341b6b7172SCesar Eduardo Barros 6351b6b7172SCesar Eduardo Barros _sc92031_phy_reset(dev); 6361b6b7172SCesar Eduardo Barros _sc92031_check_media(dev); 6371b6b7172SCesar Eduardo Barros 6381b6b7172SCesar Eduardo Barros /* calculate rx fifo overflow */ 6391b6b7172SCesar Eduardo Barros priv->rx_value = 0; 6401b6b7172SCesar Eduardo Barros 6411b6b7172SCesar Eduardo Barros /* enable PM */ 6421b6b7172SCesar Eduardo Barros iowrite32(priv->pm_config, port_base + PMConfig); 6431b6b7172SCesar Eduardo Barros 6441b6b7172SCesar Eduardo Barros /* clear intr register */ 6451b6b7172SCesar Eduardo Barros ioread32(port_base + IntrStatus); 6461b6b7172SCesar Eduardo Barros } 6471b6b7172SCesar Eduardo Barros 6481b6b7172SCesar Eduardo Barros static void _sc92031_tx_tasklet(struct net_device *dev) 6491b6b7172SCesar Eduardo Barros { 6501b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 6511b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 6521b6b7172SCesar Eduardo Barros 6531b6b7172SCesar Eduardo Barros unsigned old_tx_tail; 6541b6b7172SCesar Eduardo Barros unsigned entry; 6551b6b7172SCesar Eduardo Barros u32 tx_status; 6561b6b7172SCesar Eduardo Barros 6571b6b7172SCesar Eduardo Barros old_tx_tail = priv->tx_tail; 6581b6b7172SCesar Eduardo Barros while (priv->tx_head - priv->tx_tail > 0) { 6591b6b7172SCesar Eduardo Barros entry = priv->tx_tail % NUM_TX_DESC; 6601b6b7172SCesar Eduardo Barros tx_status = ioread32(port_base + TxStatus0 + entry * 4); 6611b6b7172SCesar Eduardo Barros 6621b6b7172SCesar Eduardo Barros if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) 6631b6b7172SCesar Eduardo Barros break; 6641b6b7172SCesar Eduardo Barros 6651b6b7172SCesar Eduardo Barros priv->tx_tail++; 6661b6b7172SCesar Eduardo Barros 6671b6b7172SCesar Eduardo Barros if (tx_status & TxStatOK) { 6681b6b7172SCesar Eduardo Barros dev->stats.tx_bytes += tx_status & 0x1fff; 6691b6b7172SCesar Eduardo Barros dev->stats.tx_packets++; 6701b6b7172SCesar Eduardo Barros /* Note: TxCarrierLost is always asserted at 100mbps. */ 6711b6b7172SCesar Eduardo Barros dev->stats.collisions += (tx_status >> 22) & 0xf; 6721b6b7172SCesar Eduardo Barros } 6731b6b7172SCesar Eduardo Barros 6741b6b7172SCesar Eduardo Barros if (tx_status & (TxOutOfWindow | TxAborted)) { 6751b6b7172SCesar Eduardo Barros dev->stats.tx_errors++; 6761b6b7172SCesar Eduardo Barros 6771b6b7172SCesar Eduardo Barros if (tx_status & TxAborted) 6781b6b7172SCesar Eduardo Barros dev->stats.tx_aborted_errors++; 6791b6b7172SCesar Eduardo Barros 6801b6b7172SCesar Eduardo Barros if (tx_status & TxCarrierLost) 6811b6b7172SCesar Eduardo Barros dev->stats.tx_carrier_errors++; 6821b6b7172SCesar Eduardo Barros 6831b6b7172SCesar Eduardo Barros if (tx_status & TxOutOfWindow) 6841b6b7172SCesar Eduardo Barros dev->stats.tx_window_errors++; 6851b6b7172SCesar Eduardo Barros } 6861b6b7172SCesar Eduardo Barros 6871b6b7172SCesar Eduardo Barros if (tx_status & TxUnderrun) 6881b6b7172SCesar Eduardo Barros dev->stats.tx_fifo_errors++; 6891b6b7172SCesar Eduardo Barros } 6901b6b7172SCesar Eduardo Barros 6911b6b7172SCesar Eduardo Barros if (priv->tx_tail != old_tx_tail) 6921b6b7172SCesar Eduardo Barros if (netif_queue_stopped(dev)) 6931b6b7172SCesar Eduardo Barros netif_wake_queue(dev); 6941b6b7172SCesar Eduardo Barros } 6951b6b7172SCesar Eduardo Barros 6961b6b7172SCesar Eduardo Barros static void _sc92031_rx_tasklet_error(struct net_device *dev, 6971b6b7172SCesar Eduardo Barros u32 rx_status, unsigned rx_size) 6981b6b7172SCesar Eduardo Barros { 6991b6b7172SCesar Eduardo Barros if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) { 7001b6b7172SCesar Eduardo Barros dev->stats.rx_errors++; 7011b6b7172SCesar Eduardo Barros dev->stats.rx_length_errors++; 7021b6b7172SCesar Eduardo Barros } 7031b6b7172SCesar Eduardo Barros 7041b6b7172SCesar Eduardo Barros if (!(rx_status & RxStatesOK)) { 7051b6b7172SCesar Eduardo Barros dev->stats.rx_errors++; 7061b6b7172SCesar Eduardo Barros 7071b6b7172SCesar Eduardo Barros if (rx_status & (RxHugeFrame | RxSmallFrame)) 7081b6b7172SCesar Eduardo Barros dev->stats.rx_length_errors++; 7091b6b7172SCesar Eduardo Barros 7101b6b7172SCesar Eduardo Barros if (rx_status & RxBadAlign) 7111b6b7172SCesar Eduardo Barros dev->stats.rx_frame_errors++; 7121b6b7172SCesar Eduardo Barros 7131b6b7172SCesar Eduardo Barros if (!(rx_status & RxCRCOK)) 7141b6b7172SCesar Eduardo Barros dev->stats.rx_crc_errors++; 7151b6b7172SCesar Eduardo Barros } else { 7161b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 7171b6b7172SCesar Eduardo Barros priv->rx_loss++; 7181b6b7172SCesar Eduardo Barros } 7191b6b7172SCesar Eduardo Barros } 7201b6b7172SCesar Eduardo Barros 7211b6b7172SCesar Eduardo Barros static void _sc92031_rx_tasklet(struct net_device *dev) 7221b6b7172SCesar Eduardo Barros { 7231b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 7241b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 7251b6b7172SCesar Eduardo Barros 7261b6b7172SCesar Eduardo Barros dma_addr_t rx_ring_head; 7271b6b7172SCesar Eduardo Barros unsigned rx_len; 7281b6b7172SCesar Eduardo Barros unsigned rx_ring_offset; 7291b6b7172SCesar Eduardo Barros void *rx_ring = priv->rx_ring; 7301b6b7172SCesar Eduardo Barros 7311b6b7172SCesar Eduardo Barros rx_ring_head = ioread32(port_base + RxBufWPtr); 7321b6b7172SCesar Eduardo Barros rmb(); 7331b6b7172SCesar Eduardo Barros 7341b6b7172SCesar Eduardo Barros /* rx_ring_head is only 17 bits in the RxBufWPtr register. 7351b6b7172SCesar Eduardo Barros * we need to change it to 32 bits physical address 7361b6b7172SCesar Eduardo Barros */ 7371b6b7172SCesar Eduardo Barros rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1); 7381b6b7172SCesar Eduardo Barros rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1); 7391b6b7172SCesar Eduardo Barros if (rx_ring_head < priv->rx_ring_dma_addr) 7401b6b7172SCesar Eduardo Barros rx_ring_head += RX_BUF_LEN; 7411b6b7172SCesar Eduardo Barros 7421b6b7172SCesar Eduardo Barros if (rx_ring_head >= priv->rx_ring_tail) 7431b6b7172SCesar Eduardo Barros rx_len = rx_ring_head - priv->rx_ring_tail; 7441b6b7172SCesar Eduardo Barros else 7451b6b7172SCesar Eduardo Barros rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head); 7461b6b7172SCesar Eduardo Barros 7471b6b7172SCesar Eduardo Barros if (!rx_len) 7481b6b7172SCesar Eduardo Barros return; 7491b6b7172SCesar Eduardo Barros 7501b6b7172SCesar Eduardo Barros if (unlikely(rx_len > RX_BUF_LEN)) { 7511b6b7172SCesar Eduardo Barros if (printk_ratelimit()) 7521b6b7172SCesar Eduardo Barros printk(KERN_ERR "%s: rx packets length > rx buffer\n", 7531b6b7172SCesar Eduardo Barros dev->name); 7541b6b7172SCesar Eduardo Barros return; 7551b6b7172SCesar Eduardo Barros } 7561b6b7172SCesar Eduardo Barros 7571b6b7172SCesar Eduardo Barros rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN; 7581b6b7172SCesar Eduardo Barros 7591b6b7172SCesar Eduardo Barros while (rx_len) { 7601b6b7172SCesar Eduardo Barros u32 rx_status; 7611b6b7172SCesar Eduardo Barros unsigned rx_size, rx_size_align, pkt_size; 7621b6b7172SCesar Eduardo Barros struct sk_buff *skb; 7631b6b7172SCesar Eduardo Barros 7641b6b7172SCesar Eduardo Barros rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset)); 7651b6b7172SCesar Eduardo Barros rmb(); 7661b6b7172SCesar Eduardo Barros 7671b6b7172SCesar Eduardo Barros rx_size = rx_status >> 20; 7681b6b7172SCesar Eduardo Barros rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned 7691b6b7172SCesar Eduardo Barros pkt_size = rx_size - 4; // Omit the four octet CRC from the length. 7701b6b7172SCesar Eduardo Barros 7711b6b7172SCesar Eduardo Barros rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; 7721b6b7172SCesar Eduardo Barros 7731b6b7172SCesar Eduardo Barros if (unlikely(rx_status == 0 || 7741b6b7172SCesar Eduardo Barros rx_size > (MAX_ETH_FRAME_SIZE + 4) || 7751b6b7172SCesar Eduardo Barros rx_size < 16 || 7761b6b7172SCesar Eduardo Barros !(rx_status & RxStatesOK))) { 7771b6b7172SCesar Eduardo Barros _sc92031_rx_tasklet_error(dev, rx_status, rx_size); 7781b6b7172SCesar Eduardo Barros break; 7791b6b7172SCesar Eduardo Barros } 7801b6b7172SCesar Eduardo Barros 7811b6b7172SCesar Eduardo Barros if (unlikely(rx_size_align + 4 > rx_len)) { 7821b6b7172SCesar Eduardo Barros if (printk_ratelimit()) 7831b6b7172SCesar Eduardo Barros printk(KERN_ERR "%s: rx_len is too small\n", dev->name); 7841b6b7172SCesar Eduardo Barros break; 7851b6b7172SCesar Eduardo Barros } 7861b6b7172SCesar Eduardo Barros 7871b6b7172SCesar Eduardo Barros rx_len -= rx_size_align + 4; 7881b6b7172SCesar Eduardo Barros 7891b6b7172SCesar Eduardo Barros skb = netdev_alloc_skb_ip_align(dev, pkt_size); 7901b6b7172SCesar Eduardo Barros if (unlikely(!skb)) { 7911b6b7172SCesar Eduardo Barros if (printk_ratelimit()) 7921b6b7172SCesar Eduardo Barros printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", 7931b6b7172SCesar Eduardo Barros dev->name, pkt_size); 7941b6b7172SCesar Eduardo Barros goto next; 7951b6b7172SCesar Eduardo Barros } 7961b6b7172SCesar Eduardo Barros 7971b6b7172SCesar Eduardo Barros if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { 7981b6b7172SCesar Eduardo Barros memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), 7991b6b7172SCesar Eduardo Barros rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); 8001b6b7172SCesar Eduardo Barros memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), 8011b6b7172SCesar Eduardo Barros rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); 8021b6b7172SCesar Eduardo Barros } else { 8031b6b7172SCesar Eduardo Barros memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); 8041b6b7172SCesar Eduardo Barros } 8051b6b7172SCesar Eduardo Barros 8061b6b7172SCesar Eduardo Barros skb->protocol = eth_type_trans(skb, dev); 8071b6b7172SCesar Eduardo Barros netif_rx(skb); 8081b6b7172SCesar Eduardo Barros 8091b6b7172SCesar Eduardo Barros dev->stats.rx_bytes += pkt_size; 8101b6b7172SCesar Eduardo Barros dev->stats.rx_packets++; 8111b6b7172SCesar Eduardo Barros 8121b6b7172SCesar Eduardo Barros if (rx_status & Rx_Multicast) 8131b6b7172SCesar Eduardo Barros dev->stats.multicast++; 8141b6b7172SCesar Eduardo Barros 8151b6b7172SCesar Eduardo Barros next: 8161b6b7172SCesar Eduardo Barros rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN; 8171b6b7172SCesar Eduardo Barros } 8181b6b7172SCesar Eduardo Barros mb(); 8191b6b7172SCesar Eduardo Barros 8201b6b7172SCesar Eduardo Barros priv->rx_ring_tail = rx_ring_head; 8211b6b7172SCesar Eduardo Barros iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr); 8221b6b7172SCesar Eduardo Barros } 8231b6b7172SCesar Eduardo Barros 8241b6b7172SCesar Eduardo Barros static void _sc92031_link_tasklet(struct net_device *dev) 8251b6b7172SCesar Eduardo Barros { 8261b6b7172SCesar Eduardo Barros if (_sc92031_check_media(dev)) 8271b6b7172SCesar Eduardo Barros netif_wake_queue(dev); 8281b6b7172SCesar Eduardo Barros else { 8291b6b7172SCesar Eduardo Barros netif_stop_queue(dev); 8301b6b7172SCesar Eduardo Barros dev->stats.tx_carrier_errors++; 8311b6b7172SCesar Eduardo Barros } 8321b6b7172SCesar Eduardo Barros } 8331b6b7172SCesar Eduardo Barros 8341b6b7172SCesar Eduardo Barros static void sc92031_tasklet(unsigned long data) 8351b6b7172SCesar Eduardo Barros { 8361b6b7172SCesar Eduardo Barros struct net_device *dev = (struct net_device *)data; 8371b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 8381b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 8391b6b7172SCesar Eduardo Barros u32 intr_status, intr_mask; 8401b6b7172SCesar Eduardo Barros 8411b6b7172SCesar Eduardo Barros intr_status = priv->intr_status; 8421b6b7172SCesar Eduardo Barros 8431b6b7172SCesar Eduardo Barros spin_lock(&priv->lock); 8441b6b7172SCesar Eduardo Barros 8451b6b7172SCesar Eduardo Barros if (unlikely(!netif_running(dev))) 8461b6b7172SCesar Eduardo Barros goto out; 8471b6b7172SCesar Eduardo Barros 8481b6b7172SCesar Eduardo Barros if (intr_status & TxOK) 8491b6b7172SCesar Eduardo Barros _sc92031_tx_tasklet(dev); 8501b6b7172SCesar Eduardo Barros 8511b6b7172SCesar Eduardo Barros if (intr_status & RxOK) 8521b6b7172SCesar Eduardo Barros _sc92031_rx_tasklet(dev); 8531b6b7172SCesar Eduardo Barros 8541b6b7172SCesar Eduardo Barros if (intr_status & RxOverflow) 8551b6b7172SCesar Eduardo Barros dev->stats.rx_errors++; 8561b6b7172SCesar Eduardo Barros 8571b6b7172SCesar Eduardo Barros if (intr_status & TimeOut) { 8581b6b7172SCesar Eduardo Barros dev->stats.rx_errors++; 8591b6b7172SCesar Eduardo Barros dev->stats.rx_length_errors++; 8601b6b7172SCesar Eduardo Barros } 8611b6b7172SCesar Eduardo Barros 8621b6b7172SCesar Eduardo Barros if (intr_status & (LinkFail | LinkOK)) 8631b6b7172SCesar Eduardo Barros _sc92031_link_tasklet(dev); 8641b6b7172SCesar Eduardo Barros 8651b6b7172SCesar Eduardo Barros out: 8661b6b7172SCesar Eduardo Barros intr_mask = atomic_read(&priv->intr_mask); 8671b6b7172SCesar Eduardo Barros rmb(); 8681b6b7172SCesar Eduardo Barros 8691b6b7172SCesar Eduardo Barros iowrite32(intr_mask, port_base + IntrMask); 8701b6b7172SCesar Eduardo Barros mmiowb(); 8711b6b7172SCesar Eduardo Barros 8721b6b7172SCesar Eduardo Barros spin_unlock(&priv->lock); 8731b6b7172SCesar Eduardo Barros } 8741b6b7172SCesar Eduardo Barros 8751b6b7172SCesar Eduardo Barros static irqreturn_t sc92031_interrupt(int irq, void *dev_id) 8761b6b7172SCesar Eduardo Barros { 8771b6b7172SCesar Eduardo Barros struct net_device *dev = dev_id; 8781b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 8791b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 8801b6b7172SCesar Eduardo Barros u32 intr_status, intr_mask; 8811b6b7172SCesar Eduardo Barros 8821b6b7172SCesar Eduardo Barros /* mask interrupts before clearing IntrStatus */ 8831b6b7172SCesar Eduardo Barros iowrite32(0, port_base + IntrMask); 8841b6b7172SCesar Eduardo Barros _sc92031_dummy_read(port_base); 8851b6b7172SCesar Eduardo Barros 8861b6b7172SCesar Eduardo Barros intr_status = ioread32(port_base + IntrStatus); 8871b6b7172SCesar Eduardo Barros if (unlikely(intr_status == 0xffffffff)) 8881b6b7172SCesar Eduardo Barros return IRQ_NONE; // hardware has gone missing 8891b6b7172SCesar Eduardo Barros 8901b6b7172SCesar Eduardo Barros intr_status &= IntrBits; 8911b6b7172SCesar Eduardo Barros if (!intr_status) 8921b6b7172SCesar Eduardo Barros goto out_none; 8931b6b7172SCesar Eduardo Barros 8941b6b7172SCesar Eduardo Barros priv->intr_status = intr_status; 8951b6b7172SCesar Eduardo Barros tasklet_schedule(&priv->tasklet); 8961b6b7172SCesar Eduardo Barros 8971b6b7172SCesar Eduardo Barros return IRQ_HANDLED; 8981b6b7172SCesar Eduardo Barros 8991b6b7172SCesar Eduardo Barros out_none: 9001b6b7172SCesar Eduardo Barros intr_mask = atomic_read(&priv->intr_mask); 9011b6b7172SCesar Eduardo Barros rmb(); 9021b6b7172SCesar Eduardo Barros 9031b6b7172SCesar Eduardo Barros iowrite32(intr_mask, port_base + IntrMask); 9041b6b7172SCesar Eduardo Barros mmiowb(); 9051b6b7172SCesar Eduardo Barros 9061b6b7172SCesar Eduardo Barros return IRQ_NONE; 9071b6b7172SCesar Eduardo Barros } 9081b6b7172SCesar Eduardo Barros 9091b6b7172SCesar Eduardo Barros static struct net_device_stats *sc92031_get_stats(struct net_device *dev) 9101b6b7172SCesar Eduardo Barros { 9111b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 9121b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 9131b6b7172SCesar Eduardo Barros 9141b6b7172SCesar Eduardo Barros // FIXME I do not understand what is this trying to do. 9151b6b7172SCesar Eduardo Barros if (netif_running(dev)) { 9161b6b7172SCesar Eduardo Barros int temp; 9171b6b7172SCesar Eduardo Barros 9181b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 9191b6b7172SCesar Eduardo Barros 9201b6b7172SCesar Eduardo Barros /* Update the error count. */ 9211b6b7172SCesar Eduardo Barros temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff; 9221b6b7172SCesar Eduardo Barros 9231b6b7172SCesar Eduardo Barros if (temp == 0xffff) { 9241b6b7172SCesar Eduardo Barros priv->rx_value += temp; 9251b6b7172SCesar Eduardo Barros dev->stats.rx_fifo_errors = priv->rx_value; 9261b6b7172SCesar Eduardo Barros } else 9271b6b7172SCesar Eduardo Barros dev->stats.rx_fifo_errors = temp + priv->rx_value; 9281b6b7172SCesar Eduardo Barros 9291b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 9301b6b7172SCesar Eduardo Barros } 9311b6b7172SCesar Eduardo Barros 9321b6b7172SCesar Eduardo Barros return &dev->stats; 9331b6b7172SCesar Eduardo Barros } 9341b6b7172SCesar Eduardo Barros 9351b6b7172SCesar Eduardo Barros static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb, 9361b6b7172SCesar Eduardo Barros struct net_device *dev) 9371b6b7172SCesar Eduardo Barros { 9381b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 9391b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 9401b6b7172SCesar Eduardo Barros unsigned len; 9411b6b7172SCesar Eduardo Barros unsigned entry; 9421b6b7172SCesar Eduardo Barros u32 tx_status; 9431b6b7172SCesar Eduardo Barros 9441b6b7172SCesar Eduardo Barros if (unlikely(skb->len > TX_BUF_SIZE)) { 9451b6b7172SCesar Eduardo Barros dev->stats.tx_dropped++; 9461b6b7172SCesar Eduardo Barros goto out; 9471b6b7172SCesar Eduardo Barros } 9481b6b7172SCesar Eduardo Barros 9491b6b7172SCesar Eduardo Barros spin_lock(&priv->lock); 9501b6b7172SCesar Eduardo Barros 9511b6b7172SCesar Eduardo Barros if (unlikely(!netif_carrier_ok(dev))) { 9521b6b7172SCesar Eduardo Barros dev->stats.tx_dropped++; 9531b6b7172SCesar Eduardo Barros goto out_unlock; 9541b6b7172SCesar Eduardo Barros } 9551b6b7172SCesar Eduardo Barros 9561b6b7172SCesar Eduardo Barros BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC); 9571b6b7172SCesar Eduardo Barros 9581b6b7172SCesar Eduardo Barros entry = priv->tx_head++ % NUM_TX_DESC; 9591b6b7172SCesar Eduardo Barros 9601b6b7172SCesar Eduardo Barros skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); 9611b6b7172SCesar Eduardo Barros 9621b6b7172SCesar Eduardo Barros len = skb->len; 9631b6b7172SCesar Eduardo Barros if (len < ETH_ZLEN) { 9641b6b7172SCesar Eduardo Barros memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, 9651b6b7172SCesar Eduardo Barros 0, ETH_ZLEN - len); 9661b6b7172SCesar Eduardo Barros len = ETH_ZLEN; 9671b6b7172SCesar Eduardo Barros } 9681b6b7172SCesar Eduardo Barros 9691b6b7172SCesar Eduardo Barros wmb(); 9701b6b7172SCesar Eduardo Barros 9711b6b7172SCesar Eduardo Barros if (len < 100) 9721b6b7172SCesar Eduardo Barros tx_status = len; 9731b6b7172SCesar Eduardo Barros else if (len < 300) 9741b6b7172SCesar Eduardo Barros tx_status = 0x30000 | len; 9751b6b7172SCesar Eduardo Barros else 9761b6b7172SCesar Eduardo Barros tx_status = 0x50000 | len; 9771b6b7172SCesar Eduardo Barros 9781b6b7172SCesar Eduardo Barros iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE, 9791b6b7172SCesar Eduardo Barros port_base + TxAddr0 + entry * 4); 9801b6b7172SCesar Eduardo Barros iowrite32(tx_status, port_base + TxStatus0 + entry * 4); 9811b6b7172SCesar Eduardo Barros mmiowb(); 9821b6b7172SCesar Eduardo Barros 9831b6b7172SCesar Eduardo Barros if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC) 9841b6b7172SCesar Eduardo Barros netif_stop_queue(dev); 9851b6b7172SCesar Eduardo Barros 9861b6b7172SCesar Eduardo Barros out_unlock: 9871b6b7172SCesar Eduardo Barros spin_unlock(&priv->lock); 9881b6b7172SCesar Eduardo Barros 9891b6b7172SCesar Eduardo Barros out: 9901b6b7172SCesar Eduardo Barros dev_kfree_skb(skb); 9911b6b7172SCesar Eduardo Barros 9921b6b7172SCesar Eduardo Barros return NETDEV_TX_OK; 9931b6b7172SCesar Eduardo Barros } 9941b6b7172SCesar Eduardo Barros 9951b6b7172SCesar Eduardo Barros static int sc92031_open(struct net_device *dev) 9961b6b7172SCesar Eduardo Barros { 9971b6b7172SCesar Eduardo Barros int err; 9981b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 9991b6b7172SCesar Eduardo Barros struct pci_dev *pdev = priv->pdev; 10001b6b7172SCesar Eduardo Barros 10011b6b7172SCesar Eduardo Barros priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN, 10021b6b7172SCesar Eduardo Barros &priv->rx_ring_dma_addr); 10031b6b7172SCesar Eduardo Barros if (unlikely(!priv->rx_ring)) { 10041b6b7172SCesar Eduardo Barros err = -ENOMEM; 10051b6b7172SCesar Eduardo Barros goto out_alloc_rx_ring; 10061b6b7172SCesar Eduardo Barros } 10071b6b7172SCesar Eduardo Barros 10081b6b7172SCesar Eduardo Barros priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN, 10091b6b7172SCesar Eduardo Barros &priv->tx_bufs_dma_addr); 10101b6b7172SCesar Eduardo Barros if (unlikely(!priv->tx_bufs)) { 10111b6b7172SCesar Eduardo Barros err = -ENOMEM; 10121b6b7172SCesar Eduardo Barros goto out_alloc_tx_bufs; 10131b6b7172SCesar Eduardo Barros } 10141b6b7172SCesar Eduardo Barros priv->tx_head = priv->tx_tail = 0; 10151b6b7172SCesar Eduardo Barros 10161b6b7172SCesar Eduardo Barros err = request_irq(pdev->irq, sc92031_interrupt, 10171b6b7172SCesar Eduardo Barros IRQF_SHARED, dev->name, dev); 10181b6b7172SCesar Eduardo Barros if (unlikely(err < 0)) 10191b6b7172SCesar Eduardo Barros goto out_request_irq; 10201b6b7172SCesar Eduardo Barros 10211b6b7172SCesar Eduardo Barros priv->pm_config = 0; 10221b6b7172SCesar Eduardo Barros 10231b6b7172SCesar Eduardo Barros /* Interrupts already disabled by sc92031_stop or sc92031_probe */ 10241b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 10251b6b7172SCesar Eduardo Barros 10261b6b7172SCesar Eduardo Barros _sc92031_reset(dev); 10271b6b7172SCesar Eduardo Barros mmiowb(); 10281b6b7172SCesar Eduardo Barros 10291b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 10301b6b7172SCesar Eduardo Barros sc92031_enable_interrupts(dev); 10311b6b7172SCesar Eduardo Barros 10321b6b7172SCesar Eduardo Barros if (netif_carrier_ok(dev)) 10331b6b7172SCesar Eduardo Barros netif_start_queue(dev); 10341b6b7172SCesar Eduardo Barros else 10351b6b7172SCesar Eduardo Barros netif_tx_disable(dev); 10361b6b7172SCesar Eduardo Barros 10371b6b7172SCesar Eduardo Barros return 0; 10381b6b7172SCesar Eduardo Barros 10391b6b7172SCesar Eduardo Barros out_request_irq: 10401b6b7172SCesar Eduardo Barros pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, 10411b6b7172SCesar Eduardo Barros priv->tx_bufs_dma_addr); 10421b6b7172SCesar Eduardo Barros out_alloc_tx_bufs: 10431b6b7172SCesar Eduardo Barros pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, 10441b6b7172SCesar Eduardo Barros priv->rx_ring_dma_addr); 10451b6b7172SCesar Eduardo Barros out_alloc_rx_ring: 10461b6b7172SCesar Eduardo Barros return err; 10471b6b7172SCesar Eduardo Barros } 10481b6b7172SCesar Eduardo Barros 10491b6b7172SCesar Eduardo Barros static int sc92031_stop(struct net_device *dev) 10501b6b7172SCesar Eduardo Barros { 10511b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 10521b6b7172SCesar Eduardo Barros struct pci_dev *pdev = priv->pdev; 10531b6b7172SCesar Eduardo Barros 10541b6b7172SCesar Eduardo Barros netif_tx_disable(dev); 10551b6b7172SCesar Eduardo Barros 10561b6b7172SCesar Eduardo Barros /* Disable interrupts, stop Tx and Rx. */ 10571b6b7172SCesar Eduardo Barros sc92031_disable_interrupts(dev); 10581b6b7172SCesar Eduardo Barros 10591b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 10601b6b7172SCesar Eduardo Barros 10611b6b7172SCesar Eduardo Barros _sc92031_disable_tx_rx(dev); 10621b6b7172SCesar Eduardo Barros _sc92031_tx_clear(dev); 10631b6b7172SCesar Eduardo Barros mmiowb(); 10641b6b7172SCesar Eduardo Barros 10651b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 10661b6b7172SCesar Eduardo Barros 10671b6b7172SCesar Eduardo Barros free_irq(pdev->irq, dev); 10681b6b7172SCesar Eduardo Barros pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, 10691b6b7172SCesar Eduardo Barros priv->tx_bufs_dma_addr); 10701b6b7172SCesar Eduardo Barros pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, 10711b6b7172SCesar Eduardo Barros priv->rx_ring_dma_addr); 10721b6b7172SCesar Eduardo Barros 10731b6b7172SCesar Eduardo Barros return 0; 10741b6b7172SCesar Eduardo Barros } 10751b6b7172SCesar Eduardo Barros 10761b6b7172SCesar Eduardo Barros static void sc92031_set_multicast_list(struct net_device *dev) 10771b6b7172SCesar Eduardo Barros { 10781b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 10791b6b7172SCesar Eduardo Barros 10801b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 10811b6b7172SCesar Eduardo Barros 10821b6b7172SCesar Eduardo Barros _sc92031_set_mar(dev); 10831b6b7172SCesar Eduardo Barros _sc92031_set_rx_config(dev); 10841b6b7172SCesar Eduardo Barros mmiowb(); 10851b6b7172SCesar Eduardo Barros 10861b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 10871b6b7172SCesar Eduardo Barros } 10881b6b7172SCesar Eduardo Barros 10891b6b7172SCesar Eduardo Barros static void sc92031_tx_timeout(struct net_device *dev) 10901b6b7172SCesar Eduardo Barros { 10911b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 10921b6b7172SCesar Eduardo Barros 10931b6b7172SCesar Eduardo Barros /* Disable interrupts by clearing the interrupt mask.*/ 10941b6b7172SCesar Eduardo Barros sc92031_disable_interrupts(dev); 10951b6b7172SCesar Eduardo Barros 10961b6b7172SCesar Eduardo Barros spin_lock(&priv->lock); 10971b6b7172SCesar Eduardo Barros 10981b6b7172SCesar Eduardo Barros priv->tx_timeouts++; 10991b6b7172SCesar Eduardo Barros 11001b6b7172SCesar Eduardo Barros _sc92031_reset(dev); 11011b6b7172SCesar Eduardo Barros mmiowb(); 11021b6b7172SCesar Eduardo Barros 11031b6b7172SCesar Eduardo Barros spin_unlock(&priv->lock); 11041b6b7172SCesar Eduardo Barros 11051b6b7172SCesar Eduardo Barros /* enable interrupts */ 11061b6b7172SCesar Eduardo Barros sc92031_enable_interrupts(dev); 11071b6b7172SCesar Eduardo Barros 11081b6b7172SCesar Eduardo Barros if (netif_carrier_ok(dev)) 11091b6b7172SCesar Eduardo Barros netif_wake_queue(dev); 11101b6b7172SCesar Eduardo Barros } 11111b6b7172SCesar Eduardo Barros 11121b6b7172SCesar Eduardo Barros #ifdef CONFIG_NET_POLL_CONTROLLER 11131b6b7172SCesar Eduardo Barros static void sc92031_poll_controller(struct net_device *dev) 11141b6b7172SCesar Eduardo Barros { 1115c4a9f085SFrancois Romieu struct sc92031_priv *priv = netdev_priv(dev); 1116c4a9f085SFrancois Romieu const int irq = priv->pdev->irq; 1117c4a9f085SFrancois Romieu 1118c4a9f085SFrancois Romieu disable_irq(irq); 1119c4a9f085SFrancois Romieu if (sc92031_interrupt(irq, dev) != IRQ_NONE) 11201b6b7172SCesar Eduardo Barros sc92031_tasklet((unsigned long)dev); 1121c4a9f085SFrancois Romieu enable_irq(irq); 11221b6b7172SCesar Eduardo Barros } 11231b6b7172SCesar Eduardo Barros #endif 11241b6b7172SCesar Eduardo Barros 11251b6b7172SCesar Eduardo Barros static int sc92031_ethtool_get_settings(struct net_device *dev, 11261b6b7172SCesar Eduardo Barros struct ethtool_cmd *cmd) 11271b6b7172SCesar Eduardo Barros { 11281b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 11291b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 11301b6b7172SCesar Eduardo Barros u8 phy_address; 11311b6b7172SCesar Eduardo Barros u32 phy_ctrl; 11321b6b7172SCesar Eduardo Barros u16 output_status; 11331b6b7172SCesar Eduardo Barros 11341b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 11351b6b7172SCesar Eduardo Barros 11361b6b7172SCesar Eduardo Barros phy_address = ioread32(port_base + Miicmd1) >> 27; 11371b6b7172SCesar Eduardo Barros phy_ctrl = ioread32(port_base + PhyCtrl); 11381b6b7172SCesar Eduardo Barros 11391b6b7172SCesar Eduardo Barros output_status = _sc92031_mii_read(port_base, MII_OutputStatus); 11401b6b7172SCesar Eduardo Barros _sc92031_mii_scan(port_base); 11411b6b7172SCesar Eduardo Barros mmiowb(); 11421b6b7172SCesar Eduardo Barros 11431b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 11441b6b7172SCesar Eduardo Barros 11451b6b7172SCesar Eduardo Barros cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full 11461b6b7172SCesar Eduardo Barros | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full 11471b6b7172SCesar Eduardo Barros | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII; 11481b6b7172SCesar Eduardo Barros 11491b6b7172SCesar Eduardo Barros cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; 11501b6b7172SCesar Eduardo Barros 11511b6b7172SCesar Eduardo Barros if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) 11521b6b7172SCesar Eduardo Barros == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) 11531b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_Autoneg; 11541b6b7172SCesar Eduardo Barros 11551b6b7172SCesar Eduardo Barros if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10) 11561b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_10baseT_Half; 11571b6b7172SCesar Eduardo Barros 11581b6b7172SCesar Eduardo Barros if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux)) 11591b6b7172SCesar Eduardo Barros == (PhyCtrlSpd10 | PhyCtrlDux)) 11601b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_10baseT_Full; 11611b6b7172SCesar Eduardo Barros 11621b6b7172SCesar Eduardo Barros if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100) 11631b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_100baseT_Half; 11641b6b7172SCesar Eduardo Barros 11651b6b7172SCesar Eduardo Barros if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux)) 11661b6b7172SCesar Eduardo Barros == (PhyCtrlSpd100 | PhyCtrlDux)) 11671b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_100baseT_Full; 11681b6b7172SCesar Eduardo Barros 11691b6b7172SCesar Eduardo Barros if (phy_ctrl & PhyCtrlAne) 11701b6b7172SCesar Eduardo Barros cmd->advertising |= ADVERTISED_Autoneg; 11711b6b7172SCesar Eduardo Barros 11721b6b7172SCesar Eduardo Barros ethtool_cmd_speed_set(cmd, 11731b6b7172SCesar Eduardo Barros (output_status & 0x2) ? SPEED_100 : SPEED_10); 11741b6b7172SCesar Eduardo Barros cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; 11751b6b7172SCesar Eduardo Barros cmd->port = PORT_MII; 11761b6b7172SCesar Eduardo Barros cmd->phy_address = phy_address; 11771b6b7172SCesar Eduardo Barros cmd->transceiver = XCVR_INTERNAL; 11781b6b7172SCesar Eduardo Barros cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE; 11791b6b7172SCesar Eduardo Barros 11801b6b7172SCesar Eduardo Barros return 0; 11811b6b7172SCesar Eduardo Barros } 11821b6b7172SCesar Eduardo Barros 11831b6b7172SCesar Eduardo Barros static int sc92031_ethtool_set_settings(struct net_device *dev, 11841b6b7172SCesar Eduardo Barros struct ethtool_cmd *cmd) 11851b6b7172SCesar Eduardo Barros { 11861b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 11871b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 11881b6b7172SCesar Eduardo Barros u32 speed = ethtool_cmd_speed(cmd); 11891b6b7172SCesar Eduardo Barros u32 phy_ctrl; 11901b6b7172SCesar Eduardo Barros u32 old_phy_ctrl; 11911b6b7172SCesar Eduardo Barros 11921b6b7172SCesar Eduardo Barros if (!(speed == SPEED_10 || speed == SPEED_100)) 11931b6b7172SCesar Eduardo Barros return -EINVAL; 11941b6b7172SCesar Eduardo Barros if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) 11951b6b7172SCesar Eduardo Barros return -EINVAL; 11961b6b7172SCesar Eduardo Barros if (!(cmd->port == PORT_MII)) 11971b6b7172SCesar Eduardo Barros return -EINVAL; 11981b6b7172SCesar Eduardo Barros if (!(cmd->phy_address == 0x1f)) 11991b6b7172SCesar Eduardo Barros return -EINVAL; 12001b6b7172SCesar Eduardo Barros if (!(cmd->transceiver == XCVR_INTERNAL)) 12011b6b7172SCesar Eduardo Barros return -EINVAL; 12021b6b7172SCesar Eduardo Barros if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE)) 12031b6b7172SCesar Eduardo Barros return -EINVAL; 12041b6b7172SCesar Eduardo Barros 12051b6b7172SCesar Eduardo Barros if (cmd->autoneg == AUTONEG_ENABLE) { 12061b6b7172SCesar Eduardo Barros if (!(cmd->advertising & (ADVERTISED_Autoneg 12071b6b7172SCesar Eduardo Barros | ADVERTISED_100baseT_Full 12081b6b7172SCesar Eduardo Barros | ADVERTISED_100baseT_Half 12091b6b7172SCesar Eduardo Barros | ADVERTISED_10baseT_Full 12101b6b7172SCesar Eduardo Barros | ADVERTISED_10baseT_Half))) 12111b6b7172SCesar Eduardo Barros return -EINVAL; 12121b6b7172SCesar Eduardo Barros 12131b6b7172SCesar Eduardo Barros phy_ctrl = PhyCtrlAne; 12141b6b7172SCesar Eduardo Barros 12151b6b7172SCesar Eduardo Barros // FIXME: I'm not sure what the original code was trying to do 12161b6b7172SCesar Eduardo Barros if (cmd->advertising & ADVERTISED_Autoneg) 12171b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; 12181b6b7172SCesar Eduardo Barros if (cmd->advertising & ADVERTISED_100baseT_Full) 12191b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; 12201b6b7172SCesar Eduardo Barros if (cmd->advertising & ADVERTISED_100baseT_Half) 12211b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd100; 12221b6b7172SCesar Eduardo Barros if (cmd->advertising & ADVERTISED_10baseT_Full) 12231b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux; 12241b6b7172SCesar Eduardo Barros if (cmd->advertising & ADVERTISED_10baseT_Half) 12251b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd10; 12261b6b7172SCesar Eduardo Barros } else { 12271b6b7172SCesar Eduardo Barros // FIXME: Whole branch guessed 12281b6b7172SCesar Eduardo Barros phy_ctrl = 0; 12291b6b7172SCesar Eduardo Barros 12301b6b7172SCesar Eduardo Barros if (speed == SPEED_10) 12311b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd10; 12321b6b7172SCesar Eduardo Barros else /* cmd->speed == SPEED_100 */ 12331b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlSpd100; 12341b6b7172SCesar Eduardo Barros 12351b6b7172SCesar Eduardo Barros if (cmd->duplex == DUPLEX_FULL) 12361b6b7172SCesar Eduardo Barros phy_ctrl |= PhyCtrlDux; 12371b6b7172SCesar Eduardo Barros } 12381b6b7172SCesar Eduardo Barros 12391b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 12401b6b7172SCesar Eduardo Barros 12411b6b7172SCesar Eduardo Barros old_phy_ctrl = ioread32(port_base + PhyCtrl); 12421b6b7172SCesar Eduardo Barros phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux 12431b6b7172SCesar Eduardo Barros | PhyCtrlSpd100 | PhyCtrlSpd10); 12441b6b7172SCesar Eduardo Barros if (phy_ctrl != old_phy_ctrl) 12451b6b7172SCesar Eduardo Barros iowrite32(phy_ctrl, port_base + PhyCtrl); 12461b6b7172SCesar Eduardo Barros 12471b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 12481b6b7172SCesar Eduardo Barros 12491b6b7172SCesar Eduardo Barros return 0; 12501b6b7172SCesar Eduardo Barros } 12511b6b7172SCesar Eduardo Barros 12521b6b7172SCesar Eduardo Barros static void sc92031_ethtool_get_wol(struct net_device *dev, 12531b6b7172SCesar Eduardo Barros struct ethtool_wolinfo *wolinfo) 12541b6b7172SCesar Eduardo Barros { 12551b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 12561b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 12571b6b7172SCesar Eduardo Barros u32 pm_config; 12581b6b7172SCesar Eduardo Barros 12591b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 12601b6b7172SCesar Eduardo Barros pm_config = ioread32(port_base + PMConfig); 12611b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 12621b6b7172SCesar Eduardo Barros 12631b6b7172SCesar Eduardo Barros // FIXME: Guessed 12641b6b7172SCesar Eduardo Barros wolinfo->supported = WAKE_PHY | WAKE_MAGIC 12651b6b7172SCesar Eduardo Barros | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; 12661b6b7172SCesar Eduardo Barros wolinfo->wolopts = 0; 12671b6b7172SCesar Eduardo Barros 12681b6b7172SCesar Eduardo Barros if (pm_config & PM_LinkUp) 12691b6b7172SCesar Eduardo Barros wolinfo->wolopts |= WAKE_PHY; 12701b6b7172SCesar Eduardo Barros 12711b6b7172SCesar Eduardo Barros if (pm_config & PM_Magic) 12721b6b7172SCesar Eduardo Barros wolinfo->wolopts |= WAKE_MAGIC; 12731b6b7172SCesar Eduardo Barros 12741b6b7172SCesar Eduardo Barros if (pm_config & PM_WakeUp) 12751b6b7172SCesar Eduardo Barros // FIXME: Guessed 12761b6b7172SCesar Eduardo Barros wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; 12771b6b7172SCesar Eduardo Barros } 12781b6b7172SCesar Eduardo Barros 12791b6b7172SCesar Eduardo Barros static int sc92031_ethtool_set_wol(struct net_device *dev, 12801b6b7172SCesar Eduardo Barros struct ethtool_wolinfo *wolinfo) 12811b6b7172SCesar Eduardo Barros { 12821b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 12831b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 12841b6b7172SCesar Eduardo Barros u32 pm_config; 12851b6b7172SCesar Eduardo Barros 12861b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 12871b6b7172SCesar Eduardo Barros 12881b6b7172SCesar Eduardo Barros pm_config = ioread32(port_base + PMConfig) 12891b6b7172SCesar Eduardo Barros & ~(PM_LinkUp | PM_Magic | PM_WakeUp); 12901b6b7172SCesar Eduardo Barros 12911b6b7172SCesar Eduardo Barros if (wolinfo->wolopts & WAKE_PHY) 12921b6b7172SCesar Eduardo Barros pm_config |= PM_LinkUp; 12931b6b7172SCesar Eduardo Barros 12941b6b7172SCesar Eduardo Barros if (wolinfo->wolopts & WAKE_MAGIC) 12951b6b7172SCesar Eduardo Barros pm_config |= PM_Magic; 12961b6b7172SCesar Eduardo Barros 12971b6b7172SCesar Eduardo Barros // FIXME: Guessed 12981b6b7172SCesar Eduardo Barros if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) 12991b6b7172SCesar Eduardo Barros pm_config |= PM_WakeUp; 13001b6b7172SCesar Eduardo Barros 13011b6b7172SCesar Eduardo Barros priv->pm_config = pm_config; 13021b6b7172SCesar Eduardo Barros iowrite32(pm_config, port_base + PMConfig); 13031b6b7172SCesar Eduardo Barros mmiowb(); 13041b6b7172SCesar Eduardo Barros 13051b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 13061b6b7172SCesar Eduardo Barros 13071b6b7172SCesar Eduardo Barros return 0; 13081b6b7172SCesar Eduardo Barros } 13091b6b7172SCesar Eduardo Barros 13101b6b7172SCesar Eduardo Barros static int sc92031_ethtool_nway_reset(struct net_device *dev) 13111b6b7172SCesar Eduardo Barros { 13121b6b7172SCesar Eduardo Barros int err = 0; 13131b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 13141b6b7172SCesar Eduardo Barros void __iomem *port_base = priv->port_base; 13151b6b7172SCesar Eduardo Barros u16 bmcr; 13161b6b7172SCesar Eduardo Barros 13171b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 13181b6b7172SCesar Eduardo Barros 13191b6b7172SCesar Eduardo Barros bmcr = _sc92031_mii_read(port_base, MII_BMCR); 13201b6b7172SCesar Eduardo Barros if (!(bmcr & BMCR_ANENABLE)) { 13211b6b7172SCesar Eduardo Barros err = -EINVAL; 13221b6b7172SCesar Eduardo Barros goto out; 13231b6b7172SCesar Eduardo Barros } 13241b6b7172SCesar Eduardo Barros 13251b6b7172SCesar Eduardo Barros _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART); 13261b6b7172SCesar Eduardo Barros 13271b6b7172SCesar Eduardo Barros out: 13281b6b7172SCesar Eduardo Barros _sc92031_mii_scan(port_base); 13291b6b7172SCesar Eduardo Barros mmiowb(); 13301b6b7172SCesar Eduardo Barros 13311b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 13321b6b7172SCesar Eduardo Barros 13331b6b7172SCesar Eduardo Barros return err; 13341b6b7172SCesar Eduardo Barros } 13351b6b7172SCesar Eduardo Barros 13361b6b7172SCesar Eduardo Barros static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = { 13371b6b7172SCesar Eduardo Barros "tx_timeout", 13381b6b7172SCesar Eduardo Barros "rx_loss", 13391b6b7172SCesar Eduardo Barros }; 13401b6b7172SCesar Eduardo Barros 13411b6b7172SCesar Eduardo Barros static void sc92031_ethtool_get_strings(struct net_device *dev, 13421b6b7172SCesar Eduardo Barros u32 stringset, u8 *data) 13431b6b7172SCesar Eduardo Barros { 13441b6b7172SCesar Eduardo Barros if (stringset == ETH_SS_STATS) 13451b6b7172SCesar Eduardo Barros memcpy(data, sc92031_ethtool_stats_strings, 13461b6b7172SCesar Eduardo Barros SILAN_STATS_NUM * ETH_GSTRING_LEN); 13471b6b7172SCesar Eduardo Barros } 13481b6b7172SCesar Eduardo Barros 13491b6b7172SCesar Eduardo Barros static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset) 13501b6b7172SCesar Eduardo Barros { 13511b6b7172SCesar Eduardo Barros switch (sset) { 13521b6b7172SCesar Eduardo Barros case ETH_SS_STATS: 13531b6b7172SCesar Eduardo Barros return SILAN_STATS_NUM; 13541b6b7172SCesar Eduardo Barros default: 13551b6b7172SCesar Eduardo Barros return -EOPNOTSUPP; 13561b6b7172SCesar Eduardo Barros } 13571b6b7172SCesar Eduardo Barros } 13581b6b7172SCesar Eduardo Barros 13591b6b7172SCesar Eduardo Barros static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, 13601b6b7172SCesar Eduardo Barros struct ethtool_stats *stats, u64 *data) 13611b6b7172SCesar Eduardo Barros { 13621b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 13631b6b7172SCesar Eduardo Barros 13641b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 13651b6b7172SCesar Eduardo Barros data[0] = priv->tx_timeouts; 13661b6b7172SCesar Eduardo Barros data[1] = priv->rx_loss; 13671b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 13681b6b7172SCesar Eduardo Barros } 13691b6b7172SCesar Eduardo Barros 13701b6b7172SCesar Eduardo Barros static const struct ethtool_ops sc92031_ethtool_ops = { 13711b6b7172SCesar Eduardo Barros .get_settings = sc92031_ethtool_get_settings, 13721b6b7172SCesar Eduardo Barros .set_settings = sc92031_ethtool_set_settings, 13731b6b7172SCesar Eduardo Barros .get_wol = sc92031_ethtool_get_wol, 13741b6b7172SCesar Eduardo Barros .set_wol = sc92031_ethtool_set_wol, 13751b6b7172SCesar Eduardo Barros .nway_reset = sc92031_ethtool_nway_reset, 13761b6b7172SCesar Eduardo Barros .get_link = ethtool_op_get_link, 13771b6b7172SCesar Eduardo Barros .get_strings = sc92031_ethtool_get_strings, 13781b6b7172SCesar Eduardo Barros .get_sset_count = sc92031_ethtool_get_sset_count, 13791b6b7172SCesar Eduardo Barros .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, 13801b6b7172SCesar Eduardo Barros }; 13811b6b7172SCesar Eduardo Barros 13821b6b7172SCesar Eduardo Barros 13831b6b7172SCesar Eduardo Barros static const struct net_device_ops sc92031_netdev_ops = { 13841b6b7172SCesar Eduardo Barros .ndo_get_stats = sc92031_get_stats, 13851b6b7172SCesar Eduardo Barros .ndo_start_xmit = sc92031_start_xmit, 13861b6b7172SCesar Eduardo Barros .ndo_open = sc92031_open, 13871b6b7172SCesar Eduardo Barros .ndo_stop = sc92031_stop, 13881b6b7172SCesar Eduardo Barros .ndo_set_rx_mode = sc92031_set_multicast_list, 13891b6b7172SCesar Eduardo Barros .ndo_change_mtu = eth_change_mtu, 13901b6b7172SCesar Eduardo Barros .ndo_validate_addr = eth_validate_addr, 13911b6b7172SCesar Eduardo Barros .ndo_set_mac_address = eth_mac_addr, 13921b6b7172SCesar Eduardo Barros .ndo_tx_timeout = sc92031_tx_timeout, 13931b6b7172SCesar Eduardo Barros #ifdef CONFIG_NET_POLL_CONTROLLER 13941b6b7172SCesar Eduardo Barros .ndo_poll_controller = sc92031_poll_controller, 13951b6b7172SCesar Eduardo Barros #endif 13961b6b7172SCesar Eduardo Barros }; 13971b6b7172SCesar Eduardo Barros 13981dd06ae8SGreg Kroah-Hartman static int sc92031_probe(struct pci_dev *pdev, const struct pci_device_id *id) 13991b6b7172SCesar Eduardo Barros { 14001b6b7172SCesar Eduardo Barros int err; 14011b6b7172SCesar Eduardo Barros void __iomem* port_base; 14021b6b7172SCesar Eduardo Barros struct net_device *dev; 14031b6b7172SCesar Eduardo Barros struct sc92031_priv *priv; 14041b6b7172SCesar Eduardo Barros u32 mac0, mac1; 14051b6b7172SCesar Eduardo Barros 14061b6b7172SCesar Eduardo Barros err = pci_enable_device(pdev); 14071b6b7172SCesar Eduardo Barros if (unlikely(err < 0)) 14081b6b7172SCesar Eduardo Barros goto out_enable_device; 14091b6b7172SCesar Eduardo Barros 14101b6b7172SCesar Eduardo Barros pci_set_master(pdev); 14111b6b7172SCesar Eduardo Barros 14121b6b7172SCesar Eduardo Barros err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 14131b6b7172SCesar Eduardo Barros if (unlikely(err < 0)) 14141b6b7172SCesar Eduardo Barros goto out_set_dma_mask; 14151b6b7172SCesar Eduardo Barros 14161b6b7172SCesar Eduardo Barros err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 14171b6b7172SCesar Eduardo Barros if (unlikely(err < 0)) 14181b6b7172SCesar Eduardo Barros goto out_set_dma_mask; 14191b6b7172SCesar Eduardo Barros 14201b6b7172SCesar Eduardo Barros err = pci_request_regions(pdev, SC92031_NAME); 14211b6b7172SCesar Eduardo Barros if (unlikely(err < 0)) 14221b6b7172SCesar Eduardo Barros goto out_request_regions; 14231b6b7172SCesar Eduardo Barros 1424c4a9f085SFrancois Romieu port_base = pci_iomap(pdev, SC92031_USE_PIO, 0); 14251b6b7172SCesar Eduardo Barros if (unlikely(!port_base)) { 14261b6b7172SCesar Eduardo Barros err = -EIO; 14271b6b7172SCesar Eduardo Barros goto out_iomap; 14281b6b7172SCesar Eduardo Barros } 14291b6b7172SCesar Eduardo Barros 14301b6b7172SCesar Eduardo Barros dev = alloc_etherdev(sizeof(struct sc92031_priv)); 14311b6b7172SCesar Eduardo Barros if (unlikely(!dev)) { 14321b6b7172SCesar Eduardo Barros err = -ENOMEM; 14331b6b7172SCesar Eduardo Barros goto out_alloc_etherdev; 14341b6b7172SCesar Eduardo Barros } 14351b6b7172SCesar Eduardo Barros 14361b6b7172SCesar Eduardo Barros pci_set_drvdata(pdev, dev); 14371b6b7172SCesar Eduardo Barros SET_NETDEV_DEV(dev, &pdev->dev); 14381b6b7172SCesar Eduardo Barros 14391b6b7172SCesar Eduardo Barros /* faked with skb_copy_and_csum_dev */ 14401b6b7172SCesar Eduardo Barros dev->features = NETIF_F_SG | NETIF_F_HIGHDMA | 14411b6b7172SCesar Eduardo Barros NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 14421b6b7172SCesar Eduardo Barros 14431b6b7172SCesar Eduardo Barros dev->netdev_ops = &sc92031_netdev_ops; 14441b6b7172SCesar Eduardo Barros dev->watchdog_timeo = TX_TIMEOUT; 14451b6b7172SCesar Eduardo Barros dev->ethtool_ops = &sc92031_ethtool_ops; 14461b6b7172SCesar Eduardo Barros 14471b6b7172SCesar Eduardo Barros priv = netdev_priv(dev); 14481b6b7172SCesar Eduardo Barros spin_lock_init(&priv->lock); 14491b6b7172SCesar Eduardo Barros priv->port_base = port_base; 14501b6b7172SCesar Eduardo Barros priv->pdev = pdev; 14511b6b7172SCesar Eduardo Barros tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev); 14521b6b7172SCesar Eduardo Barros /* Fudge tasklet count so the call to sc92031_enable_interrupts at 14531b6b7172SCesar Eduardo Barros * sc92031_open will work correctly */ 14541b6b7172SCesar Eduardo Barros tasklet_disable_nosync(&priv->tasklet); 14551b6b7172SCesar Eduardo Barros 14561b6b7172SCesar Eduardo Barros /* PCI PM Wakeup */ 14571b6b7172SCesar Eduardo Barros iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig); 14581b6b7172SCesar Eduardo Barros 14591b6b7172SCesar Eduardo Barros mac0 = ioread32(port_base + MAC0); 14601b6b7172SCesar Eduardo Barros mac1 = ioread32(port_base + MAC0 + 4); 1461aaeb6cdfSJiri Pirko dev->dev_addr[0] = mac0 >> 24; 1462aaeb6cdfSJiri Pirko dev->dev_addr[1] = mac0 >> 16; 1463aaeb6cdfSJiri Pirko dev->dev_addr[2] = mac0 >> 8; 1464aaeb6cdfSJiri Pirko dev->dev_addr[3] = mac0; 1465aaeb6cdfSJiri Pirko dev->dev_addr[4] = mac1 >> 8; 1466aaeb6cdfSJiri Pirko dev->dev_addr[5] = mac1; 14671b6b7172SCesar Eduardo Barros 14681b6b7172SCesar Eduardo Barros err = register_netdev(dev); 14691b6b7172SCesar Eduardo Barros if (err < 0) 14701b6b7172SCesar Eduardo Barros goto out_register_netdev; 14711b6b7172SCesar Eduardo Barros 14721b6b7172SCesar Eduardo Barros printk(KERN_INFO "%s: SC92031 at 0x%lx, %pM, IRQ %d\n", dev->name, 1473c4a9f085SFrancois Romieu (long)pci_resource_start(pdev, SC92031_USE_PIO), dev->dev_addr, 1474c4a9f085SFrancois Romieu pdev->irq); 14751b6b7172SCesar Eduardo Barros 14761b6b7172SCesar Eduardo Barros return 0; 14771b6b7172SCesar Eduardo Barros 14781b6b7172SCesar Eduardo Barros out_register_netdev: 14791b6b7172SCesar Eduardo Barros free_netdev(dev); 14801b6b7172SCesar Eduardo Barros out_alloc_etherdev: 14811b6b7172SCesar Eduardo Barros pci_iounmap(pdev, port_base); 14821b6b7172SCesar Eduardo Barros out_iomap: 14831b6b7172SCesar Eduardo Barros pci_release_regions(pdev); 14841b6b7172SCesar Eduardo Barros out_request_regions: 14851b6b7172SCesar Eduardo Barros out_set_dma_mask: 14861b6b7172SCesar Eduardo Barros pci_disable_device(pdev); 14871b6b7172SCesar Eduardo Barros out_enable_device: 14881b6b7172SCesar Eduardo Barros return err; 14891b6b7172SCesar Eduardo Barros } 14901b6b7172SCesar Eduardo Barros 149158af79f0SBill Pemberton static void sc92031_remove(struct pci_dev *pdev) 14921b6b7172SCesar Eduardo Barros { 14931b6b7172SCesar Eduardo Barros struct net_device *dev = pci_get_drvdata(pdev); 14941b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 14951b6b7172SCesar Eduardo Barros void __iomem* port_base = priv->port_base; 14961b6b7172SCesar Eduardo Barros 14971b6b7172SCesar Eduardo Barros unregister_netdev(dev); 14981b6b7172SCesar Eduardo Barros free_netdev(dev); 14991b6b7172SCesar Eduardo Barros pci_iounmap(pdev, port_base); 15001b6b7172SCesar Eduardo Barros pci_release_regions(pdev); 15011b6b7172SCesar Eduardo Barros pci_disable_device(pdev); 15021b6b7172SCesar Eduardo Barros } 15031b6b7172SCesar Eduardo Barros 15041b6b7172SCesar Eduardo Barros static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state) 15051b6b7172SCesar Eduardo Barros { 15061b6b7172SCesar Eduardo Barros struct net_device *dev = pci_get_drvdata(pdev); 15071b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 15081b6b7172SCesar Eduardo Barros 15091b6b7172SCesar Eduardo Barros pci_save_state(pdev); 15101b6b7172SCesar Eduardo Barros 15111b6b7172SCesar Eduardo Barros if (!netif_running(dev)) 15121b6b7172SCesar Eduardo Barros goto out; 15131b6b7172SCesar Eduardo Barros 15141b6b7172SCesar Eduardo Barros netif_device_detach(dev); 15151b6b7172SCesar Eduardo Barros 15161b6b7172SCesar Eduardo Barros /* Disable interrupts, stop Tx and Rx. */ 15171b6b7172SCesar Eduardo Barros sc92031_disable_interrupts(dev); 15181b6b7172SCesar Eduardo Barros 15191b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 15201b6b7172SCesar Eduardo Barros 15211b6b7172SCesar Eduardo Barros _sc92031_disable_tx_rx(dev); 15221b6b7172SCesar Eduardo Barros _sc92031_tx_clear(dev); 15231b6b7172SCesar Eduardo Barros mmiowb(); 15241b6b7172SCesar Eduardo Barros 15251b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 15261b6b7172SCesar Eduardo Barros 15271b6b7172SCesar Eduardo Barros out: 15281b6b7172SCesar Eduardo Barros pci_set_power_state(pdev, pci_choose_state(pdev, state)); 15291b6b7172SCesar Eduardo Barros 15301b6b7172SCesar Eduardo Barros return 0; 15311b6b7172SCesar Eduardo Barros } 15321b6b7172SCesar Eduardo Barros 15331b6b7172SCesar Eduardo Barros static int sc92031_resume(struct pci_dev *pdev) 15341b6b7172SCesar Eduardo Barros { 15351b6b7172SCesar Eduardo Barros struct net_device *dev = pci_get_drvdata(pdev); 15361b6b7172SCesar Eduardo Barros struct sc92031_priv *priv = netdev_priv(dev); 15371b6b7172SCesar Eduardo Barros 15381b6b7172SCesar Eduardo Barros pci_restore_state(pdev); 15391b6b7172SCesar Eduardo Barros pci_set_power_state(pdev, PCI_D0); 15401b6b7172SCesar Eduardo Barros 15411b6b7172SCesar Eduardo Barros if (!netif_running(dev)) 15421b6b7172SCesar Eduardo Barros goto out; 15431b6b7172SCesar Eduardo Barros 15441b6b7172SCesar Eduardo Barros /* Interrupts already disabled by sc92031_suspend */ 15451b6b7172SCesar Eduardo Barros spin_lock_bh(&priv->lock); 15461b6b7172SCesar Eduardo Barros 15471b6b7172SCesar Eduardo Barros _sc92031_reset(dev); 15481b6b7172SCesar Eduardo Barros mmiowb(); 15491b6b7172SCesar Eduardo Barros 15501b6b7172SCesar Eduardo Barros spin_unlock_bh(&priv->lock); 15511b6b7172SCesar Eduardo Barros sc92031_enable_interrupts(dev); 15521b6b7172SCesar Eduardo Barros 15531b6b7172SCesar Eduardo Barros netif_device_attach(dev); 15541b6b7172SCesar Eduardo Barros 15551b6b7172SCesar Eduardo Barros if (netif_carrier_ok(dev)) 15561b6b7172SCesar Eduardo Barros netif_wake_queue(dev); 15571b6b7172SCesar Eduardo Barros else 15581b6b7172SCesar Eduardo Barros netif_tx_disable(dev); 15591b6b7172SCesar Eduardo Barros 15601b6b7172SCesar Eduardo Barros out: 15611b6b7172SCesar Eduardo Barros return 0; 15621b6b7172SCesar Eduardo Barros } 15631b6b7172SCesar Eduardo Barros 15641b6b7172SCesar Eduardo Barros static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = { 15651b6b7172SCesar Eduardo Barros { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) }, 15661b6b7172SCesar Eduardo Barros { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) }, 15671b6b7172SCesar Eduardo Barros { PCI_DEVICE(0x1088, 0x2031) }, 15681b6b7172SCesar Eduardo Barros { 0, } 15691b6b7172SCesar Eduardo Barros }; 15701b6b7172SCesar Eduardo Barros MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table); 15711b6b7172SCesar Eduardo Barros 15721b6b7172SCesar Eduardo Barros static struct pci_driver sc92031_pci_driver = { 15731b6b7172SCesar Eduardo Barros .name = SC92031_NAME, 15741b6b7172SCesar Eduardo Barros .id_table = sc92031_pci_device_id_table, 15751b6b7172SCesar Eduardo Barros .probe = sc92031_probe, 157658af79f0SBill Pemberton .remove = sc92031_remove, 15771b6b7172SCesar Eduardo Barros .suspend = sc92031_suspend, 15781b6b7172SCesar Eduardo Barros .resume = sc92031_resume, 15791b6b7172SCesar Eduardo Barros }; 15801b6b7172SCesar Eduardo Barros 15811b6b7172SCesar Eduardo Barros static int __init sc92031_init(void) 15821b6b7172SCesar Eduardo Barros { 15831b6b7172SCesar Eduardo Barros return pci_register_driver(&sc92031_pci_driver); 15841b6b7172SCesar Eduardo Barros } 15851b6b7172SCesar Eduardo Barros 15861b6b7172SCesar Eduardo Barros static void __exit sc92031_exit(void) 15871b6b7172SCesar Eduardo Barros { 15881b6b7172SCesar Eduardo Barros pci_unregister_driver(&sc92031_pci_driver); 15891b6b7172SCesar Eduardo Barros } 15901b6b7172SCesar Eduardo Barros 15911b6b7172SCesar Eduardo Barros module_init(sc92031_init); 15921b6b7172SCesar Eduardo Barros module_exit(sc92031_exit); 15931b6b7172SCesar Eduardo Barros 15941b6b7172SCesar Eduardo Barros MODULE_LICENSE("GPL"); 15951b6b7172SCesar Eduardo Barros MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>"); 15961b6b7172SCesar Eduardo Barros MODULE_DESCRIPTION("Silan SC92031 PCI Fast Ethernet Adapter driver"); 1597