162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2016-2017, National Instruments Corp. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Author: Moritz Fischer <mdf@kernel.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/etherdevice.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/netdevice.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/of_mdio.h> 1262306a36Sopenharmony_ci#include <linux/of_net.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/skbuff.h> 1562306a36Sopenharmony_ci#include <linux/phy.h> 1662306a36Sopenharmony_ci#include <linux/mii.h> 1762306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 1862306a36Sopenharmony_ci#include <linux/ethtool.h> 1962306a36Sopenharmony_ci#include <linux/iopoll.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define TX_BD_NUM 64 2262306a36Sopenharmony_ci#define RX_BD_NUM 128 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Axi DMA Register definitions */ 2562306a36Sopenharmony_ci#define XAXIDMA_TX_CR_OFFSET 0x00 /* Channel control */ 2662306a36Sopenharmony_ci#define XAXIDMA_TX_SR_OFFSET 0x04 /* Status */ 2762306a36Sopenharmony_ci#define XAXIDMA_TX_CDESC_OFFSET 0x08 /* Current descriptor pointer */ 2862306a36Sopenharmony_ci#define XAXIDMA_TX_TDESC_OFFSET 0x10 /* Tail descriptor pointer */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define XAXIDMA_RX_CR_OFFSET 0x30 /* Channel control */ 3162306a36Sopenharmony_ci#define XAXIDMA_RX_SR_OFFSET 0x34 /* Status */ 3262306a36Sopenharmony_ci#define XAXIDMA_RX_CDESC_OFFSET 0x38 /* Current descriptor pointer */ 3362306a36Sopenharmony_ci#define XAXIDMA_RX_TDESC_OFFSET 0x40 /* Tail descriptor pointer */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define XAXIDMA_CR_RUNSTOP_MASK 0x1 /* Start/stop DMA channel */ 3662306a36Sopenharmony_ci#define XAXIDMA_CR_RESET_MASK 0x4 /* Reset DMA engine */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */ 3962306a36Sopenharmony_ci#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */ 4062306a36Sopenharmony_ci#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ 4162306a36Sopenharmony_ci#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define XAXIDMA_DELAY_MASK 0xFF000000 /* Delay timeout counter */ 4462306a36Sopenharmony_ci#define XAXIDMA_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define XAXIDMA_DELAY_SHIFT 24 4762306a36Sopenharmony_ci#define XAXIDMA_COALESCE_SHIFT 16 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define XAXIDMA_IRQ_IOC_MASK 0x00001000 /* Completion intr */ 5062306a36Sopenharmony_ci#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ 5162306a36Sopenharmony_ci#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ 5262306a36Sopenharmony_ci#define XAXIDMA_IRQ_ALL_MASK 0x00007000 /* All interrupts */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Default TX/RX Threshold and waitbound values for SGDMA mode */ 5562306a36Sopenharmony_ci#define XAXIDMA_DFT_TX_THRESHOLD 24 5662306a36Sopenharmony_ci#define XAXIDMA_DFT_TX_WAITBOUND 254 5762306a36Sopenharmony_ci#define XAXIDMA_DFT_RX_THRESHOLD 24 5862306a36Sopenharmony_ci#define XAXIDMA_DFT_RX_WAITBOUND 254 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */ 6162306a36Sopenharmony_ci#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */ 6262306a36Sopenharmony_ci#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */ 6362306a36Sopenharmony_ci#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */ 6462306a36Sopenharmony_ci#define XAXIDMA_BD_STS_INT_ERR_MASK 0x10000000 /* Internal err */ 6562306a36Sopenharmony_ci#define XAXIDMA_BD_STS_ALL_ERR_MASK 0x70000000 /* All errors */ 6662306a36Sopenharmony_ci#define XAXIDMA_BD_STS_RXSOF_MASK 0x08000000 /* First rx pkt */ 6762306a36Sopenharmony_ci#define XAXIDMA_BD_STS_RXEOF_MASK 0x04000000 /* Last rx pkt */ 6862306a36Sopenharmony_ci#define XAXIDMA_BD_STS_ALL_MASK 0xFC000000 /* All status bits */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define NIXGE_REG_CTRL_OFFSET 0x4000 7162306a36Sopenharmony_ci#define NIXGE_REG_INFO 0x00 7262306a36Sopenharmony_ci#define NIXGE_REG_MAC_CTL 0x04 7362306a36Sopenharmony_ci#define NIXGE_REG_PHY_CTL 0x08 7462306a36Sopenharmony_ci#define NIXGE_REG_LED_CTL 0x0c 7562306a36Sopenharmony_ci#define NIXGE_REG_MDIO_DATA 0x10 7662306a36Sopenharmony_ci#define NIXGE_REG_MDIO_ADDR 0x14 7762306a36Sopenharmony_ci#define NIXGE_REG_MDIO_OP 0x18 7862306a36Sopenharmony_ci#define NIXGE_REG_MDIO_CTRL 0x1c 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define NIXGE_ID_LED_CTL_EN BIT(0) 8162306a36Sopenharmony_ci#define NIXGE_ID_LED_CTL_VAL BIT(1) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define NIXGE_MDIO_CLAUSE45 BIT(12) 8462306a36Sopenharmony_ci#define NIXGE_MDIO_CLAUSE22 0 8562306a36Sopenharmony_ci#define NIXGE_MDIO_OP(n) (((n) & 0x3) << 10) 8662306a36Sopenharmony_ci#define NIXGE_MDIO_OP_ADDRESS 0 8762306a36Sopenharmony_ci#define NIXGE_MDIO_C45_WRITE BIT(0) 8862306a36Sopenharmony_ci#define NIXGE_MDIO_C45_READ (BIT(1) | BIT(0)) 8962306a36Sopenharmony_ci#define NIXGE_MDIO_C22_WRITE BIT(0) 9062306a36Sopenharmony_ci#define NIXGE_MDIO_C22_READ BIT(1) 9162306a36Sopenharmony_ci#define NIXGE_MDIO_ADDR(n) (((n) & 0x1f) << 5) 9262306a36Sopenharmony_ci#define NIXGE_MDIO_MMD(n) (((n) & 0x1f) << 0) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define NIXGE_REG_MAC_LSB 0x1000 9562306a36Sopenharmony_ci#define NIXGE_REG_MAC_MSB 0x1004 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Packet size info */ 9862306a36Sopenharmony_ci#define NIXGE_HDR_SIZE 14 /* Size of Ethernet header */ 9962306a36Sopenharmony_ci#define NIXGE_TRL_SIZE 4 /* Size of Ethernet trailer (FCS) */ 10062306a36Sopenharmony_ci#define NIXGE_MTU 1500 /* Max MTU of an Ethernet frame */ 10162306a36Sopenharmony_ci#define NIXGE_JUMBO_MTU 9000 /* Max MTU of a jumbo Eth. frame */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define NIXGE_MAX_FRAME_SIZE (NIXGE_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE) 10462306a36Sopenharmony_ci#define NIXGE_MAX_JUMBO_FRAME_SIZE \ 10562306a36Sopenharmony_ci (NIXGE_JUMBO_MTU + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cienum nixge_version { 10862306a36Sopenharmony_ci NIXGE_V2, 10962306a36Sopenharmony_ci NIXGE_V3, 11062306a36Sopenharmony_ci NIXGE_VERSION_COUNT 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistruct nixge_hw_dma_bd { 11462306a36Sopenharmony_ci u32 next_lo; 11562306a36Sopenharmony_ci u32 next_hi; 11662306a36Sopenharmony_ci u32 phys_lo; 11762306a36Sopenharmony_ci u32 phys_hi; 11862306a36Sopenharmony_ci u32 reserved3; 11962306a36Sopenharmony_ci u32 reserved4; 12062306a36Sopenharmony_ci u32 cntrl; 12162306a36Sopenharmony_ci u32 status; 12262306a36Sopenharmony_ci u32 app0; 12362306a36Sopenharmony_ci u32 app1; 12462306a36Sopenharmony_ci u32 app2; 12562306a36Sopenharmony_ci u32 app3; 12662306a36Sopenharmony_ci u32 app4; 12762306a36Sopenharmony_ci u32 sw_id_offset_lo; 12862306a36Sopenharmony_ci u32 sw_id_offset_hi; 12962306a36Sopenharmony_ci u32 reserved6; 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#ifdef CONFIG_PHYS_ADDR_T_64BIT 13362306a36Sopenharmony_ci#define nixge_hw_dma_bd_set_addr(bd, field, addr) \ 13462306a36Sopenharmony_ci do { \ 13562306a36Sopenharmony_ci (bd)->field##_lo = lower_32_bits((addr)); \ 13662306a36Sopenharmony_ci (bd)->field##_hi = upper_32_bits((addr)); \ 13762306a36Sopenharmony_ci } while (0) 13862306a36Sopenharmony_ci#else 13962306a36Sopenharmony_ci#define nixge_hw_dma_bd_set_addr(bd, field, addr) \ 14062306a36Sopenharmony_ci ((bd)->field##_lo = lower_32_bits((addr))) 14162306a36Sopenharmony_ci#endif 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define nixge_hw_dma_bd_set_phys(bd, addr) \ 14462306a36Sopenharmony_ci nixge_hw_dma_bd_set_addr((bd), phys, (addr)) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define nixge_hw_dma_bd_set_next(bd, addr) \ 14762306a36Sopenharmony_ci nixge_hw_dma_bd_set_addr((bd), next, (addr)) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define nixge_hw_dma_bd_set_offset(bd, addr) \ 15062306a36Sopenharmony_ci nixge_hw_dma_bd_set_addr((bd), sw_id_offset, (addr)) 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#ifdef CONFIG_PHYS_ADDR_T_64BIT 15362306a36Sopenharmony_ci#define nixge_hw_dma_bd_get_addr(bd, field) \ 15462306a36Sopenharmony_ci (dma_addr_t)((((u64)(bd)->field##_hi) << 32) | ((bd)->field##_lo)) 15562306a36Sopenharmony_ci#else 15662306a36Sopenharmony_ci#define nixge_hw_dma_bd_get_addr(bd, field) \ 15762306a36Sopenharmony_ci (dma_addr_t)((bd)->field##_lo) 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistruct nixge_tx_skb { 16162306a36Sopenharmony_ci struct sk_buff *skb; 16262306a36Sopenharmony_ci dma_addr_t mapping; 16362306a36Sopenharmony_ci size_t size; 16462306a36Sopenharmony_ci bool mapped_as_page; 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistruct nixge_priv { 16862306a36Sopenharmony_ci struct net_device *ndev; 16962306a36Sopenharmony_ci struct napi_struct napi; 17062306a36Sopenharmony_ci struct device *dev; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Connection to PHY device */ 17362306a36Sopenharmony_ci struct device_node *phy_node; 17462306a36Sopenharmony_ci phy_interface_t phy_mode; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci int link; 17762306a36Sopenharmony_ci unsigned int speed; 17862306a36Sopenharmony_ci unsigned int duplex; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* MDIO bus data */ 18162306a36Sopenharmony_ci struct mii_bus *mii_bus; /* MII bus reference */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* IO registers, dma functions and IRQs */ 18462306a36Sopenharmony_ci void __iomem *ctrl_regs; 18562306a36Sopenharmony_ci void __iomem *dma_regs; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci struct tasklet_struct dma_err_tasklet; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci int tx_irq; 19062306a36Sopenharmony_ci int rx_irq; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Buffer descriptors */ 19362306a36Sopenharmony_ci struct nixge_hw_dma_bd *tx_bd_v; 19462306a36Sopenharmony_ci struct nixge_tx_skb *tx_skb; 19562306a36Sopenharmony_ci dma_addr_t tx_bd_p; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci struct nixge_hw_dma_bd *rx_bd_v; 19862306a36Sopenharmony_ci dma_addr_t rx_bd_p; 19962306a36Sopenharmony_ci u32 tx_bd_ci; 20062306a36Sopenharmony_ci u32 tx_bd_tail; 20162306a36Sopenharmony_ci u32 rx_bd_ci; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci u32 coalesce_count_rx; 20462306a36Sopenharmony_ci u32 coalesce_count_tx; 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void nixge_dma_write_reg(struct nixge_priv *priv, off_t offset, u32 val) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci writel(val, priv->dma_regs + offset); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void nixge_dma_write_desc_reg(struct nixge_priv *priv, off_t offset, 21362306a36Sopenharmony_ci dma_addr_t addr) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci writel(lower_32_bits(addr), priv->dma_regs + offset); 21662306a36Sopenharmony_ci#ifdef CONFIG_PHYS_ADDR_T_64BIT 21762306a36Sopenharmony_ci writel(upper_32_bits(addr), priv->dma_regs + offset + 4); 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic u32 nixge_dma_read_reg(const struct nixge_priv *priv, off_t offset) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return readl(priv->dma_regs + offset); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic void nixge_ctrl_write_reg(struct nixge_priv *priv, off_t offset, u32 val) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci writel(val, priv->ctrl_regs + offset); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic u32 nixge_ctrl_read_reg(struct nixge_priv *priv, off_t offset) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return readl(priv->ctrl_regs + offset); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#define nixge_ctrl_poll_timeout(priv, addr, val, cond, sleep_us, timeout_us) \ 23762306a36Sopenharmony_ci readl_poll_timeout((priv)->ctrl_regs + (addr), (val), (cond), \ 23862306a36Sopenharmony_ci (sleep_us), (timeout_us)) 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci#define nixge_dma_poll_timeout(priv, addr, val, cond, sleep_us, timeout_us) \ 24162306a36Sopenharmony_ci readl_poll_timeout((priv)->dma_regs + (addr), (val), (cond), \ 24262306a36Sopenharmony_ci (sleep_us), (timeout_us)) 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void nixge_hw_dma_bd_release(struct net_device *ndev) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 24762306a36Sopenharmony_ci dma_addr_t phys_addr; 24862306a36Sopenharmony_ci struct sk_buff *skb; 24962306a36Sopenharmony_ci int i; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (priv->rx_bd_v) { 25262306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 25362306a36Sopenharmony_ci phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i], 25462306a36Sopenharmony_ci phys); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dma_unmap_single(ndev->dev.parent, phys_addr, 25762306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE, 25862306a36Sopenharmony_ci DMA_FROM_DEVICE); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci skb = (struct sk_buff *)(uintptr_t) 26162306a36Sopenharmony_ci nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i], 26262306a36Sopenharmony_ci sw_id_offset); 26362306a36Sopenharmony_ci dev_kfree_skb(skb); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dma_free_coherent(ndev->dev.parent, 26762306a36Sopenharmony_ci sizeof(*priv->rx_bd_v) * RX_BD_NUM, 26862306a36Sopenharmony_ci priv->rx_bd_v, 26962306a36Sopenharmony_ci priv->rx_bd_p); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (priv->tx_skb) 27362306a36Sopenharmony_ci devm_kfree(ndev->dev.parent, priv->tx_skb); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (priv->tx_bd_v) 27662306a36Sopenharmony_ci dma_free_coherent(ndev->dev.parent, 27762306a36Sopenharmony_ci sizeof(*priv->tx_bd_v) * TX_BD_NUM, 27862306a36Sopenharmony_ci priv->tx_bd_v, 27962306a36Sopenharmony_ci priv->tx_bd_p); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int nixge_hw_dma_bd_init(struct net_device *ndev) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 28562306a36Sopenharmony_ci struct sk_buff *skb; 28662306a36Sopenharmony_ci dma_addr_t phys; 28762306a36Sopenharmony_ci u32 cr; 28862306a36Sopenharmony_ci int i; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Reset the indexes which are used for accessing the BDs */ 29162306a36Sopenharmony_ci priv->tx_bd_ci = 0; 29262306a36Sopenharmony_ci priv->tx_bd_tail = 0; 29362306a36Sopenharmony_ci priv->rx_bd_ci = 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Allocate the Tx and Rx buffer descriptors. */ 29662306a36Sopenharmony_ci priv->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, 29762306a36Sopenharmony_ci sizeof(*priv->tx_bd_v) * TX_BD_NUM, 29862306a36Sopenharmony_ci &priv->tx_bd_p, GFP_KERNEL); 29962306a36Sopenharmony_ci if (!priv->tx_bd_v) 30062306a36Sopenharmony_ci goto out; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci priv->tx_skb = devm_kcalloc(ndev->dev.parent, 30362306a36Sopenharmony_ci TX_BD_NUM, sizeof(*priv->tx_skb), 30462306a36Sopenharmony_ci GFP_KERNEL); 30562306a36Sopenharmony_ci if (!priv->tx_skb) 30662306a36Sopenharmony_ci goto out; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci priv->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, 30962306a36Sopenharmony_ci sizeof(*priv->rx_bd_v) * RX_BD_NUM, 31062306a36Sopenharmony_ci &priv->rx_bd_p, GFP_KERNEL); 31162306a36Sopenharmony_ci if (!priv->rx_bd_v) 31262306a36Sopenharmony_ci goto out; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (i = 0; i < TX_BD_NUM; i++) { 31562306a36Sopenharmony_ci nixge_hw_dma_bd_set_next(&priv->tx_bd_v[i], 31662306a36Sopenharmony_ci priv->tx_bd_p + 31762306a36Sopenharmony_ci sizeof(*priv->tx_bd_v) * 31862306a36Sopenharmony_ci ((i + 1) % TX_BD_NUM)); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 32262306a36Sopenharmony_ci nixge_hw_dma_bd_set_next(&priv->rx_bd_v[i], 32362306a36Sopenharmony_ci priv->rx_bd_p 32462306a36Sopenharmony_ci + sizeof(*priv->rx_bd_v) * 32562306a36Sopenharmony_ci ((i + 1) % RX_BD_NUM)); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci skb = __netdev_alloc_skb_ip_align(ndev, 32862306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE, 32962306a36Sopenharmony_ci GFP_KERNEL); 33062306a36Sopenharmony_ci if (!skb) 33162306a36Sopenharmony_ci goto out; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], (uintptr_t)skb); 33462306a36Sopenharmony_ci phys = dma_map_single(ndev->dev.parent, skb->data, 33562306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE, 33662306a36Sopenharmony_ci DMA_FROM_DEVICE); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci nixge_hw_dma_bd_set_phys(&priv->rx_bd_v[i], phys); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci priv->rx_bd_v[i].cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Start updating the Rx channel control register */ 34462306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 34562306a36Sopenharmony_ci /* Update the interrupt coalesce count */ 34662306a36Sopenharmony_ci cr = ((cr & ~XAXIDMA_COALESCE_MASK) | 34762306a36Sopenharmony_ci ((priv->coalesce_count_rx) << XAXIDMA_COALESCE_SHIFT)); 34862306a36Sopenharmony_ci /* Update the delay timer count */ 34962306a36Sopenharmony_ci cr = ((cr & ~XAXIDMA_DELAY_MASK) | 35062306a36Sopenharmony_ci (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); 35162306a36Sopenharmony_ci /* Enable coalesce, delay timer and error interrupts */ 35262306a36Sopenharmony_ci cr |= XAXIDMA_IRQ_ALL_MASK; 35362306a36Sopenharmony_ci /* Write to the Rx channel control register */ 35462306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Start updating the Tx channel control register */ 35762306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 35862306a36Sopenharmony_ci /* Update the interrupt coalesce count */ 35962306a36Sopenharmony_ci cr = (((cr & ~XAXIDMA_COALESCE_MASK)) | 36062306a36Sopenharmony_ci ((priv->coalesce_count_tx) << XAXIDMA_COALESCE_SHIFT)); 36162306a36Sopenharmony_ci /* Update the delay timer count */ 36262306a36Sopenharmony_ci cr = (((cr & ~XAXIDMA_DELAY_MASK)) | 36362306a36Sopenharmony_ci (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); 36462306a36Sopenharmony_ci /* Enable coalesce, delay timer and error interrupts */ 36562306a36Sopenharmony_ci cr |= XAXIDMA_IRQ_ALL_MASK; 36662306a36Sopenharmony_ci /* Write to the Tx channel control register */ 36762306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Populate the tail pointer and bring the Rx Axi DMA engine out of 37062306a36Sopenharmony_ci * halted state. This will make the Rx side ready for reception. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci nixge_dma_write_desc_reg(priv, XAXIDMA_RX_CDESC_OFFSET, priv->rx_bd_p); 37362306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 37462306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, 37562306a36Sopenharmony_ci cr | XAXIDMA_CR_RUNSTOP_MASK); 37662306a36Sopenharmony_ci nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, priv->rx_bd_p + 37762306a36Sopenharmony_ci (sizeof(*priv->rx_bd_v) * (RX_BD_NUM - 1))); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Write to the RS (Run-stop) bit in the Tx channel control register. 38062306a36Sopenharmony_ci * Tx channel is now ready to run. But only after we write to the 38162306a36Sopenharmony_ci * tail pointer register that the Tx channel will start transmitting. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci nixge_dma_write_desc_reg(priv, XAXIDMA_TX_CDESC_OFFSET, priv->tx_bd_p); 38462306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 38562306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, 38662306a36Sopenharmony_ci cr | XAXIDMA_CR_RUNSTOP_MASK); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ciout: 39062306a36Sopenharmony_ci nixge_hw_dma_bd_release(ndev); 39162306a36Sopenharmony_ci return -ENOMEM; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void __nixge_device_reset(struct nixge_priv *priv, off_t offset) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci u32 status; 39762306a36Sopenharmony_ci int err; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Reset Axi DMA. This would reset NIXGE Ethernet core as well. 40062306a36Sopenharmony_ci * The reset process of Axi DMA takes a while to complete as all 40162306a36Sopenharmony_ci * pending commands/transfers will be flushed or completed during 40262306a36Sopenharmony_ci * this reset process. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci nixge_dma_write_reg(priv, offset, XAXIDMA_CR_RESET_MASK); 40562306a36Sopenharmony_ci err = nixge_dma_poll_timeout(priv, offset, status, 40662306a36Sopenharmony_ci !(status & XAXIDMA_CR_RESET_MASK), 10, 40762306a36Sopenharmony_ci 1000); 40862306a36Sopenharmony_ci if (err) 40962306a36Sopenharmony_ci netdev_err(priv->ndev, "%s: DMA reset timeout!\n", __func__); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void nixge_device_reset(struct net_device *ndev) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci __nixge_device_reset(priv, XAXIDMA_TX_CR_OFFSET); 41762306a36Sopenharmony_ci __nixge_device_reset(priv, XAXIDMA_RX_CR_OFFSET); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (nixge_hw_dma_bd_init(ndev)) 42062306a36Sopenharmony_ci netdev_err(ndev, "%s: descriptor allocation failed\n", 42162306a36Sopenharmony_ci __func__); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci netif_trans_update(ndev); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void nixge_handle_link_change(struct net_device *ndev) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 42962306a36Sopenharmony_ci struct phy_device *phydev = ndev->phydev; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (phydev->link != priv->link || phydev->speed != priv->speed || 43262306a36Sopenharmony_ci phydev->duplex != priv->duplex) { 43362306a36Sopenharmony_ci priv->link = phydev->link; 43462306a36Sopenharmony_ci priv->speed = phydev->speed; 43562306a36Sopenharmony_ci priv->duplex = phydev->duplex; 43662306a36Sopenharmony_ci phy_print_status(phydev); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void nixge_tx_skb_unmap(struct nixge_priv *priv, 44162306a36Sopenharmony_ci struct nixge_tx_skb *tx_skb) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci if (tx_skb->mapping) { 44462306a36Sopenharmony_ci if (tx_skb->mapped_as_page) 44562306a36Sopenharmony_ci dma_unmap_page(priv->ndev->dev.parent, tx_skb->mapping, 44662306a36Sopenharmony_ci tx_skb->size, DMA_TO_DEVICE); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci dma_unmap_single(priv->ndev->dev.parent, 44962306a36Sopenharmony_ci tx_skb->mapping, 45062306a36Sopenharmony_ci tx_skb->size, DMA_TO_DEVICE); 45162306a36Sopenharmony_ci tx_skb->mapping = 0; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (tx_skb->skb) { 45562306a36Sopenharmony_ci dev_kfree_skb_any(tx_skb->skb); 45662306a36Sopenharmony_ci tx_skb->skb = NULL; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void nixge_start_xmit_done(struct net_device *ndev) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 46362306a36Sopenharmony_ci struct nixge_hw_dma_bd *cur_p; 46462306a36Sopenharmony_ci struct nixge_tx_skb *tx_skb; 46562306a36Sopenharmony_ci unsigned int status = 0; 46662306a36Sopenharmony_ci u32 packets = 0; 46762306a36Sopenharmony_ci u32 size = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[priv->tx_bd_ci]; 47062306a36Sopenharmony_ci tx_skb = &priv->tx_skb[priv->tx_bd_ci]; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci status = cur_p->status; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci while (status & XAXIDMA_BD_STS_COMPLETE_MASK) { 47562306a36Sopenharmony_ci nixge_tx_skb_unmap(priv, tx_skb); 47662306a36Sopenharmony_ci cur_p->status = 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; 47962306a36Sopenharmony_ci packets++; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci ++priv->tx_bd_ci; 48262306a36Sopenharmony_ci priv->tx_bd_ci %= TX_BD_NUM; 48362306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[priv->tx_bd_ci]; 48462306a36Sopenharmony_ci tx_skb = &priv->tx_skb[priv->tx_bd_ci]; 48562306a36Sopenharmony_ci status = cur_p->status; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci ndev->stats.tx_packets += packets; 48962306a36Sopenharmony_ci ndev->stats.tx_bytes += size; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (packets) 49262306a36Sopenharmony_ci netif_wake_queue(ndev); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic int nixge_check_tx_bd_space(struct nixge_priv *priv, 49662306a36Sopenharmony_ci int num_frag) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct nixge_hw_dma_bd *cur_p; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[(priv->tx_bd_tail + num_frag) % TX_BD_NUM]; 50162306a36Sopenharmony_ci if (cur_p->status & XAXIDMA_BD_STS_ALL_MASK) 50262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic netdev_tx_t nixge_start_xmit(struct sk_buff *skb, 50762306a36Sopenharmony_ci struct net_device *ndev) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 51062306a36Sopenharmony_ci struct nixge_hw_dma_bd *cur_p; 51162306a36Sopenharmony_ci struct nixge_tx_skb *tx_skb; 51262306a36Sopenharmony_ci dma_addr_t tail_p, cur_phys; 51362306a36Sopenharmony_ci skb_frag_t *frag; 51462306a36Sopenharmony_ci u32 num_frag; 51562306a36Sopenharmony_ci u32 ii; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci num_frag = skb_shinfo(skb)->nr_frags; 51862306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[priv->tx_bd_tail]; 51962306a36Sopenharmony_ci tx_skb = &priv->tx_skb[priv->tx_bd_tail]; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (nixge_check_tx_bd_space(priv, num_frag)) { 52262306a36Sopenharmony_ci if (!netif_queue_stopped(ndev)) 52362306a36Sopenharmony_ci netif_stop_queue(ndev); 52462306a36Sopenharmony_ci return NETDEV_TX_OK; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci cur_phys = dma_map_single(ndev->dev.parent, skb->data, 52862306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 52962306a36Sopenharmony_ci if (dma_mapping_error(ndev->dev.parent, cur_phys)) 53062306a36Sopenharmony_ci goto drop; 53162306a36Sopenharmony_ci nixge_hw_dma_bd_set_phys(cur_p, cur_phys); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci tx_skb->skb = NULL; 53662306a36Sopenharmony_ci tx_skb->mapping = cur_phys; 53762306a36Sopenharmony_ci tx_skb->size = skb_headlen(skb); 53862306a36Sopenharmony_ci tx_skb->mapped_as_page = false; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci for (ii = 0; ii < num_frag; ii++) { 54162306a36Sopenharmony_ci ++priv->tx_bd_tail; 54262306a36Sopenharmony_ci priv->tx_bd_tail %= TX_BD_NUM; 54362306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[priv->tx_bd_tail]; 54462306a36Sopenharmony_ci tx_skb = &priv->tx_skb[priv->tx_bd_tail]; 54562306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[ii]; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci cur_phys = skb_frag_dma_map(ndev->dev.parent, frag, 0, 54862306a36Sopenharmony_ci skb_frag_size(frag), 54962306a36Sopenharmony_ci DMA_TO_DEVICE); 55062306a36Sopenharmony_ci if (dma_mapping_error(ndev->dev.parent, cur_phys)) 55162306a36Sopenharmony_ci goto frag_err; 55262306a36Sopenharmony_ci nixge_hw_dma_bd_set_phys(cur_p, cur_phys); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci cur_p->cntrl = skb_frag_size(frag); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci tx_skb->skb = NULL; 55762306a36Sopenharmony_ci tx_skb->mapping = cur_phys; 55862306a36Sopenharmony_ci tx_skb->size = skb_frag_size(frag); 55962306a36Sopenharmony_ci tx_skb->mapped_as_page = true; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* last buffer of the frame */ 56362306a36Sopenharmony_ci tx_skb->skb = skb; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci tail_p = priv->tx_bd_p + sizeof(*priv->tx_bd_v) * priv->tx_bd_tail; 56862306a36Sopenharmony_ci /* Start the transfer */ 56962306a36Sopenharmony_ci nixge_dma_write_desc_reg(priv, XAXIDMA_TX_TDESC_OFFSET, tail_p); 57062306a36Sopenharmony_ci ++priv->tx_bd_tail; 57162306a36Sopenharmony_ci priv->tx_bd_tail %= TX_BD_NUM; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return NETDEV_TX_OK; 57462306a36Sopenharmony_cifrag_err: 57562306a36Sopenharmony_ci for (; ii > 0; ii--) { 57662306a36Sopenharmony_ci if (priv->tx_bd_tail) 57762306a36Sopenharmony_ci priv->tx_bd_tail--; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci priv->tx_bd_tail = TX_BD_NUM - 1; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci tx_skb = &priv->tx_skb[priv->tx_bd_tail]; 58262306a36Sopenharmony_ci nixge_tx_skb_unmap(priv, tx_skb); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci cur_p = &priv->tx_bd_v[priv->tx_bd_tail]; 58562306a36Sopenharmony_ci cur_p->status = 0; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci dma_unmap_single(priv->ndev->dev.parent, 58862306a36Sopenharmony_ci tx_skb->mapping, 58962306a36Sopenharmony_ci tx_skb->size, DMA_TO_DEVICE); 59062306a36Sopenharmony_cidrop: 59162306a36Sopenharmony_ci ndev->stats.tx_dropped++; 59262306a36Sopenharmony_ci return NETDEV_TX_OK; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic int nixge_recv(struct net_device *ndev, int budget) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 59862306a36Sopenharmony_ci struct sk_buff *skb, *new_skb; 59962306a36Sopenharmony_ci struct nixge_hw_dma_bd *cur_p; 60062306a36Sopenharmony_ci dma_addr_t tail_p = 0, cur_phys = 0; 60162306a36Sopenharmony_ci u32 packets = 0; 60262306a36Sopenharmony_ci u32 length = 0; 60362306a36Sopenharmony_ci u32 size = 0; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci cur_p = &priv->rx_bd_v[priv->rx_bd_ci]; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK && 60862306a36Sopenharmony_ci budget > packets)) { 60962306a36Sopenharmony_ci tail_p = priv->rx_bd_p + sizeof(*priv->rx_bd_v) * 61062306a36Sopenharmony_ci priv->rx_bd_ci; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci skb = (struct sk_buff *)(uintptr_t) 61362306a36Sopenharmony_ci nixge_hw_dma_bd_get_addr(cur_p, sw_id_offset); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci length = cur_p->status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; 61662306a36Sopenharmony_ci if (length > NIXGE_MAX_JUMBO_FRAME_SIZE) 61762306a36Sopenharmony_ci length = NIXGE_MAX_JUMBO_FRAME_SIZE; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci dma_unmap_single(ndev->dev.parent, 62062306a36Sopenharmony_ci nixge_hw_dma_bd_get_addr(cur_p, phys), 62162306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE, 62262306a36Sopenharmony_ci DMA_FROM_DEVICE); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci skb_put(skb, length); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 62762306a36Sopenharmony_ci skb_checksum_none_assert(skb); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* For now mark them as CHECKSUM_NONE since 63062306a36Sopenharmony_ci * we don't have offload capabilities 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci napi_gro_receive(&priv->napi, skb); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci size += length; 63762306a36Sopenharmony_ci packets++; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci new_skb = netdev_alloc_skb_ip_align(ndev, 64062306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE); 64162306a36Sopenharmony_ci if (!new_skb) 64262306a36Sopenharmony_ci return packets; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci cur_phys = dma_map_single(ndev->dev.parent, new_skb->data, 64562306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE, 64662306a36Sopenharmony_ci DMA_FROM_DEVICE); 64762306a36Sopenharmony_ci if (dma_mapping_error(ndev->dev.parent, cur_phys)) { 64862306a36Sopenharmony_ci /* FIXME: bail out and clean up */ 64962306a36Sopenharmony_ci netdev_err(ndev, "Failed to map ...\n"); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci nixge_hw_dma_bd_set_phys(cur_p, cur_phys); 65262306a36Sopenharmony_ci cur_p->cntrl = NIXGE_MAX_JUMBO_FRAME_SIZE; 65362306a36Sopenharmony_ci cur_p->status = 0; 65462306a36Sopenharmony_ci nixge_hw_dma_bd_set_offset(cur_p, (uintptr_t)new_skb); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci ++priv->rx_bd_ci; 65762306a36Sopenharmony_ci priv->rx_bd_ci %= RX_BD_NUM; 65862306a36Sopenharmony_ci cur_p = &priv->rx_bd_v[priv->rx_bd_ci]; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ndev->stats.rx_packets += packets; 66262306a36Sopenharmony_ci ndev->stats.rx_bytes += size; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (tail_p) 66562306a36Sopenharmony_ci nixge_dma_write_desc_reg(priv, XAXIDMA_RX_TDESC_OFFSET, tail_p); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return packets; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic int nixge_poll(struct napi_struct *napi, int budget) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct nixge_priv *priv = container_of(napi, struct nixge_priv, napi); 67362306a36Sopenharmony_ci int work_done; 67462306a36Sopenharmony_ci u32 status, cr; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci work_done = 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci work_done = nixge_recv(priv->ndev, budget); 67962306a36Sopenharmony_ci if (work_done < budget) { 68062306a36Sopenharmony_ci napi_complete_done(napi, work_done); 68162306a36Sopenharmony_ci status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { 68462306a36Sopenharmony_ci /* If there's more, reschedule, but clear */ 68562306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status); 68662306a36Sopenharmony_ci napi_reschedule(napi); 68762306a36Sopenharmony_ci } else { 68862306a36Sopenharmony_ci /* if not, turn on RX IRQs again ... */ 68962306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 69062306a36Sopenharmony_ci cr |= (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); 69162306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return work_done; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic irqreturn_t nixge_tx_irq(int irq, void *_ndev) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(_ndev); 70162306a36Sopenharmony_ci struct net_device *ndev = _ndev; 70262306a36Sopenharmony_ci unsigned int status; 70362306a36Sopenharmony_ci dma_addr_t phys; 70462306a36Sopenharmony_ci u32 cr; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci status = nixge_dma_read_reg(priv, XAXIDMA_TX_SR_OFFSET); 70762306a36Sopenharmony_ci if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { 70862306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_SR_OFFSET, status); 70962306a36Sopenharmony_ci nixge_start_xmit_done(priv->ndev); 71062306a36Sopenharmony_ci goto out; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci if (!(status & XAXIDMA_IRQ_ALL_MASK)) { 71362306a36Sopenharmony_ci netdev_err(ndev, "No interrupts asserted in Tx path\n"); 71462306a36Sopenharmony_ci return IRQ_NONE; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci if (status & XAXIDMA_IRQ_ERROR_MASK) { 71762306a36Sopenharmony_ci phys = nixge_hw_dma_bd_get_addr(&priv->tx_bd_v[priv->tx_bd_ci], 71862306a36Sopenharmony_ci phys); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci netdev_err(ndev, "DMA Tx error 0x%x\n", status); 72162306a36Sopenharmony_ci netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 72462306a36Sopenharmony_ci /* Disable coalesce, delay timer and error interrupts */ 72562306a36Sopenharmony_ci cr &= (~XAXIDMA_IRQ_ALL_MASK); 72662306a36Sopenharmony_ci /* Write to the Tx channel control register */ 72762306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 73062306a36Sopenharmony_ci /* Disable coalesce, delay timer and error interrupts */ 73162306a36Sopenharmony_ci cr &= (~XAXIDMA_IRQ_ALL_MASK); 73262306a36Sopenharmony_ci /* Write to the Rx channel control register */ 73362306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci tasklet_schedule(&priv->dma_err_tasklet); 73662306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_SR_OFFSET, status); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ciout: 73962306a36Sopenharmony_ci return IRQ_HANDLED; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic irqreturn_t nixge_rx_irq(int irq, void *_ndev) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(_ndev); 74562306a36Sopenharmony_ci struct net_device *ndev = _ndev; 74662306a36Sopenharmony_ci unsigned int status; 74762306a36Sopenharmony_ci dma_addr_t phys; 74862306a36Sopenharmony_ci u32 cr; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci status = nixge_dma_read_reg(priv, XAXIDMA_RX_SR_OFFSET); 75162306a36Sopenharmony_ci if (status & (XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK)) { 75262306a36Sopenharmony_ci /* Turn of IRQs because NAPI */ 75362306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status); 75462306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 75562306a36Sopenharmony_ci cr &= ~(XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); 75662306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (napi_schedule_prep(&priv->napi)) 75962306a36Sopenharmony_ci __napi_schedule(&priv->napi); 76062306a36Sopenharmony_ci goto out; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci if (!(status & XAXIDMA_IRQ_ALL_MASK)) { 76362306a36Sopenharmony_ci netdev_err(ndev, "No interrupts asserted in Rx path\n"); 76462306a36Sopenharmony_ci return IRQ_NONE; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci if (status & XAXIDMA_IRQ_ERROR_MASK) { 76762306a36Sopenharmony_ci phys = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[priv->rx_bd_ci], 76862306a36Sopenharmony_ci phys); 76962306a36Sopenharmony_ci netdev_err(ndev, "DMA Rx error 0x%x\n", status); 77062306a36Sopenharmony_ci netdev_err(ndev, "Current BD is at: 0x%llx\n", (u64)phys); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 77362306a36Sopenharmony_ci /* Disable coalesce, delay timer and error interrupts */ 77462306a36Sopenharmony_ci cr &= (~XAXIDMA_IRQ_ALL_MASK); 77562306a36Sopenharmony_ci /* Finally write to the Tx channel control register */ 77662306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, cr); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 77962306a36Sopenharmony_ci /* Disable coalesce, delay timer and error interrupts */ 78062306a36Sopenharmony_ci cr &= (~XAXIDMA_IRQ_ALL_MASK); 78162306a36Sopenharmony_ci /* write to the Rx channel control register */ 78262306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, cr); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci tasklet_schedule(&priv->dma_err_tasklet); 78562306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_SR_OFFSET, status); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ciout: 78862306a36Sopenharmony_ci return IRQ_HANDLED; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void nixge_dma_err_handler(struct tasklet_struct *t) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct nixge_priv *lp = from_tasklet(lp, t, dma_err_tasklet); 79462306a36Sopenharmony_ci struct nixge_hw_dma_bd *cur_p; 79562306a36Sopenharmony_ci struct nixge_tx_skb *tx_skb; 79662306a36Sopenharmony_ci u32 cr, i; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci __nixge_device_reset(lp, XAXIDMA_TX_CR_OFFSET); 79962306a36Sopenharmony_ci __nixge_device_reset(lp, XAXIDMA_RX_CR_OFFSET); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci for (i = 0; i < TX_BD_NUM; i++) { 80262306a36Sopenharmony_ci cur_p = &lp->tx_bd_v[i]; 80362306a36Sopenharmony_ci tx_skb = &lp->tx_skb[i]; 80462306a36Sopenharmony_ci nixge_tx_skb_unmap(lp, tx_skb); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci nixge_hw_dma_bd_set_phys(cur_p, 0); 80762306a36Sopenharmony_ci cur_p->cntrl = 0; 80862306a36Sopenharmony_ci cur_p->status = 0; 80962306a36Sopenharmony_ci nixge_hw_dma_bd_set_offset(cur_p, 0); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 81362306a36Sopenharmony_ci cur_p = &lp->rx_bd_v[i]; 81462306a36Sopenharmony_ci cur_p->status = 0; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci lp->tx_bd_ci = 0; 81862306a36Sopenharmony_ci lp->tx_bd_tail = 0; 81962306a36Sopenharmony_ci lp->rx_bd_ci = 0; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* Start updating the Rx channel control register */ 82262306a36Sopenharmony_ci cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET); 82362306a36Sopenharmony_ci /* Update the interrupt coalesce count */ 82462306a36Sopenharmony_ci cr = ((cr & ~XAXIDMA_COALESCE_MASK) | 82562306a36Sopenharmony_ci (XAXIDMA_DFT_RX_THRESHOLD << XAXIDMA_COALESCE_SHIFT)); 82662306a36Sopenharmony_ci /* Update the delay timer count */ 82762306a36Sopenharmony_ci cr = ((cr & ~XAXIDMA_DELAY_MASK) | 82862306a36Sopenharmony_ci (XAXIDMA_DFT_RX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); 82962306a36Sopenharmony_ci /* Enable coalesce, delay timer and error interrupts */ 83062306a36Sopenharmony_ci cr |= XAXIDMA_IRQ_ALL_MASK; 83162306a36Sopenharmony_ci /* Finally write to the Rx channel control register */ 83262306a36Sopenharmony_ci nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET, cr); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* Start updating the Tx channel control register */ 83562306a36Sopenharmony_ci cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET); 83662306a36Sopenharmony_ci /* Update the interrupt coalesce count */ 83762306a36Sopenharmony_ci cr = (((cr & ~XAXIDMA_COALESCE_MASK)) | 83862306a36Sopenharmony_ci (XAXIDMA_DFT_TX_THRESHOLD << XAXIDMA_COALESCE_SHIFT)); 83962306a36Sopenharmony_ci /* Update the delay timer count */ 84062306a36Sopenharmony_ci cr = (((cr & ~XAXIDMA_DELAY_MASK)) | 84162306a36Sopenharmony_ci (XAXIDMA_DFT_TX_WAITBOUND << XAXIDMA_DELAY_SHIFT)); 84262306a36Sopenharmony_ci /* Enable coalesce, delay timer and error interrupts */ 84362306a36Sopenharmony_ci cr |= XAXIDMA_IRQ_ALL_MASK; 84462306a36Sopenharmony_ci /* Finally write to the Tx channel control register */ 84562306a36Sopenharmony_ci nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET, cr); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Populate the tail pointer and bring the Rx Axi DMA engine out of 84862306a36Sopenharmony_ci * halted state. This will make the Rx side ready for reception. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci nixge_dma_write_desc_reg(lp, XAXIDMA_RX_CDESC_OFFSET, lp->rx_bd_p); 85162306a36Sopenharmony_ci cr = nixge_dma_read_reg(lp, XAXIDMA_RX_CR_OFFSET); 85262306a36Sopenharmony_ci nixge_dma_write_reg(lp, XAXIDMA_RX_CR_OFFSET, 85362306a36Sopenharmony_ci cr | XAXIDMA_CR_RUNSTOP_MASK); 85462306a36Sopenharmony_ci nixge_dma_write_desc_reg(lp, XAXIDMA_RX_TDESC_OFFSET, lp->rx_bd_p + 85562306a36Sopenharmony_ci (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1))); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Write to the RS (Run-stop) bit in the Tx channel control register. 85862306a36Sopenharmony_ci * Tx channel is now ready to run. But only after we write to the 85962306a36Sopenharmony_ci * tail pointer register that the Tx channel will start transmitting 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ci nixge_dma_write_desc_reg(lp, XAXIDMA_TX_CDESC_OFFSET, lp->tx_bd_p); 86262306a36Sopenharmony_ci cr = nixge_dma_read_reg(lp, XAXIDMA_TX_CR_OFFSET); 86362306a36Sopenharmony_ci nixge_dma_write_reg(lp, XAXIDMA_TX_CR_OFFSET, 86462306a36Sopenharmony_ci cr | XAXIDMA_CR_RUNSTOP_MASK); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int nixge_open(struct net_device *ndev) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 87062306a36Sopenharmony_ci struct phy_device *phy; 87162306a36Sopenharmony_ci int ret; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci nixge_device_reset(ndev); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci phy = of_phy_connect(ndev, priv->phy_node, 87662306a36Sopenharmony_ci &nixge_handle_link_change, 0, priv->phy_mode); 87762306a36Sopenharmony_ci if (!phy) 87862306a36Sopenharmony_ci return -ENODEV; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci phy_start(phy); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Enable tasklets for Axi DMA error handling */ 88362306a36Sopenharmony_ci tasklet_setup(&priv->dma_err_tasklet, nixge_dma_err_handler); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci napi_enable(&priv->napi); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Enable interrupts for Axi DMA Tx */ 88862306a36Sopenharmony_ci ret = request_irq(priv->tx_irq, nixge_tx_irq, 0, ndev->name, ndev); 88962306a36Sopenharmony_ci if (ret) 89062306a36Sopenharmony_ci goto err_tx_irq; 89162306a36Sopenharmony_ci /* Enable interrupts for Axi DMA Rx */ 89262306a36Sopenharmony_ci ret = request_irq(priv->rx_irq, nixge_rx_irq, 0, ndev->name, ndev); 89362306a36Sopenharmony_ci if (ret) 89462306a36Sopenharmony_ci goto err_rx_irq; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci netif_start_queue(ndev); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cierr_rx_irq: 90162306a36Sopenharmony_ci free_irq(priv->tx_irq, ndev); 90262306a36Sopenharmony_cierr_tx_irq: 90362306a36Sopenharmony_ci napi_disable(&priv->napi); 90462306a36Sopenharmony_ci phy_stop(phy); 90562306a36Sopenharmony_ci phy_disconnect(phy); 90662306a36Sopenharmony_ci tasklet_kill(&priv->dma_err_tasklet); 90762306a36Sopenharmony_ci netdev_err(ndev, "request_irq() failed\n"); 90862306a36Sopenharmony_ci return ret; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic int nixge_stop(struct net_device *ndev) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 91462306a36Sopenharmony_ci u32 cr; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci netif_stop_queue(ndev); 91762306a36Sopenharmony_ci napi_disable(&priv->napi); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (ndev->phydev) { 92062306a36Sopenharmony_ci phy_stop(ndev->phydev); 92162306a36Sopenharmony_ci phy_disconnect(ndev->phydev); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 92562306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_RX_CR_OFFSET, 92662306a36Sopenharmony_ci cr & (~XAXIDMA_CR_RUNSTOP_MASK)); 92762306a36Sopenharmony_ci cr = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 92862306a36Sopenharmony_ci nixge_dma_write_reg(priv, XAXIDMA_TX_CR_OFFSET, 92962306a36Sopenharmony_ci cr & (~XAXIDMA_CR_RUNSTOP_MASK)); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci tasklet_kill(&priv->dma_err_tasklet); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci free_irq(priv->tx_irq, ndev); 93462306a36Sopenharmony_ci free_irq(priv->rx_irq, ndev); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci nixge_hw_dma_bd_release(ndev); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return 0; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int nixge_change_mtu(struct net_device *ndev, int new_mtu) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci if (netif_running(ndev)) 94462306a36Sopenharmony_ci return -EBUSY; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if ((new_mtu + NIXGE_HDR_SIZE + NIXGE_TRL_SIZE) > 94762306a36Sopenharmony_ci NIXGE_MAX_JUMBO_FRAME_SIZE) 94862306a36Sopenharmony_ci return -EINVAL; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci ndev->mtu = new_mtu; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return 0; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic s32 __nixge_hw_set_mac_address(struct net_device *ndev) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_LSB, 96062306a36Sopenharmony_ci (ndev->dev_addr[2]) << 24 | 96162306a36Sopenharmony_ci (ndev->dev_addr[3] << 16) | 96262306a36Sopenharmony_ci (ndev->dev_addr[4] << 8) | 96362306a36Sopenharmony_ci (ndev->dev_addr[5] << 0)); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_MSB, 96662306a36Sopenharmony_ci (ndev->dev_addr[1] | (ndev->dev_addr[0] << 8))); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci return 0; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int nixge_net_set_mac_address(struct net_device *ndev, void *p) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci int err; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci err = eth_mac_addr(ndev, p); 97662306a36Sopenharmony_ci if (!err) 97762306a36Sopenharmony_ci __nixge_hw_set_mac_address(ndev); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci return err; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic const struct net_device_ops nixge_netdev_ops = { 98362306a36Sopenharmony_ci .ndo_open = nixge_open, 98462306a36Sopenharmony_ci .ndo_stop = nixge_stop, 98562306a36Sopenharmony_ci .ndo_start_xmit = nixge_start_xmit, 98662306a36Sopenharmony_ci .ndo_change_mtu = nixge_change_mtu, 98762306a36Sopenharmony_ci .ndo_set_mac_address = nixge_net_set_mac_address, 98862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 98962306a36Sopenharmony_ci}; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void nixge_ethtools_get_drvinfo(struct net_device *ndev, 99262306a36Sopenharmony_ci struct ethtool_drvinfo *ed) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci strscpy(ed->driver, "nixge", sizeof(ed->driver)); 99562306a36Sopenharmony_ci strscpy(ed->bus_info, "platform", sizeof(ed->bus_info)); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int 99962306a36Sopenharmony_cinixge_ethtools_get_coalesce(struct net_device *ndev, 100062306a36Sopenharmony_ci struct ethtool_coalesce *ecoalesce, 100162306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 100262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 100562306a36Sopenharmony_ci u32 regval = 0; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci regval = nixge_dma_read_reg(priv, XAXIDMA_RX_CR_OFFSET); 100862306a36Sopenharmony_ci ecoalesce->rx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK) 100962306a36Sopenharmony_ci >> XAXIDMA_COALESCE_SHIFT; 101062306a36Sopenharmony_ci regval = nixge_dma_read_reg(priv, XAXIDMA_TX_CR_OFFSET); 101162306a36Sopenharmony_ci ecoalesce->tx_max_coalesced_frames = (regval & XAXIDMA_COALESCE_MASK) 101262306a36Sopenharmony_ci >> XAXIDMA_COALESCE_SHIFT; 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic int 101762306a36Sopenharmony_cinixge_ethtools_set_coalesce(struct net_device *ndev, 101862306a36Sopenharmony_ci struct ethtool_coalesce *ecoalesce, 101962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 102062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (netif_running(ndev)) { 102562306a36Sopenharmony_ci netdev_err(ndev, 102662306a36Sopenharmony_ci "Please stop netif before applying configuration\n"); 102762306a36Sopenharmony_ci return -EBUSY; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (ecoalesce->rx_max_coalesced_frames) 103162306a36Sopenharmony_ci priv->coalesce_count_rx = ecoalesce->rx_max_coalesced_frames; 103262306a36Sopenharmony_ci if (ecoalesce->tx_max_coalesced_frames) 103362306a36Sopenharmony_ci priv->coalesce_count_tx = ecoalesce->tx_max_coalesced_frames; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci return 0; 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int nixge_ethtools_set_phys_id(struct net_device *ndev, 103962306a36Sopenharmony_ci enum ethtool_phys_id_state state) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 104262306a36Sopenharmony_ci u32 ctrl; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ctrl = nixge_ctrl_read_reg(priv, NIXGE_REG_LED_CTL); 104562306a36Sopenharmony_ci switch (state) { 104662306a36Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 104762306a36Sopenharmony_ci ctrl |= NIXGE_ID_LED_CTL_EN; 104862306a36Sopenharmony_ci /* Enable identification LED override*/ 104962306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl); 105062306a36Sopenharmony_ci return 2; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci case ETHTOOL_ID_ON: 105362306a36Sopenharmony_ci ctrl |= NIXGE_ID_LED_CTL_VAL; 105462306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci case ETHTOOL_ID_OFF: 105862306a36Sopenharmony_ci ctrl &= ~NIXGE_ID_LED_CTL_VAL; 105962306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl); 106062306a36Sopenharmony_ci break; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 106362306a36Sopenharmony_ci /* Restore LED settings */ 106462306a36Sopenharmony_ci ctrl &= ~NIXGE_ID_LED_CTL_EN; 106562306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_LED_CTL, ctrl); 106662306a36Sopenharmony_ci break; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return 0; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic const struct ethtool_ops nixge_ethtool_ops = { 107362306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES, 107462306a36Sopenharmony_ci .get_drvinfo = nixge_ethtools_get_drvinfo, 107562306a36Sopenharmony_ci .get_coalesce = nixge_ethtools_get_coalesce, 107662306a36Sopenharmony_ci .set_coalesce = nixge_ethtools_set_coalesce, 107762306a36Sopenharmony_ci .set_phys_id = nixge_ethtools_set_phys_id, 107862306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 107962306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 108062306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 108162306a36Sopenharmony_ci}; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic int nixge_mdio_read_c22(struct mii_bus *bus, int phy_id, int reg) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci struct nixge_priv *priv = bus->priv; 108662306a36Sopenharmony_ci u32 status, tmp; 108762306a36Sopenharmony_ci int err; 108862306a36Sopenharmony_ci u16 device; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci device = reg & 0x1f; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE22 | NIXGE_MDIO_OP(NIXGE_MDIO_C22_READ) | 109362306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 109662306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 109962306a36Sopenharmony_ci !status, 10, 1000); 110062306a36Sopenharmony_ci if (err) { 110162306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting read command"); 110262306a36Sopenharmony_ci return err; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci status = nixge_ctrl_read_reg(priv, NIXGE_REG_MDIO_DATA); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return status; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic int nixge_mdio_read_c45(struct mii_bus *bus, int phy_id, int device, 111162306a36Sopenharmony_ci int reg) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci struct nixge_priv *priv = bus->priv; 111462306a36Sopenharmony_ci u32 status, tmp; 111562306a36Sopenharmony_ci int err; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_ADDR, reg & 0xffff); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE45 | 112062306a36Sopenharmony_ci NIXGE_MDIO_OP(NIXGE_MDIO_OP_ADDRESS) | 112162306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 112462306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 112762306a36Sopenharmony_ci !status, 10, 1000); 112862306a36Sopenharmony_ci if (err) { 112962306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting address"); 113062306a36Sopenharmony_ci return err; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_C45_READ) | 113462306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 113762306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 114062306a36Sopenharmony_ci !status, 10, 1000); 114162306a36Sopenharmony_ci if (err) { 114262306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting read command"); 114362306a36Sopenharmony_ci return err; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci status = nixge_ctrl_read_reg(priv, NIXGE_REG_MDIO_DATA); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci return status; 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic int nixge_mdio_write_c22(struct mii_bus *bus, int phy_id, int reg, 115262306a36Sopenharmony_ci u16 val) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct nixge_priv *priv = bus->priv; 115562306a36Sopenharmony_ci u32 status, tmp; 115662306a36Sopenharmony_ci u16 device; 115762306a36Sopenharmony_ci int err; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci device = reg & 0x1f; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE22 | NIXGE_MDIO_OP(NIXGE_MDIO_C22_WRITE) | 116262306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_DATA, val); 116562306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 116662306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 116962306a36Sopenharmony_ci !status, 10, 1000); 117062306a36Sopenharmony_ci if (err) 117162306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting write command"); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return err; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int nixge_mdio_write_c45(struct mii_bus *bus, int phy_id, 117762306a36Sopenharmony_ci int device, int reg, u16 val) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct nixge_priv *priv = bus->priv; 118062306a36Sopenharmony_ci u32 status, tmp; 118162306a36Sopenharmony_ci int err; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_ADDR, reg & 0xffff); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE45 | 118662306a36Sopenharmony_ci NIXGE_MDIO_OP(NIXGE_MDIO_OP_ADDRESS) | 118762306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 119062306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 119362306a36Sopenharmony_ci !status, 10, 1000); 119462306a36Sopenharmony_ci if (err) { 119562306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting address"); 119662306a36Sopenharmony_ci return err; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_C45_WRITE) | 120062306a36Sopenharmony_ci NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_DATA, val); 120362306a36Sopenharmony_ci nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status, 120662306a36Sopenharmony_ci !status, 10, 1000); 120762306a36Sopenharmony_ci if (err) 120862306a36Sopenharmony_ci dev_err(priv->dev, "timeout setting write command"); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci return err; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct mii_bus *bus; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci bus = devm_mdiobus_alloc(priv->dev); 121862306a36Sopenharmony_ci if (!bus) 121962306a36Sopenharmony_ci return -ENOMEM; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(priv->dev)); 122262306a36Sopenharmony_ci bus->priv = priv; 122362306a36Sopenharmony_ci bus->name = "nixge_mii_bus"; 122462306a36Sopenharmony_ci bus->read = nixge_mdio_read_c22; 122562306a36Sopenharmony_ci bus->write = nixge_mdio_write_c22; 122662306a36Sopenharmony_ci bus->read_c45 = nixge_mdio_read_c45; 122762306a36Sopenharmony_ci bus->write_c45 = nixge_mdio_write_c45; 122862306a36Sopenharmony_ci bus->parent = priv->dev; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci priv->mii_bus = bus; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return of_mdiobus_register(bus, np); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic void *nixge_get_nvmem_address(struct device *dev) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct nvmem_cell *cell; 123862306a36Sopenharmony_ci size_t cell_size; 123962306a36Sopenharmony_ci char *mac; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci cell = nvmem_cell_get(dev, "address"); 124262306a36Sopenharmony_ci if (IS_ERR(cell)) 124362306a36Sopenharmony_ci return cell; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci mac = nvmem_cell_read(cell, &cell_size); 124662306a36Sopenharmony_ci nvmem_cell_put(cell); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return mac; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci/* Match table for of_platform binding */ 125262306a36Sopenharmony_cistatic const struct of_device_id nixge_dt_ids[] = { 125362306a36Sopenharmony_ci { .compatible = "ni,xge-enet-2.00", .data = (void *)NIXGE_V2 }, 125462306a36Sopenharmony_ci { .compatible = "ni,xge-enet-3.00", .data = (void *)NIXGE_V3 }, 125562306a36Sopenharmony_ci {}, 125662306a36Sopenharmony_ci}; 125762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, nixge_dt_ids); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic int nixge_of_get_resources(struct platform_device *pdev) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci const struct of_device_id *of_id; 126262306a36Sopenharmony_ci enum nixge_version version; 126362306a36Sopenharmony_ci struct net_device *ndev; 126462306a36Sopenharmony_ci struct nixge_priv *priv; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ndev = platform_get_drvdata(pdev); 126762306a36Sopenharmony_ci priv = netdev_priv(ndev); 126862306a36Sopenharmony_ci of_id = of_match_node(nixge_dt_ids, pdev->dev.of_node); 126962306a36Sopenharmony_ci if (!of_id) 127062306a36Sopenharmony_ci return -ENODEV; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci version = (enum nixge_version)of_id->data; 127362306a36Sopenharmony_ci if (version <= NIXGE_V2) 127462306a36Sopenharmony_ci priv->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 127562306a36Sopenharmony_ci else 127662306a36Sopenharmony_ci priv->dma_regs = devm_platform_ioremap_resource_byname(pdev, "dma"); 127762306a36Sopenharmony_ci if (IS_ERR(priv->dma_regs)) { 127862306a36Sopenharmony_ci netdev_err(ndev, "failed to map dma regs\n"); 127962306a36Sopenharmony_ci return PTR_ERR(priv->dma_regs); 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci if (version <= NIXGE_V2) 128262306a36Sopenharmony_ci priv->ctrl_regs = priv->dma_regs + NIXGE_REG_CTRL_OFFSET; 128362306a36Sopenharmony_ci else 128462306a36Sopenharmony_ci priv->ctrl_regs = devm_platform_ioremap_resource_byname(pdev, "ctrl"); 128562306a36Sopenharmony_ci if (IS_ERR(priv->ctrl_regs)) { 128662306a36Sopenharmony_ci netdev_err(ndev, "failed to map ctrl regs\n"); 128762306a36Sopenharmony_ci return PTR_ERR(priv->ctrl_regs); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci return 0; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic int nixge_probe(struct platform_device *pdev) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci struct device_node *mn, *phy_node; 129562306a36Sopenharmony_ci struct nixge_priv *priv; 129662306a36Sopenharmony_ci struct net_device *ndev; 129762306a36Sopenharmony_ci const u8 *mac_addr; 129862306a36Sopenharmony_ci int err; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci ndev = alloc_etherdev(sizeof(*priv)); 130162306a36Sopenharmony_ci if (!ndev) 130262306a36Sopenharmony_ci return -ENOMEM; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci platform_set_drvdata(pdev, ndev); 130562306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci ndev->features = NETIF_F_SG; 130862306a36Sopenharmony_ci ndev->netdev_ops = &nixge_netdev_ops; 130962306a36Sopenharmony_ci ndev->ethtool_ops = &nixge_ethtool_ops; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci /* MTU range: 64 - 9000 */ 131262306a36Sopenharmony_ci ndev->min_mtu = 64; 131362306a36Sopenharmony_ci ndev->max_mtu = NIXGE_JUMBO_MTU; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci mac_addr = nixge_get_nvmem_address(&pdev->dev); 131662306a36Sopenharmony_ci if (!IS_ERR(mac_addr) && is_valid_ether_addr(mac_addr)) { 131762306a36Sopenharmony_ci eth_hw_addr_set(ndev, mac_addr); 131862306a36Sopenharmony_ci kfree(mac_addr); 131962306a36Sopenharmony_ci } else { 132062306a36Sopenharmony_ci eth_hw_addr_random(ndev); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci priv = netdev_priv(ndev); 132462306a36Sopenharmony_ci priv->ndev = ndev; 132562306a36Sopenharmony_ci priv->dev = &pdev->dev; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci netif_napi_add(ndev, &priv->napi, nixge_poll); 132862306a36Sopenharmony_ci err = nixge_of_get_resources(pdev); 132962306a36Sopenharmony_ci if (err) 133062306a36Sopenharmony_ci goto free_netdev; 133162306a36Sopenharmony_ci __nixge_hw_set_mac_address(ndev); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci priv->tx_irq = platform_get_irq_byname(pdev, "tx"); 133462306a36Sopenharmony_ci if (priv->tx_irq < 0) { 133562306a36Sopenharmony_ci netdev_err(ndev, "could not find 'tx' irq"); 133662306a36Sopenharmony_ci err = priv->tx_irq; 133762306a36Sopenharmony_ci goto free_netdev; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci priv->rx_irq = platform_get_irq_byname(pdev, "rx"); 134162306a36Sopenharmony_ci if (priv->rx_irq < 0) { 134262306a36Sopenharmony_ci netdev_err(ndev, "could not find 'rx' irq"); 134362306a36Sopenharmony_ci err = priv->rx_irq; 134462306a36Sopenharmony_ci goto free_netdev; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci priv->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD; 134862306a36Sopenharmony_ci priv->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci mn = of_get_child_by_name(pdev->dev.of_node, "mdio"); 135162306a36Sopenharmony_ci if (mn) { 135262306a36Sopenharmony_ci err = nixge_mdio_setup(priv, mn); 135362306a36Sopenharmony_ci of_node_put(mn); 135462306a36Sopenharmony_ci if (err) { 135562306a36Sopenharmony_ci netdev_err(ndev, "error registering mdio bus"); 135662306a36Sopenharmony_ci goto free_netdev; 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci err = of_get_phy_mode(pdev->dev.of_node, &priv->phy_mode); 136162306a36Sopenharmony_ci if (err) { 136262306a36Sopenharmony_ci netdev_err(ndev, "not find \"phy-mode\" property\n"); 136362306a36Sopenharmony_ci goto unregister_mdio; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); 136762306a36Sopenharmony_ci if (!phy_node && of_phy_is_fixed_link(pdev->dev.of_node)) { 136862306a36Sopenharmony_ci err = of_phy_register_fixed_link(pdev->dev.of_node); 136962306a36Sopenharmony_ci if (err < 0) { 137062306a36Sopenharmony_ci netdev_err(ndev, "broken fixed-link specification\n"); 137162306a36Sopenharmony_ci goto unregister_mdio; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci phy_node = of_node_get(pdev->dev.of_node); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci priv->phy_node = phy_node; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci err = register_netdev(priv->ndev); 137862306a36Sopenharmony_ci if (err) { 137962306a36Sopenharmony_ci netdev_err(ndev, "register_netdev() error (%i)\n", err); 138062306a36Sopenharmony_ci goto free_phy; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cifree_phy: 138662306a36Sopenharmony_ci if (of_phy_is_fixed_link(pdev->dev.of_node)) 138762306a36Sopenharmony_ci of_phy_deregister_fixed_link(pdev->dev.of_node); 138862306a36Sopenharmony_ci of_node_put(phy_node); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ciunregister_mdio: 139162306a36Sopenharmony_ci if (priv->mii_bus) 139262306a36Sopenharmony_ci mdiobus_unregister(priv->mii_bus); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cifree_netdev: 139562306a36Sopenharmony_ci free_netdev(ndev); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci return err; 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic int nixge_remove(struct platform_device *pdev) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 140362306a36Sopenharmony_ci struct nixge_priv *priv = netdev_priv(ndev); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci unregister_netdev(ndev); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (of_phy_is_fixed_link(pdev->dev.of_node)) 140862306a36Sopenharmony_ci of_phy_deregister_fixed_link(pdev->dev.of_node); 140962306a36Sopenharmony_ci of_node_put(priv->phy_node); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (priv->mii_bus) 141262306a36Sopenharmony_ci mdiobus_unregister(priv->mii_bus); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci free_netdev(ndev); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci return 0; 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic struct platform_driver nixge_driver = { 142062306a36Sopenharmony_ci .probe = nixge_probe, 142162306a36Sopenharmony_ci .remove = nixge_remove, 142262306a36Sopenharmony_ci .driver = { 142362306a36Sopenharmony_ci .name = "nixge", 142462306a36Sopenharmony_ci .of_match_table = nixge_dt_ids, 142562306a36Sopenharmony_ci }, 142662306a36Sopenharmony_ci}; 142762306a36Sopenharmony_cimodule_platform_driver(nixge_driver); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 143062306a36Sopenharmony_ciMODULE_DESCRIPTION("National Instruments XGE Management MAC"); 143162306a36Sopenharmony_ciMODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>"); 1432