18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RDC R6040 Fast Ethernet MAC support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw> 68c2ecf20Sopenharmony_ci * Copyright (C) 2007 78c2ecf20Sopenharmony_ci * Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> 88c2ecf20Sopenharmony_ci * Copyright (C) 2007-2012 Florian Fainelli <f.fainelli@gmail.com> 98c2ecf20Sopenharmony_ci*/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/timer.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/ioport.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 228c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/mii.h> 258c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 268c2ecf20Sopenharmony_ci#include <linux/crc32.h> 278c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 288c2ecf20Sopenharmony_ci#include <linux/bitops.h> 298c2ecf20Sopenharmony_ci#include <linux/io.h> 308c2ecf20Sopenharmony_ci#include <linux/irq.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <linux/phy.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/processor.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRV_NAME "r6040" 378c2ecf20Sopenharmony_ci#define DRV_VERSION "0.29" 388c2ecf20Sopenharmony_ci#define DRV_RELDATE "04Jul2016" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 418c2ecf20Sopenharmony_ci#define TX_TIMEOUT (6000 * HZ / 1000) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* RDC MAC I/O Size */ 448c2ecf20Sopenharmony_ci#define R6040_IO_SIZE 256 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* MAX RDC MAC */ 478c2ecf20Sopenharmony_ci#define MAX_MAC 2 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* MAC registers */ 508c2ecf20Sopenharmony_ci#define MCR0 0x00 /* Control register 0 */ 518c2ecf20Sopenharmony_ci#define MCR0_RCVEN 0x0002 /* Receive enable */ 528c2ecf20Sopenharmony_ci#define MCR0_PROMISC 0x0020 /* Promiscuous mode */ 538c2ecf20Sopenharmony_ci#define MCR0_HASH_EN 0x0100 /* Enable multicast hash table function */ 548c2ecf20Sopenharmony_ci#define MCR0_XMTEN 0x1000 /* Transmission enable */ 558c2ecf20Sopenharmony_ci#define MCR0_FD 0x8000 /* Full/Half duplex */ 568c2ecf20Sopenharmony_ci#define MCR1 0x04 /* Control register 1 */ 578c2ecf20Sopenharmony_ci#define MAC_RST 0x0001 /* Reset the MAC */ 588c2ecf20Sopenharmony_ci#define MBCR 0x08 /* Bus control */ 598c2ecf20Sopenharmony_ci#define MT_ICR 0x0C /* TX interrupt control */ 608c2ecf20Sopenharmony_ci#define MR_ICR 0x10 /* RX interrupt control */ 618c2ecf20Sopenharmony_ci#define MTPR 0x14 /* TX poll command register */ 628c2ecf20Sopenharmony_ci#define TM2TX 0x0001 /* Trigger MAC to transmit */ 638c2ecf20Sopenharmony_ci#define MR_BSR 0x18 /* RX buffer size */ 648c2ecf20Sopenharmony_ci#define MR_DCR 0x1A /* RX descriptor control */ 658c2ecf20Sopenharmony_ci#define MLSR 0x1C /* Last status */ 668c2ecf20Sopenharmony_ci#define TX_FIFO_UNDR 0x0200 /* TX FIFO under-run */ 678c2ecf20Sopenharmony_ci#define TX_EXCEEDC 0x2000 /* Transmit exceed collision */ 688c2ecf20Sopenharmony_ci#define TX_LATEC 0x4000 /* Transmit late collision */ 698c2ecf20Sopenharmony_ci#define MMDIO 0x20 /* MDIO control register */ 708c2ecf20Sopenharmony_ci#define MDIO_WRITE 0x4000 /* MDIO write */ 718c2ecf20Sopenharmony_ci#define MDIO_READ 0x2000 /* MDIO read */ 728c2ecf20Sopenharmony_ci#define MMRD 0x24 /* MDIO read data register */ 738c2ecf20Sopenharmony_ci#define MMWD 0x28 /* MDIO write data register */ 748c2ecf20Sopenharmony_ci#define MTD_SA0 0x2C /* TX descriptor start address 0 */ 758c2ecf20Sopenharmony_ci#define MTD_SA1 0x30 /* TX descriptor start address 1 */ 768c2ecf20Sopenharmony_ci#define MRD_SA0 0x34 /* RX descriptor start address 0 */ 778c2ecf20Sopenharmony_ci#define MRD_SA1 0x38 /* RX descriptor start address 1 */ 788c2ecf20Sopenharmony_ci#define MISR 0x3C /* Status register */ 798c2ecf20Sopenharmony_ci#define MIER 0x40 /* INT enable register */ 808c2ecf20Sopenharmony_ci#define MSK_INT 0x0000 /* Mask off interrupts */ 818c2ecf20Sopenharmony_ci#define RX_FINISH 0x0001 /* RX finished */ 828c2ecf20Sopenharmony_ci#define RX_NO_DESC 0x0002 /* No RX descriptor available */ 838c2ecf20Sopenharmony_ci#define RX_FIFO_FULL 0x0004 /* RX FIFO full */ 848c2ecf20Sopenharmony_ci#define RX_EARLY 0x0008 /* RX early */ 858c2ecf20Sopenharmony_ci#define TX_FINISH 0x0010 /* TX finished */ 868c2ecf20Sopenharmony_ci#define TX_EARLY 0x0080 /* TX early */ 878c2ecf20Sopenharmony_ci#define EVENT_OVRFL 0x0100 /* Event counter overflow */ 888c2ecf20Sopenharmony_ci#define LINK_CHANGED 0x0200 /* PHY link changed */ 898c2ecf20Sopenharmony_ci#define ME_CISR 0x44 /* Event counter INT status */ 908c2ecf20Sopenharmony_ci#define ME_CIER 0x48 /* Event counter INT enable */ 918c2ecf20Sopenharmony_ci#define MR_CNT 0x50 /* Successfully received packet counter */ 928c2ecf20Sopenharmony_ci#define ME_CNT0 0x52 /* Event counter 0 */ 938c2ecf20Sopenharmony_ci#define ME_CNT1 0x54 /* Event counter 1 */ 948c2ecf20Sopenharmony_ci#define ME_CNT2 0x56 /* Event counter 2 */ 958c2ecf20Sopenharmony_ci#define ME_CNT3 0x58 /* Event counter 3 */ 968c2ecf20Sopenharmony_ci#define MT_CNT 0x5A /* Successfully transmit packet counter */ 978c2ecf20Sopenharmony_ci#define ME_CNT4 0x5C /* Event counter 4 */ 988c2ecf20Sopenharmony_ci#define MP_CNT 0x5E /* Pause frame counter register */ 998c2ecf20Sopenharmony_ci#define MAR0 0x60 /* Hash table 0 */ 1008c2ecf20Sopenharmony_ci#define MAR1 0x62 /* Hash table 1 */ 1018c2ecf20Sopenharmony_ci#define MAR2 0x64 /* Hash table 2 */ 1028c2ecf20Sopenharmony_ci#define MAR3 0x66 /* Hash table 3 */ 1038c2ecf20Sopenharmony_ci#define MID_0L 0x68 /* Multicast address MID0 Low */ 1048c2ecf20Sopenharmony_ci#define MID_0M 0x6A /* Multicast address MID0 Medium */ 1058c2ecf20Sopenharmony_ci#define MID_0H 0x6C /* Multicast address MID0 High */ 1068c2ecf20Sopenharmony_ci#define MID_1L 0x70 /* MID1 Low */ 1078c2ecf20Sopenharmony_ci#define MID_1M 0x72 /* MID1 Medium */ 1088c2ecf20Sopenharmony_ci#define MID_1H 0x74 /* MID1 High */ 1098c2ecf20Sopenharmony_ci#define MID_2L 0x78 /* MID2 Low */ 1108c2ecf20Sopenharmony_ci#define MID_2M 0x7A /* MID2 Medium */ 1118c2ecf20Sopenharmony_ci#define MID_2H 0x7C /* MID2 High */ 1128c2ecf20Sopenharmony_ci#define MID_3L 0x80 /* MID3 Low */ 1138c2ecf20Sopenharmony_ci#define MID_3M 0x82 /* MID3 Medium */ 1148c2ecf20Sopenharmony_ci#define MID_3H 0x84 /* MID3 High */ 1158c2ecf20Sopenharmony_ci#define PHY_CC 0x88 /* PHY status change configuration register */ 1168c2ecf20Sopenharmony_ci#define SCEN 0x8000 /* PHY status change enable */ 1178c2ecf20Sopenharmony_ci#define PHYAD_SHIFT 8 /* PHY address shift */ 1188c2ecf20Sopenharmony_ci#define TMRDIV_SHIFT 0 /* Timer divider shift */ 1198c2ecf20Sopenharmony_ci#define PHY_ST 0x8A /* PHY status register */ 1208c2ecf20Sopenharmony_ci#define MAC_SM 0xAC /* MAC status machine */ 1218c2ecf20Sopenharmony_ci#define MAC_SM_RST 0x0002 /* MAC status machine reset */ 1228c2ecf20Sopenharmony_ci#define MD_CSC 0xb6 /* MDC speed control register */ 1238c2ecf20Sopenharmony_ci#define MD_CSC_DEFAULT 0x0030 1248c2ecf20Sopenharmony_ci#define MAC_ID 0xBE /* Identifier register */ 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define TX_DCNT 0x80 /* TX descriptor count */ 1278c2ecf20Sopenharmony_ci#define RX_DCNT 0x80 /* RX descriptor count */ 1288c2ecf20Sopenharmony_ci#define MAX_BUF_SIZE 0x600 1298c2ecf20Sopenharmony_ci#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor)) 1308c2ecf20Sopenharmony_ci#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor)) 1318c2ecf20Sopenharmony_ci#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */ 1328c2ecf20Sopenharmony_ci#define MCAST_MAX 3 /* Max number multicast addresses to filter */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define MAC_DEF_TIMEOUT 2048 /* Default MAC read/write operation timeout */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* Descriptor status */ 1378c2ecf20Sopenharmony_ci#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */ 1388c2ecf20Sopenharmony_ci#define DSC_RX_OK 0x4000 /* RX was successful */ 1398c2ecf20Sopenharmony_ci#define DSC_RX_ERR 0x0800 /* RX PHY error */ 1408c2ecf20Sopenharmony_ci#define DSC_RX_ERR_DRI 0x0400 /* RX dribble packet */ 1418c2ecf20Sopenharmony_ci#define DSC_RX_ERR_BUF 0x0200 /* RX length exceeds buffer size */ 1428c2ecf20Sopenharmony_ci#define DSC_RX_ERR_LONG 0x0100 /* RX length > maximum packet length */ 1438c2ecf20Sopenharmony_ci#define DSC_RX_ERR_RUNT 0x0080 /* RX packet length < 64 byte */ 1448c2ecf20Sopenharmony_ci#define DSC_RX_ERR_CRC 0x0040 /* RX CRC error */ 1458c2ecf20Sopenharmony_ci#define DSC_RX_BCAST 0x0020 /* RX broadcast (no error) */ 1468c2ecf20Sopenharmony_ci#define DSC_RX_MCAST 0x0010 /* RX multicast (no error) */ 1478c2ecf20Sopenharmony_ci#define DSC_RX_MCH_HIT 0x0008 /* RX multicast hit in hash table (no error) */ 1488c2ecf20Sopenharmony_ci#define DSC_RX_MIDH_HIT 0x0004 /* RX MID table hit (no error) */ 1498c2ecf20Sopenharmony_ci#define DSC_RX_IDX_MID_MASK 3 /* RX mask for the index of matched MIDx */ 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>," 1528c2ecf20Sopenharmony_ci "Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>," 1538c2ecf20Sopenharmony_ci "Florian Fainelli <f.fainelli@gmail.com>"); 1548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver"); 1568c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION " " DRV_RELDATE); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* RX and TX interrupts that we handle */ 1598c2ecf20Sopenharmony_ci#define RX_INTS (RX_FIFO_FULL | RX_NO_DESC | RX_FINISH) 1608c2ecf20Sopenharmony_ci#define TX_INTS (TX_FINISH) 1618c2ecf20Sopenharmony_ci#define INT_MASK (RX_INTS | TX_INTS) 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistruct r6040_descriptor { 1648c2ecf20Sopenharmony_ci u16 status, len; /* 0-3 */ 1658c2ecf20Sopenharmony_ci __le32 buf; /* 4-7 */ 1668c2ecf20Sopenharmony_ci __le32 ndesc; /* 8-B */ 1678c2ecf20Sopenharmony_ci u32 rev1; /* C-F */ 1688c2ecf20Sopenharmony_ci char *vbufp; /* 10-13 */ 1698c2ecf20Sopenharmony_ci struct r6040_descriptor *vndescp; /* 14-17 */ 1708c2ecf20Sopenharmony_ci struct sk_buff *skb_ptr; /* 18-1B */ 1718c2ecf20Sopenharmony_ci u32 rev2; /* 1C-1F */ 1728c2ecf20Sopenharmony_ci} __aligned(32); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistruct r6040_private { 1758c2ecf20Sopenharmony_ci spinlock_t lock; /* driver lock */ 1768c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1778c2ecf20Sopenharmony_ci struct r6040_descriptor *rx_insert_ptr; 1788c2ecf20Sopenharmony_ci struct r6040_descriptor *rx_remove_ptr; 1798c2ecf20Sopenharmony_ci struct r6040_descriptor *tx_insert_ptr; 1808c2ecf20Sopenharmony_ci struct r6040_descriptor *tx_remove_ptr; 1818c2ecf20Sopenharmony_ci struct r6040_descriptor *rx_ring; 1828c2ecf20Sopenharmony_ci struct r6040_descriptor *tx_ring; 1838c2ecf20Sopenharmony_ci dma_addr_t rx_ring_dma; 1848c2ecf20Sopenharmony_ci dma_addr_t tx_ring_dma; 1858c2ecf20Sopenharmony_ci u16 tx_free_desc; 1868c2ecf20Sopenharmony_ci u16 mcr0; 1878c2ecf20Sopenharmony_ci struct net_device *dev; 1888c2ecf20Sopenharmony_ci struct mii_bus *mii_bus; 1898c2ecf20Sopenharmony_ci struct napi_struct napi; 1908c2ecf20Sopenharmony_ci void __iomem *base; 1918c2ecf20Sopenharmony_ci int old_link; 1928c2ecf20Sopenharmony_ci int old_duplex; 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic char version[] = DRV_NAME 1968c2ecf20Sopenharmony_ci ": RDC R6040 NAPI net driver," 1978c2ecf20Sopenharmony_ci "version "DRV_VERSION " (" DRV_RELDATE ")"; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* Read a word data from PHY Chip */ 2008c2ecf20Sopenharmony_cistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 2038c2ecf20Sopenharmony_ci u16 cmd; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO); 2068c2ecf20Sopenharmony_ci /* Wait for the read bit to be cleared */ 2078c2ecf20Sopenharmony_ci while (limit--) { 2088c2ecf20Sopenharmony_ci cmd = ioread16(ioaddr + MMDIO); 2098c2ecf20Sopenharmony_ci if (!(cmd & MDIO_READ)) 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci udelay(1); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (limit < 0) 2158c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return ioread16(ioaddr + MMRD); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* Write a word data from PHY Chip */ 2218c2ecf20Sopenharmony_cistatic int r6040_phy_write(void __iomem *ioaddr, 2228c2ecf20Sopenharmony_ci int phy_addr, int reg, u16 val) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 2258c2ecf20Sopenharmony_ci u16 cmd; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci iowrite16(val, ioaddr + MMWD); 2288c2ecf20Sopenharmony_ci /* Write the command to the MDIO bus */ 2298c2ecf20Sopenharmony_ci iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO); 2308c2ecf20Sopenharmony_ci /* Wait for the write bit to be cleared */ 2318c2ecf20Sopenharmony_ci while (limit--) { 2328c2ecf20Sopenharmony_ci cmd = ioread16(ioaddr + MMDIO); 2338c2ecf20Sopenharmony_ci if (!(cmd & MDIO_WRITE)) 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci udelay(1); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return (limit < 0) ? -ETIMEDOUT : 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct net_device *dev = bus->priv; 2448c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 2458c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return r6040_phy_read(ioaddr, phy_addr, reg); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr, 2518c2ecf20Sopenharmony_ci int reg, u16 value) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct net_device *dev = bus->priv; 2548c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 2558c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return r6040_phy_write(ioaddr, phy_addr, reg, value); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void r6040_free_txbufs(struct net_device *dev) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 2638c2ecf20Sopenharmony_ci int i; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci for (i = 0; i < TX_DCNT; i++) { 2668c2ecf20Sopenharmony_ci if (lp->tx_insert_ptr->skb_ptr) { 2678c2ecf20Sopenharmony_ci dma_unmap_single(&lp->pdev->dev, 2688c2ecf20Sopenharmony_ci le32_to_cpu(lp->tx_insert_ptr->buf), 2698c2ecf20Sopenharmony_ci MAX_BUF_SIZE, DMA_TO_DEVICE); 2708c2ecf20Sopenharmony_ci dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); 2718c2ecf20Sopenharmony_ci lp->tx_insert_ptr->skb_ptr = NULL; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void r6040_free_rxbufs(struct net_device *dev) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 2808c2ecf20Sopenharmony_ci int i; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < RX_DCNT; i++) { 2838c2ecf20Sopenharmony_ci if (lp->rx_insert_ptr->skb_ptr) { 2848c2ecf20Sopenharmony_ci dma_unmap_single(&lp->pdev->dev, 2858c2ecf20Sopenharmony_ci le32_to_cpu(lp->rx_insert_ptr->buf), 2868c2ecf20Sopenharmony_ci MAX_BUF_SIZE, DMA_FROM_DEVICE); 2878c2ecf20Sopenharmony_ci dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); 2888c2ecf20Sopenharmony_ci lp->rx_insert_ptr->skb_ptr = NULL; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, 2958c2ecf20Sopenharmony_ci dma_addr_t desc_dma, int size) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct r6040_descriptor *desc = desc_ring; 2988c2ecf20Sopenharmony_ci dma_addr_t mapping = desc_dma; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci while (size-- > 0) { 3018c2ecf20Sopenharmony_ci mapping += sizeof(*desc); 3028c2ecf20Sopenharmony_ci desc->ndesc = cpu_to_le32(mapping); 3038c2ecf20Sopenharmony_ci desc->vndescp = desc + 1; 3048c2ecf20Sopenharmony_ci desc++; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci desc--; 3078c2ecf20Sopenharmony_ci desc->ndesc = cpu_to_le32(desc_dma); 3088c2ecf20Sopenharmony_ci desc->vndescp = desc_ring; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void r6040_init_txbufs(struct net_device *dev) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci lp->tx_free_desc = TX_DCNT; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; 3188c2ecf20Sopenharmony_ci r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int r6040_alloc_rxbufs(struct net_device *dev) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 3248c2ecf20Sopenharmony_ci struct r6040_descriptor *desc; 3258c2ecf20Sopenharmony_ci struct sk_buff *skb; 3268c2ecf20Sopenharmony_ci int rc; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; 3298c2ecf20Sopenharmony_ci r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Allocate skbs for the rx descriptors */ 3328c2ecf20Sopenharmony_ci desc = lp->rx_ring; 3338c2ecf20Sopenharmony_ci do { 3348c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); 3358c2ecf20Sopenharmony_ci if (!skb) { 3368c2ecf20Sopenharmony_ci rc = -ENOMEM; 3378c2ecf20Sopenharmony_ci goto err_exit; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci desc->skb_ptr = skb; 3408c2ecf20Sopenharmony_ci desc->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, 3418c2ecf20Sopenharmony_ci desc->skb_ptr->data, 3428c2ecf20Sopenharmony_ci MAX_BUF_SIZE, 3438c2ecf20Sopenharmony_ci DMA_FROM_DEVICE)); 3448c2ecf20Sopenharmony_ci desc->status = DSC_OWNER_MAC; 3458c2ecf20Sopenharmony_ci desc = desc->vndescp; 3468c2ecf20Sopenharmony_ci } while (desc != lp->rx_ring); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cierr_exit: 3518c2ecf20Sopenharmony_ci /* Deallocate all previously allocated skbs */ 3528c2ecf20Sopenharmony_ci r6040_free_rxbufs(dev); 3538c2ecf20Sopenharmony_ci return rc; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void r6040_reset_mac(struct r6040_private *lp) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 3598c2ecf20Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 3608c2ecf20Sopenharmony_ci u16 cmd, md_csc; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci md_csc = ioread16(ioaddr + MD_CSC); 3638c2ecf20Sopenharmony_ci iowrite16(MAC_RST, ioaddr + MCR1); 3648c2ecf20Sopenharmony_ci while (limit--) { 3658c2ecf20Sopenharmony_ci cmd = ioread16(ioaddr + MCR1); 3668c2ecf20Sopenharmony_ci if (cmd & MAC_RST) 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Reset internal state machine */ 3718c2ecf20Sopenharmony_ci iowrite16(MAC_SM_RST, ioaddr + MAC_SM); 3728c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MAC_SM); 3738c2ecf20Sopenharmony_ci mdelay(5); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Restore MDIO clock frequency */ 3768c2ecf20Sopenharmony_ci if (md_csc != MD_CSC_DEFAULT) 3778c2ecf20Sopenharmony_ci iowrite16(md_csc, ioaddr + MD_CSC); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void r6040_init_mac_regs(struct net_device *dev) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 3838c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Mask Off Interrupt */ 3868c2ecf20Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Reset RDC MAC */ 3898c2ecf20Sopenharmony_ci r6040_reset_mac(lp); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* MAC Bus Control Register */ 3928c2ecf20Sopenharmony_ci iowrite16(MBCR_DEFAULT, ioaddr + MBCR); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* Buffer Size Register */ 3958c2ecf20Sopenharmony_ci iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Write TX ring start address */ 3988c2ecf20Sopenharmony_ci iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); 3998c2ecf20Sopenharmony_ci iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Write RX ring start address */ 4028c2ecf20Sopenharmony_ci iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); 4038c2ecf20Sopenharmony_ci iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Set interrupt waiting time and packet numbers */ 4068c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MT_ICR); 4078c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MR_ICR); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Enable interrupts */ 4108c2ecf20Sopenharmony_ci iowrite16(INT_MASK, ioaddr + MIER); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Enable TX and RX */ 4138c2ecf20Sopenharmony_ci iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Let TX poll the descriptors 4168c2ecf20Sopenharmony_ci * we may got called by r6040_tx_timeout which has left 4178c2ecf20Sopenharmony_ci * some unsent tx buffers */ 4188c2ecf20Sopenharmony_ci iowrite16(TM2TX, ioaddr + MTPR); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void r6040_tx_timeout(struct net_device *dev, unsigned int txqueue) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 4248c2ecf20Sopenharmony_ci void __iomem *ioaddr = priv->base; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci netdev_warn(dev, "transmit timed out, int enable %4.4x " 4278c2ecf20Sopenharmony_ci "status %4.4x\n", 4288c2ecf20Sopenharmony_ci ioread16(ioaddr + MIER), 4298c2ecf20Sopenharmony_ci ioread16(ioaddr + MISR)); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Reset MAC and re-init all registers */ 4348c2ecf20Sopenharmony_ci r6040_init_mac_regs(dev); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic struct net_device_stats *r6040_get_stats(struct net_device *dev) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 4408c2ecf20Sopenharmony_ci void __iomem *ioaddr = priv->base; 4418c2ecf20Sopenharmony_ci unsigned long flags; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 4448c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); 4458c2ecf20Sopenharmony_ci dev->stats.multicast += ioread8(ioaddr + ME_CNT0); 4468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return &dev->stats; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci/* Stop RDC MAC and Free the allocated resource */ 4528c2ecf20Sopenharmony_cistatic void r6040_down(struct net_device *dev) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 4558c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 4568c2ecf20Sopenharmony_ci u16 *adrp; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Stop MAC */ 4598c2ecf20Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Reset RDC MAC */ 4628c2ecf20Sopenharmony_ci r6040_reset_mac(lp); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Restore MAC Address to MIDx */ 4658c2ecf20Sopenharmony_ci adrp = (u16 *) dev->dev_addr; 4668c2ecf20Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 4678c2ecf20Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 4688c2ecf20Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic int r6040_close(struct net_device *dev) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 4748c2ecf20Sopenharmony_ci struct pci_dev *pdev = lp->pdev; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci phy_stop(dev->phydev); 4778c2ecf20Sopenharmony_ci napi_disable(&lp->napi); 4788c2ecf20Sopenharmony_ci netif_stop_queue(dev); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci spin_lock_irq(&lp->lock); 4818c2ecf20Sopenharmony_ci r6040_down(dev); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Free RX buffer */ 4848c2ecf20Sopenharmony_ci r6040_free_rxbufs(dev); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Free TX buffer */ 4878c2ecf20Sopenharmony_ci r6040_free_txbufs(dev); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci spin_unlock_irq(&lp->lock); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Free Descriptor memory */ 4948c2ecf20Sopenharmony_ci if (lp->rx_ring) { 4958c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_DESC_SIZE, lp->rx_ring, 4968c2ecf20Sopenharmony_ci lp->rx_ring_dma); 4978c2ecf20Sopenharmony_ci lp->rx_ring = NULL; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (lp->tx_ring) { 5018c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_DESC_SIZE, lp->tx_ring, 5028c2ecf20Sopenharmony_ci lp->tx_ring_dma); 5038c2ecf20Sopenharmony_ci lp->tx_ring = NULL; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int r6040_rx(struct net_device *dev, int limit) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 5128c2ecf20Sopenharmony_ci struct r6040_descriptor *descptr = priv->rx_remove_ptr; 5138c2ecf20Sopenharmony_ci struct sk_buff *skb_ptr, *new_skb; 5148c2ecf20Sopenharmony_ci int count = 0; 5158c2ecf20Sopenharmony_ci u16 err; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Limit not reached and the descriptor belongs to the CPU */ 5188c2ecf20Sopenharmony_ci while (count < limit && !(descptr->status & DSC_OWNER_MAC)) { 5198c2ecf20Sopenharmony_ci /* Read the descriptor status */ 5208c2ecf20Sopenharmony_ci err = descptr->status; 5218c2ecf20Sopenharmony_ci /* Global error status set */ 5228c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR) { 5238c2ecf20Sopenharmony_ci /* RX dribble */ 5248c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR_DRI) 5258c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 5268c2ecf20Sopenharmony_ci /* Buffer length exceeded */ 5278c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR_BUF) 5288c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 5298c2ecf20Sopenharmony_ci /* Packet too long */ 5308c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR_LONG) 5318c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 5328c2ecf20Sopenharmony_ci /* Packet < 64 bytes */ 5338c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR_RUNT) 5348c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 5358c2ecf20Sopenharmony_ci /* CRC error */ 5368c2ecf20Sopenharmony_ci if (err & DSC_RX_ERR_CRC) { 5378c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 5388c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 5398c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci goto next_descr; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Packet successfully received */ 5458c2ecf20Sopenharmony_ci new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); 5468c2ecf20Sopenharmony_ci if (!new_skb) { 5478c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 5488c2ecf20Sopenharmony_ci goto next_descr; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci skb_ptr = descptr->skb_ptr; 5518c2ecf20Sopenharmony_ci skb_ptr->dev = priv->dev; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Do not count the CRC */ 5548c2ecf20Sopenharmony_ci skb_put(skb_ptr, descptr->len - 4); 5558c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf), 5568c2ecf20Sopenharmony_ci MAX_BUF_SIZE, DMA_FROM_DEVICE); 5578c2ecf20Sopenharmony_ci skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Send to upper layer */ 5608c2ecf20Sopenharmony_ci netif_receive_skb(skb_ptr); 5618c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 5628c2ecf20Sopenharmony_ci dev->stats.rx_bytes += descptr->len - 4; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* put new skb into descriptor */ 5658c2ecf20Sopenharmony_ci descptr->skb_ptr = new_skb; 5668c2ecf20Sopenharmony_ci descptr->buf = cpu_to_le32(dma_map_single(&priv->pdev->dev, 5678c2ecf20Sopenharmony_ci descptr->skb_ptr->data, 5688c2ecf20Sopenharmony_ci MAX_BUF_SIZE, 5698c2ecf20Sopenharmony_ci DMA_FROM_DEVICE)); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cinext_descr: 5728c2ecf20Sopenharmony_ci /* put the descriptor back to the MAC */ 5738c2ecf20Sopenharmony_ci descptr->status = DSC_OWNER_MAC; 5748c2ecf20Sopenharmony_ci descptr = descptr->vndescp; 5758c2ecf20Sopenharmony_ci count++; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci priv->rx_remove_ptr = descptr; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return count; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void r6040_tx(struct net_device *dev) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 5858c2ecf20Sopenharmony_ci struct r6040_descriptor *descptr; 5868c2ecf20Sopenharmony_ci void __iomem *ioaddr = priv->base; 5878c2ecf20Sopenharmony_ci struct sk_buff *skb_ptr; 5888c2ecf20Sopenharmony_ci u16 err; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 5918c2ecf20Sopenharmony_ci descptr = priv->tx_remove_ptr; 5928c2ecf20Sopenharmony_ci while (priv->tx_free_desc < TX_DCNT) { 5938c2ecf20Sopenharmony_ci /* Check for errors */ 5948c2ecf20Sopenharmony_ci err = ioread16(ioaddr + MLSR); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (err & TX_FIFO_UNDR) 5978c2ecf20Sopenharmony_ci dev->stats.tx_fifo_errors++; 5988c2ecf20Sopenharmony_ci if (err & (TX_EXCEEDC | TX_LATEC)) 5998c2ecf20Sopenharmony_ci dev->stats.tx_carrier_errors++; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (descptr->status & DSC_OWNER_MAC) 6028c2ecf20Sopenharmony_ci break; /* Not complete */ 6038c2ecf20Sopenharmony_ci skb_ptr = descptr->skb_ptr; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* Statistic Counter */ 6068c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 6078c2ecf20Sopenharmony_ci dev->stats.tx_bytes += skb_ptr->len; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf), 6108c2ecf20Sopenharmony_ci skb_ptr->len, DMA_TO_DEVICE); 6118c2ecf20Sopenharmony_ci /* Free buffer */ 6128c2ecf20Sopenharmony_ci dev_kfree_skb(skb_ptr); 6138c2ecf20Sopenharmony_ci descptr->skb_ptr = NULL; 6148c2ecf20Sopenharmony_ci /* To next descriptor */ 6158c2ecf20Sopenharmony_ci descptr = descptr->vndescp; 6168c2ecf20Sopenharmony_ci priv->tx_free_desc++; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci priv->tx_remove_ptr = descptr; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (priv->tx_free_desc) 6218c2ecf20Sopenharmony_ci netif_wake_queue(dev); 6228c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int r6040_poll(struct napi_struct *napi, int budget) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct r6040_private *priv = 6288c2ecf20Sopenharmony_ci container_of(napi, struct r6040_private, napi); 6298c2ecf20Sopenharmony_ci struct net_device *dev = priv->dev; 6308c2ecf20Sopenharmony_ci void __iomem *ioaddr = priv->base; 6318c2ecf20Sopenharmony_ci int work_done; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci r6040_tx(dev); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci work_done = r6040_rx(dev, budget); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (work_done < budget) { 6388c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 6398c2ecf20Sopenharmony_ci /* Enable RX/TX interrupt */ 6408c2ecf20Sopenharmony_ci iowrite16(ioread16(ioaddr + MIER) | RX_INTS | TX_INTS, 6418c2ecf20Sopenharmony_ci ioaddr + MIER); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci return work_done; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/* The RDC interrupt handler. */ 6478c2ecf20Sopenharmony_cistatic irqreturn_t r6040_interrupt(int irq, void *dev_id) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 6508c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 6518c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 6528c2ecf20Sopenharmony_ci u16 misr, status; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Save MIER */ 6558c2ecf20Sopenharmony_ci misr = ioread16(ioaddr + MIER); 6568c2ecf20Sopenharmony_ci /* Mask off RDC MAC interrupt */ 6578c2ecf20Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); 6588c2ecf20Sopenharmony_ci /* Read MISR status and clear */ 6598c2ecf20Sopenharmony_ci status = ioread16(ioaddr + MISR); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (status == 0x0000 || status == 0xffff) { 6628c2ecf20Sopenharmony_ci /* Restore RDC MAC interrupt */ 6638c2ecf20Sopenharmony_ci iowrite16(misr, ioaddr + MIER); 6648c2ecf20Sopenharmony_ci return IRQ_NONE; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* RX interrupt request */ 6688c2ecf20Sopenharmony_ci if (status & (RX_INTS | TX_INTS)) { 6698c2ecf20Sopenharmony_ci if (status & RX_NO_DESC) { 6708c2ecf20Sopenharmony_ci /* RX descriptor unavailable */ 6718c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 6728c2ecf20Sopenharmony_ci dev->stats.rx_missed_errors++; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci if (status & RX_FIFO_FULL) 6758c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (likely(napi_schedule_prep(&lp->napi))) { 6788c2ecf20Sopenharmony_ci /* Mask off RX interrupt */ 6798c2ecf20Sopenharmony_ci misr &= ~(RX_INTS | TX_INTS); 6808c2ecf20Sopenharmony_ci __napi_schedule_irqoff(&lp->napi); 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Restore RDC MAC interrupt */ 6858c2ecf20Sopenharmony_ci iowrite16(misr, ioaddr + MIER); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 6918c2ecf20Sopenharmony_cistatic void r6040_poll_controller(struct net_device *dev) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci disable_irq(dev->irq); 6948c2ecf20Sopenharmony_ci r6040_interrupt(dev->irq, dev); 6958c2ecf20Sopenharmony_ci enable_irq(dev->irq); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci#endif 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/* Init RDC MAC */ 7008c2ecf20Sopenharmony_cistatic int r6040_up(struct net_device *dev) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 7038c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 7048c2ecf20Sopenharmony_ci int ret; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Initialise and alloc RX/TX buffers */ 7078c2ecf20Sopenharmony_ci r6040_init_txbufs(dev); 7088c2ecf20Sopenharmony_ci ret = r6040_alloc_rxbufs(dev); 7098c2ecf20Sopenharmony_ci if (ret) 7108c2ecf20Sopenharmony_ci return ret; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* improve performance (by RDC guys) */ 7138c2ecf20Sopenharmony_ci r6040_phy_write(ioaddr, 30, 17, 7148c2ecf20Sopenharmony_ci (r6040_phy_read(ioaddr, 30, 17) | 0x4000)); 7158c2ecf20Sopenharmony_ci r6040_phy_write(ioaddr, 30, 17, 7168c2ecf20Sopenharmony_ci ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000)); 7178c2ecf20Sopenharmony_ci r6040_phy_write(ioaddr, 0, 19, 0x0000); 7188c2ecf20Sopenharmony_ci r6040_phy_write(ioaddr, 0, 30, 0x01F0); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* Initialize all MAC registers */ 7218c2ecf20Sopenharmony_ci r6040_init_mac_regs(dev); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci phy_start(dev->phydev); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/* Read/set MAC address routines */ 7308c2ecf20Sopenharmony_cistatic void r6040_mac_address(struct net_device *dev) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 7338c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 7348c2ecf20Sopenharmony_ci u16 *adrp; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Reset MAC */ 7378c2ecf20Sopenharmony_ci r6040_reset_mac(lp); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Restore MAC Address */ 7408c2ecf20Sopenharmony_ci adrp = (u16 *) dev->dev_addr; 7418c2ecf20Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 7428c2ecf20Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 7438c2ecf20Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int r6040_open(struct net_device *dev) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 7498c2ecf20Sopenharmony_ci int ret; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Request IRQ and Register interrupt handler */ 7528c2ecf20Sopenharmony_ci ret = request_irq(dev->irq, r6040_interrupt, 7538c2ecf20Sopenharmony_ci IRQF_SHARED, dev->name, dev); 7548c2ecf20Sopenharmony_ci if (ret) 7558c2ecf20Sopenharmony_ci goto out; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* Set MAC address */ 7588c2ecf20Sopenharmony_ci r6040_mac_address(dev); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Allocate Descriptor memory */ 7618c2ecf20Sopenharmony_ci lp->rx_ring = 7628c2ecf20Sopenharmony_ci dma_alloc_coherent(&lp->pdev->dev, RX_DESC_SIZE, 7638c2ecf20Sopenharmony_ci &lp->rx_ring_dma, GFP_KERNEL); 7648c2ecf20Sopenharmony_ci if (!lp->rx_ring) { 7658c2ecf20Sopenharmony_ci ret = -ENOMEM; 7668c2ecf20Sopenharmony_ci goto err_free_irq; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci lp->tx_ring = 7708c2ecf20Sopenharmony_ci dma_alloc_coherent(&lp->pdev->dev, TX_DESC_SIZE, 7718c2ecf20Sopenharmony_ci &lp->tx_ring_dma, GFP_KERNEL); 7728c2ecf20Sopenharmony_ci if (!lp->tx_ring) { 7738c2ecf20Sopenharmony_ci ret = -ENOMEM; 7748c2ecf20Sopenharmony_ci goto err_free_rx_ring; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ret = r6040_up(dev); 7788c2ecf20Sopenharmony_ci if (ret) 7798c2ecf20Sopenharmony_ci goto err_free_tx_ring; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci napi_enable(&lp->napi); 7828c2ecf20Sopenharmony_ci netif_start_queue(dev); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return 0; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cierr_free_tx_ring: 7878c2ecf20Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, TX_DESC_SIZE, lp->tx_ring, 7888c2ecf20Sopenharmony_ci lp->tx_ring_dma); 7898c2ecf20Sopenharmony_cierr_free_rx_ring: 7908c2ecf20Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, RX_DESC_SIZE, lp->rx_ring, 7918c2ecf20Sopenharmony_ci lp->rx_ring_dma); 7928c2ecf20Sopenharmony_cierr_free_irq: 7938c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 7948c2ecf20Sopenharmony_ciout: 7958c2ecf20Sopenharmony_ci return ret; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb, 7998c2ecf20Sopenharmony_ci struct net_device *dev) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 8028c2ecf20Sopenharmony_ci struct r6040_descriptor *descptr; 8038c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 8048c2ecf20Sopenharmony_ci unsigned long flags; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (skb_put_padto(skb, ETH_ZLEN) < 0) 8078c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Critical Section */ 8108c2ecf20Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* TX resource check */ 8138c2ecf20Sopenharmony_ci if (!lp->tx_free_desc) { 8148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 8158c2ecf20Sopenharmony_ci netif_stop_queue(dev); 8168c2ecf20Sopenharmony_ci netdev_err(dev, ": no tx descriptor\n"); 8178c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* Set TX descriptor & Transmit it */ 8218c2ecf20Sopenharmony_ci lp->tx_free_desc--; 8228c2ecf20Sopenharmony_ci descptr = lp->tx_insert_ptr; 8238c2ecf20Sopenharmony_ci descptr->len = skb->len; 8248c2ecf20Sopenharmony_ci descptr->skb_ptr = skb; 8258c2ecf20Sopenharmony_ci descptr->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, skb->data, 8268c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE)); 8278c2ecf20Sopenharmony_ci descptr->status = DSC_OWNER_MAC; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Trigger the MAC to check the TX descriptor */ 8328c2ecf20Sopenharmony_ci if (!netdev_xmit_more() || netif_queue_stopped(dev)) 8338c2ecf20Sopenharmony_ci iowrite16(TM2TX, ioaddr + MTPR); 8348c2ecf20Sopenharmony_ci lp->tx_insert_ptr = descptr->vndescp; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* If no tx resource, stop */ 8378c2ecf20Sopenharmony_ci if (!lp->tx_free_desc) 8388c2ecf20Sopenharmony_ci netif_stop_queue(dev); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void r6040_multicast_list(struct net_device *dev) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 8488c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 8498c2ecf20Sopenharmony_ci unsigned long flags; 8508c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 8518c2ecf20Sopenharmony_ci int i; 8528c2ecf20Sopenharmony_ci u16 *adrp; 8538c2ecf20Sopenharmony_ci u16 hash_table[4] = { 0 }; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Keep our MAC Address */ 8588c2ecf20Sopenharmony_ci adrp = (u16 *)dev->dev_addr; 8598c2ecf20Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 8608c2ecf20Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 8618c2ecf20Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Clear AMCP & PROM bits */ 8648c2ecf20Sopenharmony_ci lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Promiscuous mode */ 8678c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) 8688c2ecf20Sopenharmony_ci lp->mcr0 |= MCR0_PROMISC; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* Enable multicast hash table function to 8718c2ecf20Sopenharmony_ci * receive all multicast packets. */ 8728c2ecf20Sopenharmony_ci else if (dev->flags & IFF_ALLMULTI) { 8738c2ecf20Sopenharmony_ci lp->mcr0 |= MCR0_HASH_EN; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci for (i = 0; i < MCAST_MAX ; i++) { 8768c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 8778c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 8788c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 8828c2ecf20Sopenharmony_ci hash_table[i] = 0xffff; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci /* Use internal multicast address registers if the number of 8858c2ecf20Sopenharmony_ci * multicast addresses is not greater than MCAST_MAX. */ 8868c2ecf20Sopenharmony_ci else if (netdev_mc_count(dev) <= MCAST_MAX) { 8878c2ecf20Sopenharmony_ci i = 0; 8888c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 8898c2ecf20Sopenharmony_ci u16 *adrp = (u16 *) ha->addr; 8908c2ecf20Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); 8918c2ecf20Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); 8928c2ecf20Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); 8938c2ecf20Sopenharmony_ci i++; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci while (i < MCAST_MAX) { 8968c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 8978c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 8988c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 8998c2ecf20Sopenharmony_ci i++; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci /* Otherwise, Enable multicast hash table function. */ 9038c2ecf20Sopenharmony_ci else { 9048c2ecf20Sopenharmony_ci u32 crc; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci lp->mcr0 |= MCR0_HASH_EN; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci for (i = 0; i < MCAST_MAX ; i++) { 9098c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 9108c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 9118c2ecf20Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* Build multicast hash table */ 9158c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 9168c2ecf20Sopenharmony_ci u8 *addrs = ha->addr; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci crc = ether_crc(ETH_ALEN, addrs); 9198c2ecf20Sopenharmony_ci crc >>= 26; 9208c2ecf20Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci iowrite16(lp->mcr0, ioaddr + MCR0); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* Fill the MAC hash tables with their values */ 9278c2ecf20Sopenharmony_ci if (lp->mcr0 & MCR0_HASH_EN) { 9288c2ecf20Sopenharmony_ci iowrite16(hash_table[0], ioaddr + MAR0); 9298c2ecf20Sopenharmony_ci iowrite16(hash_table[1], ioaddr + MAR1); 9308c2ecf20Sopenharmony_ci iowrite16(hash_table[2], ioaddr + MAR2); 9318c2ecf20Sopenharmony_ci iowrite16(hash_table[3], ioaddr + MAR3); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, 9388c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct r6040_private *rp = netdev_priv(dev); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 9438c2ecf20Sopenharmony_ci strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 9448c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info)); 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 9488c2ecf20Sopenharmony_ci .get_drvinfo = netdev_get_drvinfo, 9498c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 9508c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 9518c2ecf20Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 9528c2ecf20Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 9538c2ecf20Sopenharmony_ci}; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic const struct net_device_ops r6040_netdev_ops = { 9568c2ecf20Sopenharmony_ci .ndo_open = r6040_open, 9578c2ecf20Sopenharmony_ci .ndo_stop = r6040_close, 9588c2ecf20Sopenharmony_ci .ndo_start_xmit = r6040_start_xmit, 9598c2ecf20Sopenharmony_ci .ndo_get_stats = r6040_get_stats, 9608c2ecf20Sopenharmony_ci .ndo_set_rx_mode = r6040_multicast_list, 9618c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 9628c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 9638c2ecf20Sopenharmony_ci .ndo_do_ioctl = phy_do_ioctl, 9648c2ecf20Sopenharmony_ci .ndo_tx_timeout = r6040_tx_timeout, 9658c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 9668c2ecf20Sopenharmony_ci .ndo_poll_controller = r6040_poll_controller, 9678c2ecf20Sopenharmony_ci#endif 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic void r6040_adjust_link(struct net_device *dev) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 9738c2ecf20Sopenharmony_ci struct phy_device *phydev = dev->phydev; 9748c2ecf20Sopenharmony_ci int status_changed = 0; 9758c2ecf20Sopenharmony_ci void __iomem *ioaddr = lp->base; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci BUG_ON(!phydev); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (lp->old_link != phydev->link) { 9808c2ecf20Sopenharmony_ci status_changed = 1; 9818c2ecf20Sopenharmony_ci lp->old_link = phydev->link; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* reflect duplex change */ 9858c2ecf20Sopenharmony_ci if (phydev->link && (lp->old_duplex != phydev->duplex)) { 9868c2ecf20Sopenharmony_ci lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0); 9878c2ecf20Sopenharmony_ci iowrite16(lp->mcr0, ioaddr); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci status_changed = 1; 9908c2ecf20Sopenharmony_ci lp->old_duplex = phydev->duplex; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (status_changed) 9948c2ecf20Sopenharmony_ci phy_print_status(phydev); 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int r6040_mii_probe(struct net_device *dev) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 10008c2ecf20Sopenharmony_ci struct phy_device *phydev = NULL; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci phydev = phy_find_first(lp->mii_bus); 10038c2ecf20Sopenharmony_ci if (!phydev) { 10048c2ecf20Sopenharmony_ci dev_err(&lp->pdev->dev, "no PHY found\n"); 10058c2ecf20Sopenharmony_ci return -ENODEV; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci phydev = phy_connect(dev, phydev_name(phydev), &r6040_adjust_link, 10098c2ecf20Sopenharmony_ci PHY_INTERFACE_MODE_MII); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (IS_ERR(phydev)) { 10128c2ecf20Sopenharmony_ci dev_err(&lp->pdev->dev, "could not attach to PHY\n"); 10138c2ecf20Sopenharmony_ci return PTR_ERR(phydev); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci phy_set_max_speed(phydev, SPEED_100); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci lp->old_link = 0; 10198c2ecf20Sopenharmony_ci lp->old_duplex = -1; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci phy_attached_info(phydev); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci return 0; 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct net_device *dev; 10298c2ecf20Sopenharmony_ci struct r6040_private *lp; 10308c2ecf20Sopenharmony_ci void __iomem *ioaddr; 10318c2ecf20Sopenharmony_ci int err, io_size = R6040_IO_SIZE; 10328c2ecf20Sopenharmony_ci static int card_idx = -1; 10338c2ecf20Sopenharmony_ci int bar = 0; 10348c2ecf20Sopenharmony_ci u16 *adrp; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci pr_info("%s\n", version); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 10398c2ecf20Sopenharmony_ci if (err) 10408c2ecf20Sopenharmony_ci goto err_out; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* this should always be supported */ 10438c2ecf20Sopenharmony_ci err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 10448c2ecf20Sopenharmony_ci if (err) { 10458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n"); 10468c2ecf20Sopenharmony_ci goto err_out_disable_dev; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 10498c2ecf20Sopenharmony_ci if (err) { 10508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n"); 10518c2ecf20Sopenharmony_ci goto err_out_disable_dev; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* IO Size check */ 10558c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, bar) < io_size) { 10568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); 10578c2ecf20Sopenharmony_ci err = -EIO; 10588c2ecf20Sopenharmony_ci goto err_out_disable_dev; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci pci_set_master(pdev); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct r6040_private)); 10648c2ecf20Sopenharmony_ci if (!dev) { 10658c2ecf20Sopenharmony_ci err = -ENOMEM; 10668c2ecf20Sopenharmony_ci goto err_out_disable_dev; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 10698c2ecf20Sopenharmony_ci lp = netdev_priv(dev); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (err) { 10748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to request PCI regions\n"); 10758c2ecf20Sopenharmony_ci goto err_out_free_dev; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci ioaddr = pci_iomap(pdev, bar, io_size); 10798c2ecf20Sopenharmony_ci if (!ioaddr) { 10808c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed for device\n"); 10818c2ecf20Sopenharmony_ci err = -EIO; 10828c2ecf20Sopenharmony_ci goto err_out_free_res; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* If PHY status change register is still set to zero it means the 10868c2ecf20Sopenharmony_ci * bootloader didn't initialize it, so we set it to: 10878c2ecf20Sopenharmony_ci * - enable phy status change 10888c2ecf20Sopenharmony_ci * - enable all phy addresses 10898c2ecf20Sopenharmony_ci * - set to lowest timer divider */ 10908c2ecf20Sopenharmony_ci if (ioread16(ioaddr + PHY_CC) == 0) 10918c2ecf20Sopenharmony_ci iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT | 10928c2ecf20Sopenharmony_ci 7 << TMRDIV_SHIFT, ioaddr + PHY_CC); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* Init system & device */ 10958c2ecf20Sopenharmony_ci lp->base = ioaddr; 10968c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci spin_lock_init(&lp->lock); 10998c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Set MAC address */ 11028c2ecf20Sopenharmony_ci card_idx++; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci adrp = (u16 *)dev->dev_addr; 11058c2ecf20Sopenharmony_ci adrp[0] = ioread16(ioaddr + MID_0L); 11068c2ecf20Sopenharmony_ci adrp[1] = ioread16(ioaddr + MID_0M); 11078c2ecf20Sopenharmony_ci adrp[2] = ioread16(ioaddr + MID_0H); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* Some bootloader/BIOSes do not initialize 11108c2ecf20Sopenharmony_ci * MAC address, warn about that */ 11118c2ecf20Sopenharmony_ci if (!(adrp[0] || adrp[1] || adrp[2])) { 11128c2ecf20Sopenharmony_ci netdev_warn(dev, "MAC address not initialized, " 11138c2ecf20Sopenharmony_ci "generating random\n"); 11148c2ecf20Sopenharmony_ci eth_hw_addr_random(dev); 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Link new device into r6040_root_dev */ 11188c2ecf20Sopenharmony_ci lp->pdev = pdev; 11198c2ecf20Sopenharmony_ci lp->dev = dev; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Init RDC private data */ 11228c2ecf20Sopenharmony_ci lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* The RDC-specific entries in the device structure. */ 11258c2ecf20Sopenharmony_ci dev->netdev_ops = &r6040_netdev_ops; 11268c2ecf20Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 11278c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci netif_napi_add(dev, &lp->napi, r6040_poll, 64); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci lp->mii_bus = mdiobus_alloc(); 11328c2ecf20Sopenharmony_ci if (!lp->mii_bus) { 11338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "mdiobus_alloc() failed\n"); 11348c2ecf20Sopenharmony_ci err = -ENOMEM; 11358c2ecf20Sopenharmony_ci goto err_out_unmap; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci lp->mii_bus->priv = dev; 11398c2ecf20Sopenharmony_ci lp->mii_bus->read = r6040_mdiobus_read; 11408c2ecf20Sopenharmony_ci lp->mii_bus->write = r6040_mdiobus_write; 11418c2ecf20Sopenharmony_ci lp->mii_bus->name = "r6040_eth_mii"; 11428c2ecf20Sopenharmony_ci snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 11438c2ecf20Sopenharmony_ci dev_name(&pdev->dev), card_idx); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci err = mdiobus_register(lp->mii_bus); 11468c2ecf20Sopenharmony_ci if (err) { 11478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register MII bus\n"); 11488c2ecf20Sopenharmony_ci goto err_out_mdio; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci err = r6040_mii_probe(dev); 11528c2ecf20Sopenharmony_ci if (err) { 11538c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to probe MII bus\n"); 11548c2ecf20Sopenharmony_ci goto err_out_mdio_unregister; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* Register net device. After this dev->name assign */ 11588c2ecf20Sopenharmony_ci err = register_netdev(dev); 11598c2ecf20Sopenharmony_ci if (err) { 11608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to register net device\n"); 11618c2ecf20Sopenharmony_ci goto err_out_phy_disconnect; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci return 0; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cierr_out_phy_disconnect: 11668c2ecf20Sopenharmony_ci phy_disconnect(dev->phydev); 11678c2ecf20Sopenharmony_cierr_out_mdio_unregister: 11688c2ecf20Sopenharmony_ci mdiobus_unregister(lp->mii_bus); 11698c2ecf20Sopenharmony_cierr_out_mdio: 11708c2ecf20Sopenharmony_ci mdiobus_free(lp->mii_bus); 11718c2ecf20Sopenharmony_cierr_out_unmap: 11728c2ecf20Sopenharmony_ci netif_napi_del(&lp->napi); 11738c2ecf20Sopenharmony_ci pci_iounmap(pdev, ioaddr); 11748c2ecf20Sopenharmony_cierr_out_free_res: 11758c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11768c2ecf20Sopenharmony_cierr_out_free_dev: 11778c2ecf20Sopenharmony_ci free_netdev(dev); 11788c2ecf20Sopenharmony_cierr_out_disable_dev: 11798c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11808c2ecf20Sopenharmony_cierr_out: 11818c2ecf20Sopenharmony_ci return err; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic void r6040_remove_one(struct pci_dev *pdev) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 11878c2ecf20Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci unregister_netdev(dev); 11908c2ecf20Sopenharmony_ci phy_disconnect(dev->phydev); 11918c2ecf20Sopenharmony_ci mdiobus_unregister(lp->mii_bus); 11928c2ecf20Sopenharmony_ci mdiobus_free(lp->mii_bus); 11938c2ecf20Sopenharmony_ci netif_napi_del(&lp->napi); 11948c2ecf20Sopenharmony_ci pci_iounmap(pdev, lp->base); 11958c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11968c2ecf20Sopenharmony_ci free_netdev(dev); 11978c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic const struct pci_device_id r6040_pci_tbl[] = { 12028c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) }, 12038c2ecf20Sopenharmony_ci { 0 } 12048c2ecf20Sopenharmony_ci}; 12058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r6040_pci_tbl); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic struct pci_driver r6040_driver = { 12088c2ecf20Sopenharmony_ci .name = DRV_NAME, 12098c2ecf20Sopenharmony_ci .id_table = r6040_pci_tbl, 12108c2ecf20Sopenharmony_ci .probe = r6040_init_one, 12118c2ecf20Sopenharmony_ci .remove = r6040_remove_one, 12128c2ecf20Sopenharmony_ci}; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cimodule_pci_driver(r6040_driver); 1215