162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * RDC R6040 Fast Ethernet MAC support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw> 662306a36Sopenharmony_ci * Copyright (C) 2007 762306a36Sopenharmony_ci * Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> 862306a36Sopenharmony_ci * Copyright (C) 2007-2012 Florian Fainelli <f.fainelli@gmail.com> 962306a36Sopenharmony_ci*/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/moduleparam.h> 1462306a36Sopenharmony_ci#include <linux/string.h> 1562306a36Sopenharmony_ci#include <linux/timer.h> 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci#include <linux/ioport.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <linux/pci.h> 2062306a36Sopenharmony_ci#include <linux/netdevice.h> 2162306a36Sopenharmony_ci#include <linux/etherdevice.h> 2262306a36Sopenharmony_ci#include <linux/skbuff.h> 2362306a36Sopenharmony_ci#include <linux/delay.h> 2462306a36Sopenharmony_ci#include <linux/mii.h> 2562306a36Sopenharmony_ci#include <linux/ethtool.h> 2662306a36Sopenharmony_ci#include <linux/crc32.h> 2762306a36Sopenharmony_ci#include <linux/spinlock.h> 2862306a36Sopenharmony_ci#include <linux/bitops.h> 2962306a36Sopenharmony_ci#include <linux/io.h> 3062306a36Sopenharmony_ci#include <linux/irq.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci#include <linux/phy.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <asm/processor.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define DRV_NAME "r6040" 3762306a36Sopenharmony_ci#define DRV_VERSION "0.29" 3862306a36Sopenharmony_ci#define DRV_RELDATE "04Jul2016" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 4162306a36Sopenharmony_ci#define TX_TIMEOUT (6000 * HZ / 1000) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* RDC MAC I/O Size */ 4462306a36Sopenharmony_ci#define R6040_IO_SIZE 256 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* MAX RDC MAC */ 4762306a36Sopenharmony_ci#define MAX_MAC 2 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* MAC registers */ 5062306a36Sopenharmony_ci#define MCR0 0x00 /* Control register 0 */ 5162306a36Sopenharmony_ci#define MCR0_RCVEN 0x0002 /* Receive enable */ 5262306a36Sopenharmony_ci#define MCR0_PROMISC 0x0020 /* Promiscuous mode */ 5362306a36Sopenharmony_ci#define MCR0_HASH_EN 0x0100 /* Enable multicast hash table function */ 5462306a36Sopenharmony_ci#define MCR0_XMTEN 0x1000 /* Transmission enable */ 5562306a36Sopenharmony_ci#define MCR0_FD 0x8000 /* Full/Half duplex */ 5662306a36Sopenharmony_ci#define MCR1 0x04 /* Control register 1 */ 5762306a36Sopenharmony_ci#define MAC_RST 0x0001 /* Reset the MAC */ 5862306a36Sopenharmony_ci#define MBCR 0x08 /* Bus control */ 5962306a36Sopenharmony_ci#define MT_ICR 0x0C /* TX interrupt control */ 6062306a36Sopenharmony_ci#define MR_ICR 0x10 /* RX interrupt control */ 6162306a36Sopenharmony_ci#define MTPR 0x14 /* TX poll command register */ 6262306a36Sopenharmony_ci#define TM2TX 0x0001 /* Trigger MAC to transmit */ 6362306a36Sopenharmony_ci#define MR_BSR 0x18 /* RX buffer size */ 6462306a36Sopenharmony_ci#define MR_DCR 0x1A /* RX descriptor control */ 6562306a36Sopenharmony_ci#define MLSR 0x1C /* Last status */ 6662306a36Sopenharmony_ci#define TX_FIFO_UNDR 0x0200 /* TX FIFO under-run */ 6762306a36Sopenharmony_ci#define TX_EXCEEDC 0x2000 /* Transmit exceed collision */ 6862306a36Sopenharmony_ci#define TX_LATEC 0x4000 /* Transmit late collision */ 6962306a36Sopenharmony_ci#define MMDIO 0x20 /* MDIO control register */ 7062306a36Sopenharmony_ci#define MDIO_WRITE 0x4000 /* MDIO write */ 7162306a36Sopenharmony_ci#define MDIO_READ 0x2000 /* MDIO read */ 7262306a36Sopenharmony_ci#define MMRD 0x24 /* MDIO read data register */ 7362306a36Sopenharmony_ci#define MMWD 0x28 /* MDIO write data register */ 7462306a36Sopenharmony_ci#define MTD_SA0 0x2C /* TX descriptor start address 0 */ 7562306a36Sopenharmony_ci#define MTD_SA1 0x30 /* TX descriptor start address 1 */ 7662306a36Sopenharmony_ci#define MRD_SA0 0x34 /* RX descriptor start address 0 */ 7762306a36Sopenharmony_ci#define MRD_SA1 0x38 /* RX descriptor start address 1 */ 7862306a36Sopenharmony_ci#define MISR 0x3C /* Status register */ 7962306a36Sopenharmony_ci#define MIER 0x40 /* INT enable register */ 8062306a36Sopenharmony_ci#define MSK_INT 0x0000 /* Mask off interrupts */ 8162306a36Sopenharmony_ci#define RX_FINISH 0x0001 /* RX finished */ 8262306a36Sopenharmony_ci#define RX_NO_DESC 0x0002 /* No RX descriptor available */ 8362306a36Sopenharmony_ci#define RX_FIFO_FULL 0x0004 /* RX FIFO full */ 8462306a36Sopenharmony_ci#define RX_EARLY 0x0008 /* RX early */ 8562306a36Sopenharmony_ci#define TX_FINISH 0x0010 /* TX finished */ 8662306a36Sopenharmony_ci#define TX_EARLY 0x0080 /* TX early */ 8762306a36Sopenharmony_ci#define EVENT_OVRFL 0x0100 /* Event counter overflow */ 8862306a36Sopenharmony_ci#define LINK_CHANGED 0x0200 /* PHY link changed */ 8962306a36Sopenharmony_ci#define ME_CISR 0x44 /* Event counter INT status */ 9062306a36Sopenharmony_ci#define ME_CIER 0x48 /* Event counter INT enable */ 9162306a36Sopenharmony_ci#define MR_CNT 0x50 /* Successfully received packet counter */ 9262306a36Sopenharmony_ci#define ME_CNT0 0x52 /* Event counter 0 */ 9362306a36Sopenharmony_ci#define ME_CNT1 0x54 /* Event counter 1 */ 9462306a36Sopenharmony_ci#define ME_CNT2 0x56 /* Event counter 2 */ 9562306a36Sopenharmony_ci#define ME_CNT3 0x58 /* Event counter 3 */ 9662306a36Sopenharmony_ci#define MT_CNT 0x5A /* Successfully transmit packet counter */ 9762306a36Sopenharmony_ci#define ME_CNT4 0x5C /* Event counter 4 */ 9862306a36Sopenharmony_ci#define MP_CNT 0x5E /* Pause frame counter register */ 9962306a36Sopenharmony_ci#define MAR0 0x60 /* Hash table 0 */ 10062306a36Sopenharmony_ci#define MAR1 0x62 /* Hash table 1 */ 10162306a36Sopenharmony_ci#define MAR2 0x64 /* Hash table 2 */ 10262306a36Sopenharmony_ci#define MAR3 0x66 /* Hash table 3 */ 10362306a36Sopenharmony_ci#define MID_0L 0x68 /* Multicast address MID0 Low */ 10462306a36Sopenharmony_ci#define MID_0M 0x6A /* Multicast address MID0 Medium */ 10562306a36Sopenharmony_ci#define MID_0H 0x6C /* Multicast address MID0 High */ 10662306a36Sopenharmony_ci#define MID_1L 0x70 /* MID1 Low */ 10762306a36Sopenharmony_ci#define MID_1M 0x72 /* MID1 Medium */ 10862306a36Sopenharmony_ci#define MID_1H 0x74 /* MID1 High */ 10962306a36Sopenharmony_ci#define MID_2L 0x78 /* MID2 Low */ 11062306a36Sopenharmony_ci#define MID_2M 0x7A /* MID2 Medium */ 11162306a36Sopenharmony_ci#define MID_2H 0x7C /* MID2 High */ 11262306a36Sopenharmony_ci#define MID_3L 0x80 /* MID3 Low */ 11362306a36Sopenharmony_ci#define MID_3M 0x82 /* MID3 Medium */ 11462306a36Sopenharmony_ci#define MID_3H 0x84 /* MID3 High */ 11562306a36Sopenharmony_ci#define PHY_CC 0x88 /* PHY status change configuration register */ 11662306a36Sopenharmony_ci#define SCEN 0x8000 /* PHY status change enable */ 11762306a36Sopenharmony_ci#define PHYAD_SHIFT 8 /* PHY address shift */ 11862306a36Sopenharmony_ci#define TMRDIV_SHIFT 0 /* Timer divider shift */ 11962306a36Sopenharmony_ci#define PHY_ST 0x8A /* PHY status register */ 12062306a36Sopenharmony_ci#define MAC_SM 0xAC /* MAC status machine */ 12162306a36Sopenharmony_ci#define MAC_SM_RST 0x0002 /* MAC status machine reset */ 12262306a36Sopenharmony_ci#define MD_CSC 0xb6 /* MDC speed control register */ 12362306a36Sopenharmony_ci#define MD_CSC_DEFAULT 0x0030 12462306a36Sopenharmony_ci#define MAC_ID 0xBE /* Identifier register */ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define TX_DCNT 0x80 /* TX descriptor count */ 12762306a36Sopenharmony_ci#define RX_DCNT 0x80 /* RX descriptor count */ 12862306a36Sopenharmony_ci#define MAX_BUF_SIZE 0x600 12962306a36Sopenharmony_ci#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor)) 13062306a36Sopenharmony_ci#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor)) 13162306a36Sopenharmony_ci#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */ 13262306a36Sopenharmony_ci#define MCAST_MAX 3 /* Max number multicast addresses to filter */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define MAC_DEF_TIMEOUT 2048 /* Default MAC read/write operation timeout */ 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* Descriptor status */ 13762306a36Sopenharmony_ci#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */ 13862306a36Sopenharmony_ci#define DSC_RX_OK 0x4000 /* RX was successful */ 13962306a36Sopenharmony_ci#define DSC_RX_ERR 0x0800 /* RX PHY error */ 14062306a36Sopenharmony_ci#define DSC_RX_ERR_DRI 0x0400 /* RX dribble packet */ 14162306a36Sopenharmony_ci#define DSC_RX_ERR_BUF 0x0200 /* RX length exceeds buffer size */ 14262306a36Sopenharmony_ci#define DSC_RX_ERR_LONG 0x0100 /* RX length > maximum packet length */ 14362306a36Sopenharmony_ci#define DSC_RX_ERR_RUNT 0x0080 /* RX packet length < 64 byte */ 14462306a36Sopenharmony_ci#define DSC_RX_ERR_CRC 0x0040 /* RX CRC error */ 14562306a36Sopenharmony_ci#define DSC_RX_BCAST 0x0020 /* RX broadcast (no error) */ 14662306a36Sopenharmony_ci#define DSC_RX_MCAST 0x0010 /* RX multicast (no error) */ 14762306a36Sopenharmony_ci#define DSC_RX_MCH_HIT 0x0008 /* RX multicast hit in hash table (no error) */ 14862306a36Sopenharmony_ci#define DSC_RX_MIDH_HIT 0x0004 /* RX MID table hit (no error) */ 14962306a36Sopenharmony_ci#define DSC_RX_IDX_MID_MASK 3 /* RX mask for the index of matched MIDx */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>," 15262306a36Sopenharmony_ci "Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>," 15362306a36Sopenharmony_ci "Florian Fainelli <f.fainelli@gmail.com>"); 15462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 15562306a36Sopenharmony_ciMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver"); 15662306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION " " DRV_RELDATE); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* RX and TX interrupts that we handle */ 15962306a36Sopenharmony_ci#define RX_INTS (RX_FIFO_FULL | RX_NO_DESC | RX_FINISH) 16062306a36Sopenharmony_ci#define TX_INTS (TX_FINISH) 16162306a36Sopenharmony_ci#define INT_MASK (RX_INTS | TX_INTS) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct r6040_descriptor { 16462306a36Sopenharmony_ci u16 status, len; /* 0-3 */ 16562306a36Sopenharmony_ci __le32 buf; /* 4-7 */ 16662306a36Sopenharmony_ci __le32 ndesc; /* 8-B */ 16762306a36Sopenharmony_ci u32 rev1; /* C-F */ 16862306a36Sopenharmony_ci char *vbufp; /* 10-13 */ 16962306a36Sopenharmony_ci struct r6040_descriptor *vndescp; /* 14-17 */ 17062306a36Sopenharmony_ci struct sk_buff *skb_ptr; /* 18-1B */ 17162306a36Sopenharmony_ci u32 rev2; /* 1C-1F */ 17262306a36Sopenharmony_ci} __aligned(32); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct r6040_private { 17562306a36Sopenharmony_ci spinlock_t lock; /* driver lock */ 17662306a36Sopenharmony_ci struct pci_dev *pdev; 17762306a36Sopenharmony_ci struct r6040_descriptor *rx_insert_ptr; 17862306a36Sopenharmony_ci struct r6040_descriptor *rx_remove_ptr; 17962306a36Sopenharmony_ci struct r6040_descriptor *tx_insert_ptr; 18062306a36Sopenharmony_ci struct r6040_descriptor *tx_remove_ptr; 18162306a36Sopenharmony_ci struct r6040_descriptor *rx_ring; 18262306a36Sopenharmony_ci struct r6040_descriptor *tx_ring; 18362306a36Sopenharmony_ci dma_addr_t rx_ring_dma; 18462306a36Sopenharmony_ci dma_addr_t tx_ring_dma; 18562306a36Sopenharmony_ci u16 tx_free_desc; 18662306a36Sopenharmony_ci u16 mcr0; 18762306a36Sopenharmony_ci struct net_device *dev; 18862306a36Sopenharmony_ci struct mii_bus *mii_bus; 18962306a36Sopenharmony_ci struct napi_struct napi; 19062306a36Sopenharmony_ci void __iomem *base; 19162306a36Sopenharmony_ci int old_link; 19262306a36Sopenharmony_ci int old_duplex; 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic char version[] = DRV_NAME 19662306a36Sopenharmony_ci ": RDC R6040 NAPI net driver," 19762306a36Sopenharmony_ci "version "DRV_VERSION " (" DRV_RELDATE ")"; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* Read a word data from PHY Chip */ 20062306a36Sopenharmony_cistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 20362306a36Sopenharmony_ci u16 cmd; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci iowrite16(MDIO_READ | reg | (phy_addr << 8), ioaddr + MMDIO); 20662306a36Sopenharmony_ci /* Wait for the read bit to be cleared */ 20762306a36Sopenharmony_ci while (limit--) { 20862306a36Sopenharmony_ci cmd = ioread16(ioaddr + MMDIO); 20962306a36Sopenharmony_ci if (!(cmd & MDIO_READ)) 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci udelay(1); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (limit < 0) 21562306a36Sopenharmony_ci return -ETIMEDOUT; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return ioread16(ioaddr + MMRD); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* Write a word data from PHY Chip */ 22162306a36Sopenharmony_cistatic int r6040_phy_write(void __iomem *ioaddr, 22262306a36Sopenharmony_ci int phy_addr, int reg, u16 val) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 22562306a36Sopenharmony_ci u16 cmd; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci iowrite16(val, ioaddr + MMWD); 22862306a36Sopenharmony_ci /* Write the command to the MDIO bus */ 22962306a36Sopenharmony_ci iowrite16(MDIO_WRITE | reg | (phy_addr << 8), ioaddr + MMDIO); 23062306a36Sopenharmony_ci /* Wait for the write bit to be cleared */ 23162306a36Sopenharmony_ci while (limit--) { 23262306a36Sopenharmony_ci cmd = ioread16(ioaddr + MMDIO); 23362306a36Sopenharmony_ci if (!(cmd & MDIO_WRITE)) 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci udelay(1); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return (limit < 0) ? -ETIMEDOUT : 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct net_device *dev = bus->priv; 24462306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 24562306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return r6040_phy_read(ioaddr, phy_addr, reg); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr, 25162306a36Sopenharmony_ci int reg, u16 value) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct net_device *dev = bus->priv; 25462306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 25562306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return r6040_phy_write(ioaddr, phy_addr, reg, value); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void r6040_free_txbufs(struct net_device *dev) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 26362306a36Sopenharmony_ci int i; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci for (i = 0; i < TX_DCNT; i++) { 26662306a36Sopenharmony_ci if (lp->tx_insert_ptr->skb_ptr) { 26762306a36Sopenharmony_ci dma_unmap_single(&lp->pdev->dev, 26862306a36Sopenharmony_ci le32_to_cpu(lp->tx_insert_ptr->buf), 26962306a36Sopenharmony_ci MAX_BUF_SIZE, DMA_TO_DEVICE); 27062306a36Sopenharmony_ci dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); 27162306a36Sopenharmony_ci lp->tx_insert_ptr->skb_ptr = NULL; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void r6040_free_rxbufs(struct net_device *dev) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 28062306a36Sopenharmony_ci int i; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < RX_DCNT; i++) { 28362306a36Sopenharmony_ci if (lp->rx_insert_ptr->skb_ptr) { 28462306a36Sopenharmony_ci dma_unmap_single(&lp->pdev->dev, 28562306a36Sopenharmony_ci le32_to_cpu(lp->rx_insert_ptr->buf), 28662306a36Sopenharmony_ci MAX_BUF_SIZE, DMA_FROM_DEVICE); 28762306a36Sopenharmony_ci dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); 28862306a36Sopenharmony_ci lp->rx_insert_ptr->skb_ptr = NULL; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, 29562306a36Sopenharmony_ci dma_addr_t desc_dma, int size) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct r6040_descriptor *desc = desc_ring; 29862306a36Sopenharmony_ci dma_addr_t mapping = desc_dma; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci while (size-- > 0) { 30162306a36Sopenharmony_ci mapping += sizeof(*desc); 30262306a36Sopenharmony_ci desc->ndesc = cpu_to_le32(mapping); 30362306a36Sopenharmony_ci desc->vndescp = desc + 1; 30462306a36Sopenharmony_ci desc++; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci desc--; 30762306a36Sopenharmony_ci desc->ndesc = cpu_to_le32(desc_dma); 30862306a36Sopenharmony_ci desc->vndescp = desc_ring; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void r6040_init_txbufs(struct net_device *dev) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci lp->tx_free_desc = TX_DCNT; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; 31862306a36Sopenharmony_ci r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int r6040_alloc_rxbufs(struct net_device *dev) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 32462306a36Sopenharmony_ci struct r6040_descriptor *desc; 32562306a36Sopenharmony_ci struct sk_buff *skb; 32662306a36Sopenharmony_ci int rc; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; 32962306a36Sopenharmony_ci r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Allocate skbs for the rx descriptors */ 33262306a36Sopenharmony_ci desc = lp->rx_ring; 33362306a36Sopenharmony_ci do { 33462306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); 33562306a36Sopenharmony_ci if (!skb) { 33662306a36Sopenharmony_ci rc = -ENOMEM; 33762306a36Sopenharmony_ci goto err_exit; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci desc->skb_ptr = skb; 34062306a36Sopenharmony_ci desc->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, 34162306a36Sopenharmony_ci desc->skb_ptr->data, 34262306a36Sopenharmony_ci MAX_BUF_SIZE, 34362306a36Sopenharmony_ci DMA_FROM_DEVICE)); 34462306a36Sopenharmony_ci desc->status = DSC_OWNER_MAC; 34562306a36Sopenharmony_ci desc = desc->vndescp; 34662306a36Sopenharmony_ci } while (desc != lp->rx_ring); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cierr_exit: 35162306a36Sopenharmony_ci /* Deallocate all previously allocated skbs */ 35262306a36Sopenharmony_ci r6040_free_rxbufs(dev); 35362306a36Sopenharmony_ci return rc; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void r6040_reset_mac(struct r6040_private *lp) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 35962306a36Sopenharmony_ci int limit = MAC_DEF_TIMEOUT; 36062306a36Sopenharmony_ci u16 cmd, md_csc; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci md_csc = ioread16(ioaddr + MD_CSC); 36362306a36Sopenharmony_ci iowrite16(MAC_RST, ioaddr + MCR1); 36462306a36Sopenharmony_ci while (limit--) { 36562306a36Sopenharmony_ci cmd = ioread16(ioaddr + MCR1); 36662306a36Sopenharmony_ci if (cmd & MAC_RST) 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Reset internal state machine */ 37162306a36Sopenharmony_ci iowrite16(MAC_SM_RST, ioaddr + MAC_SM); 37262306a36Sopenharmony_ci iowrite16(0, ioaddr + MAC_SM); 37362306a36Sopenharmony_ci mdelay(5); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Restore MDIO clock frequency */ 37662306a36Sopenharmony_ci if (md_csc != MD_CSC_DEFAULT) 37762306a36Sopenharmony_ci iowrite16(md_csc, ioaddr + MD_CSC); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void r6040_init_mac_regs(struct net_device *dev) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 38362306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Mask Off Interrupt */ 38662306a36Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Reset RDC MAC */ 38962306a36Sopenharmony_ci r6040_reset_mac(lp); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* MAC Bus Control Register */ 39262306a36Sopenharmony_ci iowrite16(MBCR_DEFAULT, ioaddr + MBCR); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Buffer Size Register */ 39562306a36Sopenharmony_ci iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Write TX ring start address */ 39862306a36Sopenharmony_ci iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); 39962306a36Sopenharmony_ci iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Write RX ring start address */ 40262306a36Sopenharmony_ci iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); 40362306a36Sopenharmony_ci iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Set interrupt waiting time and packet numbers */ 40662306a36Sopenharmony_ci iowrite16(0, ioaddr + MT_ICR); 40762306a36Sopenharmony_ci iowrite16(0, ioaddr + MR_ICR); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* Enable interrupts */ 41062306a36Sopenharmony_ci iowrite16(INT_MASK, ioaddr + MIER); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Enable TX and RX */ 41362306a36Sopenharmony_ci iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Let TX poll the descriptors 41662306a36Sopenharmony_ci * we may got called by r6040_tx_timeout which has left 41762306a36Sopenharmony_ci * some unsent tx buffers */ 41862306a36Sopenharmony_ci iowrite16(TM2TX, ioaddr + MTPR); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void r6040_tx_timeout(struct net_device *dev, unsigned int txqueue) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 42462306a36Sopenharmony_ci void __iomem *ioaddr = priv->base; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci netdev_warn(dev, "transmit timed out, int enable %4.4x " 42762306a36Sopenharmony_ci "status %4.4x\n", 42862306a36Sopenharmony_ci ioread16(ioaddr + MIER), 42962306a36Sopenharmony_ci ioread16(ioaddr + MISR)); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci dev->stats.tx_errors++; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Reset MAC and re-init all registers */ 43462306a36Sopenharmony_ci r6040_init_mac_regs(dev); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic struct net_device_stats *r6040_get_stats(struct net_device *dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 44062306a36Sopenharmony_ci void __iomem *ioaddr = priv->base; 44162306a36Sopenharmony_ci unsigned long flags; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 44462306a36Sopenharmony_ci dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); 44562306a36Sopenharmony_ci dev->stats.multicast += ioread8(ioaddr + ME_CNT0); 44662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return &dev->stats; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/* Stop RDC MAC and Free the allocated resource */ 45262306a36Sopenharmony_cistatic void r6040_down(struct net_device *dev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 45562306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 45662306a36Sopenharmony_ci const u16 *adrp; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Stop MAC */ 45962306a36Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Reset RDC MAC */ 46262306a36Sopenharmony_ci r6040_reset_mac(lp); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Restore MAC Address to MIDx */ 46562306a36Sopenharmony_ci adrp = (const u16 *) dev->dev_addr; 46662306a36Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 46762306a36Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 46862306a36Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic int r6040_close(struct net_device *dev) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 47462306a36Sopenharmony_ci struct pci_dev *pdev = lp->pdev; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci phy_stop(dev->phydev); 47762306a36Sopenharmony_ci napi_disable(&lp->napi); 47862306a36Sopenharmony_ci netif_stop_queue(dev); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci spin_lock_irq(&lp->lock); 48162306a36Sopenharmony_ci r6040_down(dev); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Free RX buffer */ 48462306a36Sopenharmony_ci r6040_free_rxbufs(dev); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Free TX buffer */ 48762306a36Sopenharmony_ci r6040_free_txbufs(dev); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci spin_unlock_irq(&lp->lock); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci free_irq(dev->irq, dev); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Free Descriptor memory */ 49462306a36Sopenharmony_ci if (lp->rx_ring) { 49562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_DESC_SIZE, lp->rx_ring, 49662306a36Sopenharmony_ci lp->rx_ring_dma); 49762306a36Sopenharmony_ci lp->rx_ring = NULL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (lp->tx_ring) { 50162306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_DESC_SIZE, lp->tx_ring, 50262306a36Sopenharmony_ci lp->tx_ring_dma); 50362306a36Sopenharmony_ci lp->tx_ring = NULL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int r6040_rx(struct net_device *dev, int limit) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 51262306a36Sopenharmony_ci struct r6040_descriptor *descptr = priv->rx_remove_ptr; 51362306a36Sopenharmony_ci struct sk_buff *skb_ptr, *new_skb; 51462306a36Sopenharmony_ci int count = 0; 51562306a36Sopenharmony_ci u16 err; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Limit not reached and the descriptor belongs to the CPU */ 51862306a36Sopenharmony_ci while (count < limit && !(descptr->status & DSC_OWNER_MAC)) { 51962306a36Sopenharmony_ci /* Read the descriptor status */ 52062306a36Sopenharmony_ci err = descptr->status; 52162306a36Sopenharmony_ci /* Global error status set */ 52262306a36Sopenharmony_ci if (err & DSC_RX_ERR) { 52362306a36Sopenharmony_ci /* RX dribble */ 52462306a36Sopenharmony_ci if (err & DSC_RX_ERR_DRI) 52562306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 52662306a36Sopenharmony_ci /* Buffer length exceeded */ 52762306a36Sopenharmony_ci if (err & DSC_RX_ERR_BUF) 52862306a36Sopenharmony_ci dev->stats.rx_length_errors++; 52962306a36Sopenharmony_ci /* Packet too long */ 53062306a36Sopenharmony_ci if (err & DSC_RX_ERR_LONG) 53162306a36Sopenharmony_ci dev->stats.rx_length_errors++; 53262306a36Sopenharmony_ci /* Packet < 64 bytes */ 53362306a36Sopenharmony_ci if (err & DSC_RX_ERR_RUNT) 53462306a36Sopenharmony_ci dev->stats.rx_length_errors++; 53562306a36Sopenharmony_ci /* CRC error */ 53662306a36Sopenharmony_ci if (err & DSC_RX_ERR_CRC) { 53762306a36Sopenharmony_ci spin_lock(&priv->lock); 53862306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 53962306a36Sopenharmony_ci spin_unlock(&priv->lock); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci goto next_descr; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Packet successfully received */ 54562306a36Sopenharmony_ci new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); 54662306a36Sopenharmony_ci if (!new_skb) { 54762306a36Sopenharmony_ci dev->stats.rx_dropped++; 54862306a36Sopenharmony_ci goto next_descr; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci skb_ptr = descptr->skb_ptr; 55162306a36Sopenharmony_ci skb_ptr->dev = priv->dev; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* Do not count the CRC */ 55462306a36Sopenharmony_ci skb_put(skb_ptr, descptr->len - ETH_FCS_LEN); 55562306a36Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf), 55662306a36Sopenharmony_ci MAX_BUF_SIZE, DMA_FROM_DEVICE); 55762306a36Sopenharmony_ci skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Send to upper layer */ 56062306a36Sopenharmony_ci netif_receive_skb(skb_ptr); 56162306a36Sopenharmony_ci dev->stats.rx_packets++; 56262306a36Sopenharmony_ci dev->stats.rx_bytes += descptr->len - ETH_FCS_LEN; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* put new skb into descriptor */ 56562306a36Sopenharmony_ci descptr->skb_ptr = new_skb; 56662306a36Sopenharmony_ci descptr->buf = cpu_to_le32(dma_map_single(&priv->pdev->dev, 56762306a36Sopenharmony_ci descptr->skb_ptr->data, 56862306a36Sopenharmony_ci MAX_BUF_SIZE, 56962306a36Sopenharmony_ci DMA_FROM_DEVICE)); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cinext_descr: 57262306a36Sopenharmony_ci /* put the descriptor back to the MAC */ 57362306a36Sopenharmony_ci descptr->status = DSC_OWNER_MAC; 57462306a36Sopenharmony_ci descptr = descptr->vndescp; 57562306a36Sopenharmony_ci count++; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci priv->rx_remove_ptr = descptr; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return count; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void r6040_tx(struct net_device *dev) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct r6040_private *priv = netdev_priv(dev); 58562306a36Sopenharmony_ci struct r6040_descriptor *descptr; 58662306a36Sopenharmony_ci void __iomem *ioaddr = priv->base; 58762306a36Sopenharmony_ci struct sk_buff *skb_ptr; 58862306a36Sopenharmony_ci u16 err; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci spin_lock(&priv->lock); 59162306a36Sopenharmony_ci descptr = priv->tx_remove_ptr; 59262306a36Sopenharmony_ci while (priv->tx_free_desc < TX_DCNT) { 59362306a36Sopenharmony_ci /* Check for errors */ 59462306a36Sopenharmony_ci err = ioread16(ioaddr + MLSR); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (err & TX_FIFO_UNDR) 59762306a36Sopenharmony_ci dev->stats.tx_fifo_errors++; 59862306a36Sopenharmony_ci if (err & (TX_EXCEEDC | TX_LATEC)) 59962306a36Sopenharmony_ci dev->stats.tx_carrier_errors++; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (descptr->status & DSC_OWNER_MAC) 60262306a36Sopenharmony_ci break; /* Not complete */ 60362306a36Sopenharmony_ci skb_ptr = descptr->skb_ptr; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Statistic Counter */ 60662306a36Sopenharmony_ci dev->stats.tx_packets++; 60762306a36Sopenharmony_ci dev->stats.tx_bytes += skb_ptr->len; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf), 61062306a36Sopenharmony_ci skb_ptr->len, DMA_TO_DEVICE); 61162306a36Sopenharmony_ci /* Free buffer */ 61262306a36Sopenharmony_ci dev_kfree_skb(skb_ptr); 61362306a36Sopenharmony_ci descptr->skb_ptr = NULL; 61462306a36Sopenharmony_ci /* To next descriptor */ 61562306a36Sopenharmony_ci descptr = descptr->vndescp; 61662306a36Sopenharmony_ci priv->tx_free_desc++; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci priv->tx_remove_ptr = descptr; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (priv->tx_free_desc) 62162306a36Sopenharmony_ci netif_wake_queue(dev); 62262306a36Sopenharmony_ci spin_unlock(&priv->lock); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int r6040_poll(struct napi_struct *napi, int budget) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct r6040_private *priv = 62862306a36Sopenharmony_ci container_of(napi, struct r6040_private, napi); 62962306a36Sopenharmony_ci struct net_device *dev = priv->dev; 63062306a36Sopenharmony_ci void __iomem *ioaddr = priv->base; 63162306a36Sopenharmony_ci int work_done; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci r6040_tx(dev); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci work_done = r6040_rx(dev, budget); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (work_done < budget) { 63862306a36Sopenharmony_ci napi_complete_done(napi, work_done); 63962306a36Sopenharmony_ci /* Enable RX/TX interrupt */ 64062306a36Sopenharmony_ci iowrite16(ioread16(ioaddr + MIER) | RX_INTS | TX_INTS, 64162306a36Sopenharmony_ci ioaddr + MIER); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci return work_done; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* The RDC interrupt handler. */ 64762306a36Sopenharmony_cistatic irqreturn_t r6040_interrupt(int irq, void *dev_id) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct net_device *dev = dev_id; 65062306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 65162306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 65262306a36Sopenharmony_ci u16 misr, status; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* Save MIER */ 65562306a36Sopenharmony_ci misr = ioread16(ioaddr + MIER); 65662306a36Sopenharmony_ci /* Mask off RDC MAC interrupt */ 65762306a36Sopenharmony_ci iowrite16(MSK_INT, ioaddr + MIER); 65862306a36Sopenharmony_ci /* Read MISR status and clear */ 65962306a36Sopenharmony_ci status = ioread16(ioaddr + MISR); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (status == 0x0000 || status == 0xffff) { 66262306a36Sopenharmony_ci /* Restore RDC MAC interrupt */ 66362306a36Sopenharmony_ci iowrite16(misr, ioaddr + MIER); 66462306a36Sopenharmony_ci return IRQ_NONE; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* RX interrupt request */ 66862306a36Sopenharmony_ci if (status & (RX_INTS | TX_INTS)) { 66962306a36Sopenharmony_ci if (status & RX_NO_DESC) { 67062306a36Sopenharmony_ci /* RX descriptor unavailable */ 67162306a36Sopenharmony_ci dev->stats.rx_dropped++; 67262306a36Sopenharmony_ci dev->stats.rx_missed_errors++; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci if (status & RX_FIFO_FULL) 67562306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (likely(napi_schedule_prep(&lp->napi))) { 67862306a36Sopenharmony_ci /* Mask off RX interrupt */ 67962306a36Sopenharmony_ci misr &= ~(RX_INTS | TX_INTS); 68062306a36Sopenharmony_ci __napi_schedule_irqoff(&lp->napi); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Restore RDC MAC interrupt */ 68562306a36Sopenharmony_ci iowrite16(misr, ioaddr + MIER); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return IRQ_HANDLED; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 69162306a36Sopenharmony_cistatic void r6040_poll_controller(struct net_device *dev) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci disable_irq(dev->irq); 69462306a36Sopenharmony_ci r6040_interrupt(dev->irq, dev); 69562306a36Sopenharmony_ci enable_irq(dev->irq); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci#endif 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/* Init RDC MAC */ 70062306a36Sopenharmony_cistatic int r6040_up(struct net_device *dev) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 70362306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 70462306a36Sopenharmony_ci int ret; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Initialise and alloc RX/TX buffers */ 70762306a36Sopenharmony_ci r6040_init_txbufs(dev); 70862306a36Sopenharmony_ci ret = r6040_alloc_rxbufs(dev); 70962306a36Sopenharmony_ci if (ret) 71062306a36Sopenharmony_ci return ret; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* improve performance (by RDC guys) */ 71362306a36Sopenharmony_ci r6040_phy_write(ioaddr, 30, 17, 71462306a36Sopenharmony_ci (r6040_phy_read(ioaddr, 30, 17) | 0x4000)); 71562306a36Sopenharmony_ci r6040_phy_write(ioaddr, 30, 17, 71662306a36Sopenharmony_ci ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000)); 71762306a36Sopenharmony_ci r6040_phy_write(ioaddr, 0, 19, 0x0000); 71862306a36Sopenharmony_ci r6040_phy_write(ioaddr, 0, 30, 0x01F0); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Initialize all MAC registers */ 72162306a36Sopenharmony_ci r6040_init_mac_regs(dev); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci phy_start(dev->phydev); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci/* Read/set MAC address routines */ 73062306a36Sopenharmony_cistatic void r6040_mac_address(struct net_device *dev) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 73362306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 73462306a36Sopenharmony_ci const u16 *adrp; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Reset MAC */ 73762306a36Sopenharmony_ci r6040_reset_mac(lp); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Restore MAC Address */ 74062306a36Sopenharmony_ci adrp = (const u16 *) dev->dev_addr; 74162306a36Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 74262306a36Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 74362306a36Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int r6040_open(struct net_device *dev) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Request IRQ and Register interrupt handler */ 75262306a36Sopenharmony_ci ret = request_irq(dev->irq, r6040_interrupt, 75362306a36Sopenharmony_ci IRQF_SHARED, dev->name, dev); 75462306a36Sopenharmony_ci if (ret) 75562306a36Sopenharmony_ci goto out; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Set MAC address */ 75862306a36Sopenharmony_ci r6040_mac_address(dev); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Allocate Descriptor memory */ 76162306a36Sopenharmony_ci lp->rx_ring = 76262306a36Sopenharmony_ci dma_alloc_coherent(&lp->pdev->dev, RX_DESC_SIZE, 76362306a36Sopenharmony_ci &lp->rx_ring_dma, GFP_KERNEL); 76462306a36Sopenharmony_ci if (!lp->rx_ring) { 76562306a36Sopenharmony_ci ret = -ENOMEM; 76662306a36Sopenharmony_ci goto err_free_irq; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci lp->tx_ring = 77062306a36Sopenharmony_ci dma_alloc_coherent(&lp->pdev->dev, TX_DESC_SIZE, 77162306a36Sopenharmony_ci &lp->tx_ring_dma, GFP_KERNEL); 77262306a36Sopenharmony_ci if (!lp->tx_ring) { 77362306a36Sopenharmony_ci ret = -ENOMEM; 77462306a36Sopenharmony_ci goto err_free_rx_ring; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci ret = r6040_up(dev); 77862306a36Sopenharmony_ci if (ret) 77962306a36Sopenharmony_ci goto err_free_tx_ring; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci napi_enable(&lp->napi); 78262306a36Sopenharmony_ci netif_start_queue(dev); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cierr_free_tx_ring: 78762306a36Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, TX_DESC_SIZE, lp->tx_ring, 78862306a36Sopenharmony_ci lp->tx_ring_dma); 78962306a36Sopenharmony_cierr_free_rx_ring: 79062306a36Sopenharmony_ci dma_free_coherent(&lp->pdev->dev, RX_DESC_SIZE, lp->rx_ring, 79162306a36Sopenharmony_ci lp->rx_ring_dma); 79262306a36Sopenharmony_cierr_free_irq: 79362306a36Sopenharmony_ci free_irq(dev->irq, dev); 79462306a36Sopenharmony_ciout: 79562306a36Sopenharmony_ci return ret; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb, 79962306a36Sopenharmony_ci struct net_device *dev) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 80262306a36Sopenharmony_ci struct r6040_descriptor *descptr; 80362306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 80462306a36Sopenharmony_ci unsigned long flags; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (skb_put_padto(skb, ETH_ZLEN) < 0) 80762306a36Sopenharmony_ci return NETDEV_TX_OK; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Critical Section */ 81062306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* TX resource check */ 81362306a36Sopenharmony_ci if (!lp->tx_free_desc) { 81462306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 81562306a36Sopenharmony_ci netif_stop_queue(dev); 81662306a36Sopenharmony_ci netdev_err(dev, ": no tx descriptor\n"); 81762306a36Sopenharmony_ci return NETDEV_TX_BUSY; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* Set TX descriptor & Transmit it */ 82162306a36Sopenharmony_ci lp->tx_free_desc--; 82262306a36Sopenharmony_ci descptr = lp->tx_insert_ptr; 82362306a36Sopenharmony_ci descptr->len = skb->len; 82462306a36Sopenharmony_ci descptr->skb_ptr = skb; 82562306a36Sopenharmony_ci descptr->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, skb->data, 82662306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE)); 82762306a36Sopenharmony_ci descptr->status = DSC_OWNER_MAC; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci skb_tx_timestamp(skb); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Trigger the MAC to check the TX descriptor */ 83262306a36Sopenharmony_ci if (!netdev_xmit_more() || netif_queue_stopped(dev)) 83362306a36Sopenharmony_ci iowrite16(TM2TX, ioaddr + MTPR); 83462306a36Sopenharmony_ci lp->tx_insert_ptr = descptr->vndescp; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* If no tx resource, stop */ 83762306a36Sopenharmony_ci if (!lp->tx_free_desc) 83862306a36Sopenharmony_ci netif_stop_queue(dev); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return NETDEV_TX_OK; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic void r6040_multicast_list(struct net_device *dev) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 84862306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 84962306a36Sopenharmony_ci unsigned long flags; 85062306a36Sopenharmony_ci struct netdev_hw_addr *ha; 85162306a36Sopenharmony_ci int i; 85262306a36Sopenharmony_ci const u16 *adrp; 85362306a36Sopenharmony_ci u16 hash_table[4] = { 0 }; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci spin_lock_irqsave(&lp->lock, flags); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Keep our MAC Address */ 85862306a36Sopenharmony_ci adrp = (const u16 *)dev->dev_addr; 85962306a36Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_0L); 86062306a36Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_0M); 86162306a36Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_0H); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Clear AMCP & PROM bits */ 86462306a36Sopenharmony_ci lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* Promiscuous mode */ 86762306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 86862306a36Sopenharmony_ci lp->mcr0 |= MCR0_PROMISC; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Enable multicast hash table function to 87162306a36Sopenharmony_ci * receive all multicast packets. */ 87262306a36Sopenharmony_ci else if (dev->flags & IFF_ALLMULTI) { 87362306a36Sopenharmony_ci lp->mcr0 |= MCR0_HASH_EN; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci for (i = 0; i < MCAST_MAX ; i++) { 87662306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 87762306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 87862306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 88262306a36Sopenharmony_ci hash_table[i] = 0xffff; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci /* Use internal multicast address registers if the number of 88562306a36Sopenharmony_ci * multicast addresses is not greater than MCAST_MAX. */ 88662306a36Sopenharmony_ci else if (netdev_mc_count(dev) <= MCAST_MAX) { 88762306a36Sopenharmony_ci i = 0; 88862306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 88962306a36Sopenharmony_ci u16 *adrp = (u16 *) ha->addr; 89062306a36Sopenharmony_ci iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); 89162306a36Sopenharmony_ci iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); 89262306a36Sopenharmony_ci iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); 89362306a36Sopenharmony_ci i++; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci while (i < MCAST_MAX) { 89662306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 89762306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 89862306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 89962306a36Sopenharmony_ci i++; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci /* Otherwise, Enable multicast hash table function. */ 90362306a36Sopenharmony_ci else { 90462306a36Sopenharmony_ci u32 crc; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci lp->mcr0 |= MCR0_HASH_EN; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci for (i = 0; i < MCAST_MAX ; i++) { 90962306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1L + 8 * i); 91062306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1M + 8 * i); 91162306a36Sopenharmony_ci iowrite16(0, ioaddr + MID_1H + 8 * i); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* Build multicast hash table */ 91562306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 91662306a36Sopenharmony_ci u8 *addrs = ha->addr; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci crc = ether_crc(ETH_ALEN, addrs); 91962306a36Sopenharmony_ci crc >>= 26; 92062306a36Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci iowrite16(lp->mcr0, ioaddr + MCR0); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* Fill the MAC hash tables with their values */ 92762306a36Sopenharmony_ci if (lp->mcr0 & MCR0_HASH_EN) { 92862306a36Sopenharmony_ci iowrite16(hash_table[0], ioaddr + MAR0); 92962306a36Sopenharmony_ci iowrite16(hash_table[1], ioaddr + MAR1); 93062306a36Sopenharmony_ci iowrite16(hash_table[2], ioaddr + MAR2); 93162306a36Sopenharmony_ci iowrite16(hash_table[3], ioaddr + MAR3); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci spin_unlock_irqrestore(&lp->lock, flags); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, 93862306a36Sopenharmony_ci struct ethtool_drvinfo *info) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct r6040_private *rp = netdev_priv(dev); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 94362306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 94462306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info)); 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 94862306a36Sopenharmony_ci .get_drvinfo = netdev_get_drvinfo, 94962306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 95062306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 95162306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 95262306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 95362306a36Sopenharmony_ci .nway_reset = phy_ethtool_nway_reset, 95462306a36Sopenharmony_ci}; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic const struct net_device_ops r6040_netdev_ops = { 95762306a36Sopenharmony_ci .ndo_open = r6040_open, 95862306a36Sopenharmony_ci .ndo_stop = r6040_close, 95962306a36Sopenharmony_ci .ndo_start_xmit = r6040_start_xmit, 96062306a36Sopenharmony_ci .ndo_get_stats = r6040_get_stats, 96162306a36Sopenharmony_ci .ndo_set_rx_mode = r6040_multicast_list, 96262306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 96362306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 96462306a36Sopenharmony_ci .ndo_eth_ioctl = phy_do_ioctl, 96562306a36Sopenharmony_ci .ndo_tx_timeout = r6040_tx_timeout, 96662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 96762306a36Sopenharmony_ci .ndo_poll_controller = r6040_poll_controller, 96862306a36Sopenharmony_ci#endif 96962306a36Sopenharmony_ci}; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic void r6040_adjust_link(struct net_device *dev) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 97462306a36Sopenharmony_ci struct phy_device *phydev = dev->phydev; 97562306a36Sopenharmony_ci int status_changed = 0; 97662306a36Sopenharmony_ci void __iomem *ioaddr = lp->base; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci BUG_ON(!phydev); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (lp->old_link != phydev->link) { 98162306a36Sopenharmony_ci status_changed = 1; 98262306a36Sopenharmony_ci lp->old_link = phydev->link; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* reflect duplex change */ 98662306a36Sopenharmony_ci if (phydev->link && (lp->old_duplex != phydev->duplex)) { 98762306a36Sopenharmony_ci lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0); 98862306a36Sopenharmony_ci iowrite16(lp->mcr0, ioaddr); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci status_changed = 1; 99162306a36Sopenharmony_ci lp->old_duplex = phydev->duplex; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (status_changed) 99562306a36Sopenharmony_ci phy_print_status(phydev); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int r6040_mii_probe(struct net_device *dev) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 100162306a36Sopenharmony_ci struct phy_device *phydev = NULL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci phydev = phy_find_first(lp->mii_bus); 100462306a36Sopenharmony_ci if (!phydev) { 100562306a36Sopenharmony_ci dev_err(&lp->pdev->dev, "no PHY found\n"); 100662306a36Sopenharmony_ci return -ENODEV; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci phydev = phy_connect(dev, phydev_name(phydev), &r6040_adjust_link, 101062306a36Sopenharmony_ci PHY_INTERFACE_MODE_MII); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (IS_ERR(phydev)) { 101362306a36Sopenharmony_ci dev_err(&lp->pdev->dev, "could not attach to PHY\n"); 101462306a36Sopenharmony_ci return PTR_ERR(phydev); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci phy_set_max_speed(phydev, SPEED_100); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci lp->old_link = 0; 102062306a36Sopenharmony_ci lp->old_duplex = -1; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci phy_attached_info(phydev); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return 0; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci struct net_device *dev; 103062306a36Sopenharmony_ci struct r6040_private *lp; 103162306a36Sopenharmony_ci void __iomem *ioaddr; 103262306a36Sopenharmony_ci int err, io_size = R6040_IO_SIZE; 103362306a36Sopenharmony_ci static int card_idx = -1; 103462306a36Sopenharmony_ci u16 addr[ETH_ALEN / 2]; 103562306a36Sopenharmony_ci int bar = 0; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci pr_info("%s\n", version); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci err = pci_enable_device(pdev); 104062306a36Sopenharmony_ci if (err) 104162306a36Sopenharmony_ci goto err_out; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* this should always be supported */ 104462306a36Sopenharmony_ci err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 104562306a36Sopenharmony_ci if (err) { 104662306a36Sopenharmony_ci dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n"); 104762306a36Sopenharmony_ci goto err_out_disable_dev; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 105062306a36Sopenharmony_ci if (err) { 105162306a36Sopenharmony_ci dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n"); 105262306a36Sopenharmony_ci goto err_out_disable_dev; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* IO Size check */ 105662306a36Sopenharmony_ci if (pci_resource_len(pdev, bar) < io_size) { 105762306a36Sopenharmony_ci dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); 105862306a36Sopenharmony_ci err = -EIO; 105962306a36Sopenharmony_ci goto err_out_disable_dev; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci pci_set_master(pdev); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct r6040_private)); 106562306a36Sopenharmony_ci if (!dev) { 106662306a36Sopenharmony_ci err = -ENOMEM; 106762306a36Sopenharmony_ci goto err_out_disable_dev; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 107062306a36Sopenharmony_ci lp = netdev_priv(dev); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (err) { 107562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to request PCI regions\n"); 107662306a36Sopenharmony_ci goto err_out_free_dev; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci ioaddr = pci_iomap(pdev, bar, io_size); 108062306a36Sopenharmony_ci if (!ioaddr) { 108162306a36Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed for device\n"); 108262306a36Sopenharmony_ci err = -EIO; 108362306a36Sopenharmony_ci goto err_out_free_res; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* If PHY status change register is still set to zero it means the 108762306a36Sopenharmony_ci * bootloader didn't initialize it, so we set it to: 108862306a36Sopenharmony_ci * - enable phy status change 108962306a36Sopenharmony_ci * - enable all phy addresses 109062306a36Sopenharmony_ci * - set to lowest timer divider */ 109162306a36Sopenharmony_ci if (ioread16(ioaddr + PHY_CC) == 0) 109262306a36Sopenharmony_ci iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT | 109362306a36Sopenharmony_ci 7 << TMRDIV_SHIFT, ioaddr + PHY_CC); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* Init system & device */ 109662306a36Sopenharmony_ci lp->base = ioaddr; 109762306a36Sopenharmony_ci dev->irq = pdev->irq; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci spin_lock_init(&lp->lock); 110062306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* Set MAC address */ 110362306a36Sopenharmony_ci card_idx++; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci addr[0] = ioread16(ioaddr + MID_0L); 110662306a36Sopenharmony_ci addr[1] = ioread16(ioaddr + MID_0M); 110762306a36Sopenharmony_ci addr[2] = ioread16(ioaddr + MID_0H); 110862306a36Sopenharmony_ci eth_hw_addr_set(dev, (u8 *)addr); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Some bootloader/BIOSes do not initialize 111162306a36Sopenharmony_ci * MAC address, warn about that */ 111262306a36Sopenharmony_ci if (!(addr[0] || addr[1] || addr[2])) { 111362306a36Sopenharmony_ci netdev_warn(dev, "MAC address not initialized, " 111462306a36Sopenharmony_ci "generating random\n"); 111562306a36Sopenharmony_ci eth_hw_addr_random(dev); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* Link new device into r6040_root_dev */ 111962306a36Sopenharmony_ci lp->pdev = pdev; 112062306a36Sopenharmony_ci lp->dev = dev; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* Init RDC private data */ 112362306a36Sopenharmony_ci lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* The RDC-specific entries in the device structure. */ 112662306a36Sopenharmony_ci dev->netdev_ops = &r6040_netdev_ops; 112762306a36Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 112862306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci netif_napi_add(dev, &lp->napi, r6040_poll); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci lp->mii_bus = mdiobus_alloc(); 113362306a36Sopenharmony_ci if (!lp->mii_bus) { 113462306a36Sopenharmony_ci dev_err(&pdev->dev, "mdiobus_alloc() failed\n"); 113562306a36Sopenharmony_ci err = -ENOMEM; 113662306a36Sopenharmony_ci goto err_out_unmap; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci lp->mii_bus->priv = dev; 114062306a36Sopenharmony_ci lp->mii_bus->read = r6040_mdiobus_read; 114162306a36Sopenharmony_ci lp->mii_bus->write = r6040_mdiobus_write; 114262306a36Sopenharmony_ci lp->mii_bus->name = "r6040_eth_mii"; 114362306a36Sopenharmony_ci snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 114462306a36Sopenharmony_ci dev_name(&pdev->dev), card_idx); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci err = mdiobus_register(lp->mii_bus); 114762306a36Sopenharmony_ci if (err) { 114862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register MII bus\n"); 114962306a36Sopenharmony_ci goto err_out_mdio; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci err = r6040_mii_probe(dev); 115362306a36Sopenharmony_ci if (err) { 115462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to probe MII bus\n"); 115562306a36Sopenharmony_ci goto err_out_mdio_unregister; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Register net device. After this dev->name assign */ 115962306a36Sopenharmony_ci err = register_netdev(dev); 116062306a36Sopenharmony_ci if (err) { 116162306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register net device\n"); 116262306a36Sopenharmony_ci goto err_out_phy_disconnect; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci return 0; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cierr_out_phy_disconnect: 116762306a36Sopenharmony_ci phy_disconnect(dev->phydev); 116862306a36Sopenharmony_cierr_out_mdio_unregister: 116962306a36Sopenharmony_ci mdiobus_unregister(lp->mii_bus); 117062306a36Sopenharmony_cierr_out_mdio: 117162306a36Sopenharmony_ci mdiobus_free(lp->mii_bus); 117262306a36Sopenharmony_cierr_out_unmap: 117362306a36Sopenharmony_ci netif_napi_del(&lp->napi); 117462306a36Sopenharmony_ci pci_iounmap(pdev, ioaddr); 117562306a36Sopenharmony_cierr_out_free_res: 117662306a36Sopenharmony_ci pci_release_regions(pdev); 117762306a36Sopenharmony_cierr_out_free_dev: 117862306a36Sopenharmony_ci free_netdev(dev); 117962306a36Sopenharmony_cierr_out_disable_dev: 118062306a36Sopenharmony_ci pci_disable_device(pdev); 118162306a36Sopenharmony_cierr_out: 118262306a36Sopenharmony_ci return err; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void r6040_remove_one(struct pci_dev *pdev) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 118862306a36Sopenharmony_ci struct r6040_private *lp = netdev_priv(dev); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci unregister_netdev(dev); 119162306a36Sopenharmony_ci phy_disconnect(dev->phydev); 119262306a36Sopenharmony_ci mdiobus_unregister(lp->mii_bus); 119362306a36Sopenharmony_ci mdiobus_free(lp->mii_bus); 119462306a36Sopenharmony_ci netif_napi_del(&lp->napi); 119562306a36Sopenharmony_ci pci_iounmap(pdev, lp->base); 119662306a36Sopenharmony_ci pci_release_regions(pdev); 119762306a36Sopenharmony_ci free_netdev(dev); 119862306a36Sopenharmony_ci pci_disable_device(pdev); 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cistatic const struct pci_device_id r6040_pci_tbl[] = { 120362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) }, 120462306a36Sopenharmony_ci { 0 } 120562306a36Sopenharmony_ci}; 120662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r6040_pci_tbl); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic struct pci_driver r6040_driver = { 120962306a36Sopenharmony_ci .name = DRV_NAME, 121062306a36Sopenharmony_ci .id_table = r6040_pci_tbl, 121162306a36Sopenharmony_ci .probe = r6040_init_one, 121262306a36Sopenharmony_ci .remove = r6040_remove_one, 121362306a36Sopenharmony_ci}; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cimodule_pci_driver(r6040_driver); 1216