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