14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20dd07709SNoam Camus /* 30dd07709SNoam Camus * Copyright(c) 2015 EZchip Technologies. 40dd07709SNoam Camus */ 50dd07709SNoam Camus 60dd07709SNoam Camus #include <linux/module.h> 70dd07709SNoam Camus #include <linux/etherdevice.h> 8282ccf6eSFlorian Westphal #include <linux/interrupt.h> 9*3d40aed8SRob Herring #include <linux/mod_devicetable.h> 100dd07709SNoam Camus #include <linux/of_net.h> 11*3d40aed8SRob Herring #include <linux/platform_device.h> 120dd07709SNoam Camus #include "nps_enet.h" 130dd07709SNoam Camus 140dd07709SNoam Camus #define DRV_NAME "nps_mgt_enet" 150dd07709SNoam Camus 16094f57aaSElad Kanfi static inline bool nps_enet_is_tx_pending(struct nps_enet_priv *priv) 17094f57aaSElad Kanfi { 18094f57aaSElad Kanfi u32 tx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); 19094f57aaSElad Kanfi u32 tx_ctrl_ct = (tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT; 20094f57aaSElad Kanfi 21094f57aaSElad Kanfi return (!tx_ctrl_ct && priv->tx_skb); 22094f57aaSElad Kanfi } 23094f57aaSElad Kanfi 240dd07709SNoam Camus static void nps_enet_clean_rx_fifo(struct net_device *ndev, u32 frame_len) 250dd07709SNoam Camus { 260dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 270dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(frame_len, sizeof(u32)); 280dd07709SNoam Camus 290dd07709SNoam Camus /* Empty Rx FIFO buffer by reading all words */ 300dd07709SNoam Camus for (i = 0; i < len; i++) 310dd07709SNoam Camus nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 320dd07709SNoam Camus } 330dd07709SNoam Camus 340dd07709SNoam Camus static void nps_enet_read_rx_fifo(struct net_device *ndev, 350dd07709SNoam Camus unsigned char *dst, u32 length) 360dd07709SNoam Camus { 370dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 380dd07709SNoam Camus s32 i, last = length & (sizeof(u32) - 1); 390dd07709SNoam Camus u32 *reg = (u32 *)dst, len = length / sizeof(u32); 400dd07709SNoam Camus bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32)); 410dd07709SNoam Camus 420dd07709SNoam Camus /* In case dst is not aligned we need an intermediate buffer */ 43b54b8c2dSLada Trimasova if (dst_is_aligned) { 44b54b8c2dSLada Trimasova ioread32_rep(priv->regs_base + NPS_ENET_REG_RX_BUF, reg, len); 45b54b8c2dSLada Trimasova reg += len; 46ddbff3e8SElad Kanfi } else { /* !dst_is_aligned */ 470dd07709SNoam Camus for (i = 0; i < len; i++, reg++) { 48b0a8d1a0SArnd Bergmann u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 49ddbff3e8SElad Kanfi 50b54b8c2dSLada Trimasova put_unaligned_be32(buf, reg); 510dd07709SNoam Camus } 520dd07709SNoam Camus } 530dd07709SNoam Camus /* copy last bytes (if any) */ 540dd07709SNoam Camus if (last) { 55b54b8c2dSLada Trimasova u32 buf; 56ddbff3e8SElad Kanfi 57b54b8c2dSLada Trimasova ioread32_rep(priv->regs_base + NPS_ENET_REG_RX_BUF, &buf, 1); 58b0a8d1a0SArnd Bergmann memcpy((u8 *)reg, &buf, last); 590dd07709SNoam Camus } 600dd07709SNoam Camus } 610dd07709SNoam Camus 620dd07709SNoam Camus static u32 nps_enet_rx_handler(struct net_device *ndev) 630dd07709SNoam Camus { 640dd07709SNoam Camus u32 frame_len, err = 0; 650dd07709SNoam Camus u32 work_done = 0; 660dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 670dd07709SNoam Camus struct sk_buff *skb; 68b54b8c2dSLada Trimasova u32 rx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); 69b54b8c2dSLada Trimasova u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT; 70b54b8c2dSLada Trimasova u32 rx_ctrl_er = (rx_ctrl_value & RX_CTL_ER_MASK) >> RX_CTL_ER_SHIFT; 71b54b8c2dSLada Trimasova u32 rx_ctrl_crc = (rx_ctrl_value & RX_CTL_CRC_MASK) >> RX_CTL_CRC_SHIFT; 720dd07709SNoam Camus 73b54b8c2dSLada Trimasova frame_len = (rx_ctrl_value & RX_CTL_NR_MASK) >> RX_CTL_NR_SHIFT; 740dd07709SNoam Camus 750dd07709SNoam Camus /* Check if we got RX */ 76b54b8c2dSLada Trimasova if (!rx_ctrl_cr) 770dd07709SNoam Camus return work_done; 780dd07709SNoam Camus 790dd07709SNoam Camus /* If we got here there is a work for us */ 800dd07709SNoam Camus work_done++; 810dd07709SNoam Camus 820dd07709SNoam Camus /* Check Rx error */ 83b54b8c2dSLada Trimasova if (rx_ctrl_er) { 840dd07709SNoam Camus ndev->stats.rx_errors++; 850dd07709SNoam Camus err = 1; 860dd07709SNoam Camus } 870dd07709SNoam Camus 880dd07709SNoam Camus /* Check Rx CRC error */ 89b54b8c2dSLada Trimasova if (rx_ctrl_crc) { 900dd07709SNoam Camus ndev->stats.rx_crc_errors++; 910dd07709SNoam Camus ndev->stats.rx_dropped++; 920dd07709SNoam Camus err = 1; 930dd07709SNoam Camus } 940dd07709SNoam Camus 950dd07709SNoam Camus /* Check Frame length Min 64b */ 960dd07709SNoam Camus if (unlikely(frame_len < ETH_ZLEN)) { 970dd07709SNoam Camus ndev->stats.rx_length_errors++; 980dd07709SNoam Camus ndev->stats.rx_dropped++; 990dd07709SNoam Camus err = 1; 1000dd07709SNoam Camus } 1010dd07709SNoam Camus 1020dd07709SNoam Camus if (err) 1030dd07709SNoam Camus goto rx_irq_clean; 1040dd07709SNoam Camus 1050dd07709SNoam Camus /* Skb allocation */ 1060dd07709SNoam Camus skb = netdev_alloc_skb_ip_align(ndev, frame_len); 1070dd07709SNoam Camus if (unlikely(!skb)) { 1080dd07709SNoam Camus ndev->stats.rx_errors++; 1090dd07709SNoam Camus ndev->stats.rx_dropped++; 1100dd07709SNoam Camus goto rx_irq_clean; 1110dd07709SNoam Camus } 1120dd07709SNoam Camus 1130dd07709SNoam Camus /* Copy frame from Rx fifo into the skb */ 1140dd07709SNoam Camus nps_enet_read_rx_fifo(ndev, skb->data, frame_len); 1150dd07709SNoam Camus 1160dd07709SNoam Camus skb_put(skb, frame_len); 1170dd07709SNoam Camus skb->protocol = eth_type_trans(skb, ndev); 1180dd07709SNoam Camus skb->ip_summed = CHECKSUM_UNNECESSARY; 1190dd07709SNoam Camus 1200dd07709SNoam Camus ndev->stats.rx_packets++; 1210dd07709SNoam Camus ndev->stats.rx_bytes += frame_len; 1220dd07709SNoam Camus netif_receive_skb(skb); 1230dd07709SNoam Camus 1240dd07709SNoam Camus goto rx_irq_frame_done; 1250dd07709SNoam Camus 1260dd07709SNoam Camus rx_irq_clean: 1270dd07709SNoam Camus /* Clean Rx fifo */ 1280dd07709SNoam Camus nps_enet_clean_rx_fifo(ndev, frame_len); 1290dd07709SNoam Camus 1300dd07709SNoam Camus rx_irq_frame_done: 1310dd07709SNoam Camus /* Ack Rx ctrl register */ 1320dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_RX_CTL, 0); 1330dd07709SNoam Camus 1340dd07709SNoam Camus return work_done; 1350dd07709SNoam Camus } 1360dd07709SNoam Camus 1370dd07709SNoam Camus static void nps_enet_tx_handler(struct net_device *ndev) 1380dd07709SNoam Camus { 1390dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 140b54b8c2dSLada Trimasova u32 tx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); 141b54b8c2dSLada Trimasova u32 tx_ctrl_et = (tx_ctrl_value & TX_CTL_ET_MASK) >> TX_CTL_ET_SHIFT; 142b54b8c2dSLada Trimasova u32 tx_ctrl_nt = (tx_ctrl_value & TX_CTL_NT_MASK) >> TX_CTL_NT_SHIFT; 1430dd07709SNoam Camus 1440dd07709SNoam Camus /* Check if we got TX */ 145094f57aaSElad Kanfi if (!nps_enet_is_tx_pending(priv)) 1460dd07709SNoam Camus return; 1470dd07709SNoam Camus 1483d99b74aSNoam Camus /* Ack Tx ctrl register */ 1493d99b74aSNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, 0); 1503d99b74aSNoam Camus 1510dd07709SNoam Camus /* Check Tx transmit error */ 152b54b8c2dSLada Trimasova if (unlikely(tx_ctrl_et)) { 1530dd07709SNoam Camus ndev->stats.tx_errors++; 1540dd07709SNoam Camus } else { 1550dd07709SNoam Camus ndev->stats.tx_packets++; 156b54b8c2dSLada Trimasova ndev->stats.tx_bytes += tx_ctrl_nt; 1570dd07709SNoam Camus } 1580dd07709SNoam Camus 1590dd07709SNoam Camus dev_kfree_skb(priv->tx_skb); 160e5df49d5SElad Kanfi priv->tx_skb = NULL; 1610dd07709SNoam Camus 1620dd07709SNoam Camus if (netif_queue_stopped(ndev)) 1630dd07709SNoam Camus netif_wake_queue(ndev); 1640dd07709SNoam Camus } 1650dd07709SNoam Camus 1660dd07709SNoam Camus /** 1670dd07709SNoam Camus * nps_enet_poll - NAPI poll handler. 1680dd07709SNoam Camus * @napi: Pointer to napi_struct structure. 1690dd07709SNoam Camus * @budget: How many frames to process on one call. 1700dd07709SNoam Camus * 1710dd07709SNoam Camus * returns: Number of processed frames 1720dd07709SNoam Camus */ 1730dd07709SNoam Camus static int nps_enet_poll(struct napi_struct *napi, int budget) 1740dd07709SNoam Camus { 1750dd07709SNoam Camus struct net_device *ndev = napi->dev; 1760dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 1770dd07709SNoam Camus u32 work_done; 1780dd07709SNoam Camus 1790dd07709SNoam Camus nps_enet_tx_handler(ndev); 1800dd07709SNoam Camus work_done = nps_enet_rx_handler(ndev); 181358e78b5SZakharov Vlad if ((work_done < budget) && napi_complete_done(napi, work_done)) { 182b54b8c2dSLada Trimasova u32 buf_int_enable_value = 0; 18341493795SNoam Camus 184b54b8c2dSLada Trimasova /* set tx_done and rx_rdy bits */ 185b54b8c2dSLada Trimasova buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT; 186b54b8c2dSLada Trimasova buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT; 187b54b8c2dSLada Trimasova 1880dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 189b54b8c2dSLada Trimasova buf_int_enable_value); 19005c00d82SElad Kanfi 19105c00d82SElad Kanfi /* in case we will get a tx interrupt while interrupts 19205c00d82SElad Kanfi * are masked, we will lose it since the tx is edge interrupt. 19305c00d82SElad Kanfi * specifically, while executing the code section above, 19405c00d82SElad Kanfi * between nps_enet_tx_handler and the interrupts enable, all 19505c00d82SElad Kanfi * tx requests will be stuck until we will get an rx interrupt. 19605c00d82SElad Kanfi * the two code lines below will solve this situation by 19705c00d82SElad Kanfi * re-adding ourselves to the poll list. 19805c00d82SElad Kanfi */ 199094f57aaSElad Kanfi if (nps_enet_is_tx_pending(priv)) { 20086651650SElad Kanfi nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 20105c00d82SElad Kanfi napi_reschedule(napi); 2020dd07709SNoam Camus } 20386651650SElad Kanfi } 2040dd07709SNoam Camus 2050dd07709SNoam Camus return work_done; 2060dd07709SNoam Camus } 2070dd07709SNoam Camus 2080dd07709SNoam Camus /** 2090dd07709SNoam Camus * nps_enet_irq_handler - Global interrupt handler for ENET. 2100dd07709SNoam Camus * @irq: irq number. 2110dd07709SNoam Camus * @dev_instance: device instance. 2120dd07709SNoam Camus * 2130dd07709SNoam Camus * returns: IRQ_HANDLED for all cases. 2140dd07709SNoam Camus * 2150dd07709SNoam Camus * EZchip ENET has 2 interrupt causes, and depending on bits raised in 2160dd07709SNoam Camus * CTRL registers we may tell what is a reason for interrupt to fire up. 2170dd07709SNoam Camus * We got one for RX and the other for TX (completion). 2180dd07709SNoam Camus */ 2190dd07709SNoam Camus static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance) 2200dd07709SNoam Camus { 2210dd07709SNoam Camus struct net_device *ndev = dev_instance; 2220dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 223b54b8c2dSLada Trimasova u32 rx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); 224b54b8c2dSLada Trimasova u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT; 2250dd07709SNoam Camus 226094f57aaSElad Kanfi if (nps_enet_is_tx_pending(priv) || rx_ctrl_cr) 2270dd07709SNoam Camus if (likely(napi_schedule_prep(&priv->napi))) { 2280dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 2290dd07709SNoam Camus __napi_schedule(&priv->napi); 2300dd07709SNoam Camus } 2310dd07709SNoam Camus 2320dd07709SNoam Camus return IRQ_HANDLED; 2330dd07709SNoam Camus } 2340dd07709SNoam Camus 2350dd07709SNoam Camus static void nps_enet_set_hw_mac_address(struct net_device *ndev) 2360dd07709SNoam Camus { 2370dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 238b54b8c2dSLada Trimasova u32 ge_mac_cfg_1_value = 0; 239b54b8c2dSLada Trimasova u32 *ge_mac_cfg_2_value = &priv->ge_mac_cfg_2_value; 2400dd07709SNoam Camus 2410dd07709SNoam Camus /* set MAC address in HW */ 242b54b8c2dSLada Trimasova ge_mac_cfg_1_value |= ndev->dev_addr[0] << CFG_1_OCTET_0_SHIFT; 243b54b8c2dSLada Trimasova ge_mac_cfg_1_value |= ndev->dev_addr[1] << CFG_1_OCTET_1_SHIFT; 244b54b8c2dSLada Trimasova ge_mac_cfg_1_value |= ndev->dev_addr[2] << CFG_1_OCTET_2_SHIFT; 245b54b8c2dSLada Trimasova ge_mac_cfg_1_value |= ndev->dev_addr[3] << CFG_1_OCTET_3_SHIFT; 246b54b8c2dSLada Trimasova *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_OCTET_4_MASK) 247b54b8c2dSLada Trimasova | ndev->dev_addr[4] << CFG_2_OCTET_4_SHIFT; 248b54b8c2dSLada Trimasova *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_OCTET_5_MASK) 249b54b8c2dSLada Trimasova | ndev->dev_addr[5] << CFG_2_OCTET_5_SHIFT; 2500dd07709SNoam Camus 2510dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1, 252b54b8c2dSLada Trimasova ge_mac_cfg_1_value); 2530dd07709SNoam Camus 2540dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 255b54b8c2dSLada Trimasova *ge_mac_cfg_2_value); 2560dd07709SNoam Camus } 2570dd07709SNoam Camus 2580dd07709SNoam Camus /** 2590dd07709SNoam Camus * nps_enet_hw_reset - Reset the network device. 2600dd07709SNoam Camus * @ndev: Pointer to the network device. 2610dd07709SNoam Camus * 2620dd07709SNoam Camus * This function reset the PCS and TX fifo. 2630dd07709SNoam Camus * The programming model is to set the relevant reset bits 2640dd07709SNoam Camus * wait for some time for this to propagate and then unset 2650dd07709SNoam Camus * the reset bits. This way we ensure that reset procedure 2660dd07709SNoam Camus * is done successfully by device. 2670dd07709SNoam Camus */ 2680dd07709SNoam Camus static void nps_enet_hw_reset(struct net_device *ndev) 2690dd07709SNoam Camus { 2700dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 271b54b8c2dSLada Trimasova u32 ge_rst_value = 0, phase_fifo_ctl_value = 0; 2720dd07709SNoam Camus 2730dd07709SNoam Camus /* Pcs reset sequence*/ 274b54b8c2dSLada Trimasova ge_rst_value |= NPS_ENET_ENABLE << RST_GMAC_0_SHIFT; 275b54b8c2dSLada Trimasova nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value); 2760dd07709SNoam Camus usleep_range(10, 20); 277136ab0d0SNoam Camus ge_rst_value = 0; 278b54b8c2dSLada Trimasova nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value); 2790dd07709SNoam Camus 2800dd07709SNoam Camus /* Tx fifo reset sequence */ 281b54b8c2dSLada Trimasova phase_fifo_ctl_value |= NPS_ENET_ENABLE << PHASE_FIFO_CTL_RST_SHIFT; 282b54b8c2dSLada Trimasova phase_fifo_ctl_value |= NPS_ENET_ENABLE << PHASE_FIFO_CTL_INIT_SHIFT; 2830dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 284b54b8c2dSLada Trimasova phase_fifo_ctl_value); 2850dd07709SNoam Camus usleep_range(10, 20); 286b54b8c2dSLada Trimasova phase_fifo_ctl_value = 0; 2870dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 288b54b8c2dSLada Trimasova phase_fifo_ctl_value); 2890dd07709SNoam Camus } 2900dd07709SNoam Camus 2910dd07709SNoam Camus static void nps_enet_hw_enable_control(struct net_device *ndev) 2920dd07709SNoam Camus { 2930dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 294b54b8c2dSLada Trimasova u32 ge_mac_cfg_0_value = 0, buf_int_enable_value = 0; 295b54b8c2dSLada Trimasova u32 *ge_mac_cfg_2_value = &priv->ge_mac_cfg_2_value; 296b54b8c2dSLada Trimasova u32 *ge_mac_cfg_3_value = &priv->ge_mac_cfg_3_value; 2970dd07709SNoam Camus s32 max_frame_length; 2980dd07709SNoam Camus 2990dd07709SNoam Camus /* Enable Rx and Tx statistics */ 300b54b8c2dSLada Trimasova *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_STAT_EN_MASK) 301b54b8c2dSLada Trimasova | NPS_ENET_GE_MAC_CFG_2_STAT_EN << CFG_2_STAT_EN_SHIFT; 3020dd07709SNoam Camus 3030dd07709SNoam Camus /* Discard packets with different MAC address */ 304b54b8c2dSLada Trimasova *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK) 305b54b8c2dSLada Trimasova | NPS_ENET_ENABLE << CFG_2_DISK_DA_SHIFT; 3060dd07709SNoam Camus 3070dd07709SNoam Camus /* Discard multicast packets */ 308b54b8c2dSLada Trimasova *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK) 309b54b8c2dSLada Trimasova | NPS_ENET_ENABLE << CFG_2_DISK_MC_SHIFT; 3100dd07709SNoam Camus 3110dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 312b54b8c2dSLada Trimasova *ge_mac_cfg_2_value); 3130dd07709SNoam Camus 3140dd07709SNoam Camus /* Discard Packets bigger than max frame length */ 3150dd07709SNoam Camus max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN; 316b54b8c2dSLada Trimasova if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) { 317b54b8c2dSLada Trimasova *ge_mac_cfg_3_value = 318b54b8c2dSLada Trimasova (*ge_mac_cfg_3_value & ~CFG_3_MAX_LEN_MASK) 319b54b8c2dSLada Trimasova | max_frame_length << CFG_3_MAX_LEN_SHIFT; 320b54b8c2dSLada Trimasova } 3210dd07709SNoam Camus 3220dd07709SNoam Camus /* Enable interrupts */ 323b54b8c2dSLada Trimasova buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT; 324b54b8c2dSLada Trimasova buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT; 3250dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 326b54b8c2dSLada Trimasova buf_int_enable_value); 3270dd07709SNoam Camus 3280dd07709SNoam Camus /* Write device MAC address to HW */ 3290dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 3300dd07709SNoam Camus 3310dd07709SNoam Camus /* Rx and Tx HW features */ 332b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_PAD_EN_SHIFT; 333b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_CRC_EN_SHIFT; 334b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_CRC_STRIP_SHIFT; 3350dd07709SNoam Camus 3360dd07709SNoam Camus /* IFG configuration */ 337b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= 338b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_0_RX_IFG << CFG_0_RX_IFG_SHIFT; 339b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= 340b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_0_TX_IFG << CFG_0_TX_IFG_SHIFT; 3410dd07709SNoam Camus 3420dd07709SNoam Camus /* preamble configuration */ 343b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_PR_CHECK_EN_SHIFT; 344b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= 345b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN << CFG_0_TX_PR_LEN_SHIFT; 3460dd07709SNoam Camus 3470dd07709SNoam Camus /* enable flow control frames */ 348b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_FC_EN_SHIFT; 349b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_FC_EN_SHIFT; 350b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= 351b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR << CFG_0_TX_FC_RETR_SHIFT; 352b54b8c2dSLada Trimasova *ge_mac_cfg_3_value = (*ge_mac_cfg_3_value & ~CFG_3_CF_DROP_MASK) 353b54b8c2dSLada Trimasova | NPS_ENET_ENABLE << CFG_3_CF_DROP_SHIFT; 3540dd07709SNoam Camus 3550dd07709SNoam Camus /* Enable Rx and Tx */ 356b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_EN_SHIFT; 357b54b8c2dSLada Trimasova ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_EN_SHIFT; 3580dd07709SNoam Camus 359de671567SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, 360b54b8c2dSLada Trimasova *ge_mac_cfg_3_value); 3610dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 362b54b8c2dSLada Trimasova ge_mac_cfg_0_value); 3630dd07709SNoam Camus } 3640dd07709SNoam Camus 3650dd07709SNoam Camus static void nps_enet_hw_disable_control(struct net_device *ndev) 3660dd07709SNoam Camus { 3670dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 3680dd07709SNoam Camus 3690dd07709SNoam Camus /* Disable interrupts */ 3700dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 3710dd07709SNoam Camus 3720dd07709SNoam Camus /* Disable Rx and Tx */ 3730dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 0); 3740dd07709SNoam Camus } 3750dd07709SNoam Camus 3760dd07709SNoam Camus static void nps_enet_send_frame(struct net_device *ndev, 3770dd07709SNoam Camus struct sk_buff *skb) 3780dd07709SNoam Camus { 3790dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 380b54b8c2dSLada Trimasova u32 tx_ctrl_value = 0; 3810dd07709SNoam Camus short length = skb->len; 3820dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(length, sizeof(u32)); 383b0a8d1a0SArnd Bergmann u32 *src = (void *)skb->data; 3840dd07709SNoam Camus bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32)); 3850dd07709SNoam Camus 3860dd07709SNoam Camus /* In case src is not aligned we need an intermediate buffer */ 3870dd07709SNoam Camus if (src_is_aligned) 388b54b8c2dSLada Trimasova iowrite32_rep(priv->regs_base + NPS_ENET_REG_TX_BUF, src, len); 389b0a8d1a0SArnd Bergmann else /* !src_is_aligned */ 390b0a8d1a0SArnd Bergmann for (i = 0; i < len; i++, src++) 391b0a8d1a0SArnd Bergmann nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, 392b54b8c2dSLada Trimasova get_unaligned_be32(src)); 3930dd07709SNoam Camus 3940dd07709SNoam Camus /* Write the length of the Frame */ 395b54b8c2dSLada Trimasova tx_ctrl_value |= length << TX_CTL_NT_SHIFT; 3960dd07709SNoam Camus 397b54b8c2dSLada Trimasova tx_ctrl_value |= NPS_ENET_ENABLE << TX_CTL_CT_SHIFT; 3980dd07709SNoam Camus /* Send Frame */ 399b54b8c2dSLada Trimasova nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl_value); 4000dd07709SNoam Camus } 4010dd07709SNoam Camus 4020dd07709SNoam Camus /** 4030dd07709SNoam Camus * nps_enet_set_mac_address - Set the MAC address for this device. 4040dd07709SNoam Camus * @ndev: Pointer to net_device structure. 4050dd07709SNoam Camus * @p: 6 byte Address to be written as MAC address. 4060dd07709SNoam Camus * 4070dd07709SNoam Camus * This function copies the HW address from the sockaddr structure to the 4080dd07709SNoam Camus * net_device structure and updates the address in HW. 4090dd07709SNoam Camus * 4100dd07709SNoam Camus * returns: -EBUSY if the net device is busy or 0 if the address is set 4110dd07709SNoam Camus * successfully. 4120dd07709SNoam Camus */ 4130dd07709SNoam Camus static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p) 4140dd07709SNoam Camus { 4150dd07709SNoam Camus struct sockaddr *addr = p; 4160dd07709SNoam Camus s32 res; 4170dd07709SNoam Camus 4180dd07709SNoam Camus if (netif_running(ndev)) 4190dd07709SNoam Camus return -EBUSY; 4200dd07709SNoam Camus 4210dd07709SNoam Camus res = eth_mac_addr(ndev, p); 4220dd07709SNoam Camus if (!res) { 423f3956ebbSJakub Kicinski eth_hw_addr_set(ndev, addr->sa_data); 4240dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 4250dd07709SNoam Camus } 4260dd07709SNoam Camus 4270dd07709SNoam Camus return res; 4280dd07709SNoam Camus } 4290dd07709SNoam Camus 4300dd07709SNoam Camus /** 4310dd07709SNoam Camus * nps_enet_set_rx_mode - Change the receive filtering mode. 4320dd07709SNoam Camus * @ndev: Pointer to the network device. 4330dd07709SNoam Camus * 4340dd07709SNoam Camus * This function enables/disables promiscuous mode 4350dd07709SNoam Camus */ 4360dd07709SNoam Camus static void nps_enet_set_rx_mode(struct net_device *ndev) 4370dd07709SNoam Camus { 4380dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 439b54b8c2dSLada Trimasova u32 ge_mac_cfg_2_value = priv->ge_mac_cfg_2_value; 4400dd07709SNoam Camus 4410dd07709SNoam Camus if (ndev->flags & IFF_PROMISC) { 442b54b8c2dSLada Trimasova ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK) 443b54b8c2dSLada Trimasova | NPS_ENET_DISABLE << CFG_2_DISK_DA_SHIFT; 444b54b8c2dSLada Trimasova ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK) 445b54b8c2dSLada Trimasova | NPS_ENET_DISABLE << CFG_2_DISK_MC_SHIFT; 446b54b8c2dSLada Trimasova 4470dd07709SNoam Camus } else { 448b54b8c2dSLada Trimasova ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK) 449b54b8c2dSLada Trimasova | NPS_ENET_ENABLE << CFG_2_DISK_DA_SHIFT; 450b54b8c2dSLada Trimasova ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK) 451b54b8c2dSLada Trimasova | NPS_ENET_ENABLE << CFG_2_DISK_MC_SHIFT; 4520dd07709SNoam Camus } 4530dd07709SNoam Camus 454b54b8c2dSLada Trimasova nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2_value); 4550dd07709SNoam Camus } 4560dd07709SNoam Camus 4570dd07709SNoam Camus /** 4580dd07709SNoam Camus * nps_enet_open - Open the network device. 4590dd07709SNoam Camus * @ndev: Pointer to the network device. 4600dd07709SNoam Camus * 4610dd07709SNoam Camus * returns: 0, on success or non-zero error value on failure. 4620dd07709SNoam Camus * 4630dd07709SNoam Camus * This function sets the MAC address, requests and enables an IRQ 4640dd07709SNoam Camus * for the ENET device and starts the Tx queue. 4650dd07709SNoam Camus */ 4660dd07709SNoam Camus static s32 nps_enet_open(struct net_device *ndev) 4670dd07709SNoam Camus { 4680dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 4690dd07709SNoam Camus s32 err; 4700dd07709SNoam Camus 4710dd07709SNoam Camus /* Reset private variables */ 472e5df49d5SElad Kanfi priv->tx_skb = NULL; 473b54b8c2dSLada Trimasova priv->ge_mac_cfg_2_value = 0; 474b54b8c2dSLada Trimasova priv->ge_mac_cfg_3_value = 0; 4750dd07709SNoam Camus 4760dd07709SNoam Camus /* ge_mac_cfg_3 default values */ 477b54b8c2dSLada Trimasova priv->ge_mac_cfg_3_value |= 478b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH << CFG_3_RX_IFG_TH_SHIFT; 479b54b8c2dSLada Trimasova 480b54b8c2dSLada Trimasova priv->ge_mac_cfg_3_value |= 481b54b8c2dSLada Trimasova NPS_ENET_GE_MAC_CFG_3_MAX_LEN << CFG_3_MAX_LEN_SHIFT; 4820dd07709SNoam Camus 4830dd07709SNoam Camus /* Disable HW device */ 4840dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 4850dd07709SNoam Camus 4860dd07709SNoam Camus /* irq Rx allocation */ 4870dd07709SNoam Camus err = request_irq(priv->irq, nps_enet_irq_handler, 4880dd07709SNoam Camus 0, "enet-rx-tx", ndev); 4890dd07709SNoam Camus if (err) 4900dd07709SNoam Camus return err; 4910dd07709SNoam Camus 4920dd07709SNoam Camus napi_enable(&priv->napi); 4930dd07709SNoam Camus 4940dd07709SNoam Camus /* Enable HW device */ 4950dd07709SNoam Camus nps_enet_hw_reset(ndev); 4960dd07709SNoam Camus nps_enet_hw_enable_control(ndev); 4970dd07709SNoam Camus 4980dd07709SNoam Camus netif_start_queue(ndev); 4990dd07709SNoam Camus 5000dd07709SNoam Camus return 0; 5010dd07709SNoam Camus } 5020dd07709SNoam Camus 5030dd07709SNoam Camus /** 5040dd07709SNoam Camus * nps_enet_stop - Close the network device. 5050dd07709SNoam Camus * @ndev: Pointer to the network device. 5060dd07709SNoam Camus * 5070dd07709SNoam Camus * This function stops the Tx queue, disables interrupts for the ENET device. 5080dd07709SNoam Camus */ 5090dd07709SNoam Camus static s32 nps_enet_stop(struct net_device *ndev) 5100dd07709SNoam Camus { 5110dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 5120dd07709SNoam Camus 5130dd07709SNoam Camus napi_disable(&priv->napi); 5140dd07709SNoam Camus netif_stop_queue(ndev); 5150dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 5160dd07709SNoam Camus free_irq(priv->irq, ndev); 5170dd07709SNoam Camus 5180dd07709SNoam Camus return 0; 5190dd07709SNoam Camus } 5200dd07709SNoam Camus 5210dd07709SNoam Camus /** 5220dd07709SNoam Camus * nps_enet_start_xmit - Starts the data transmission. 5230dd07709SNoam Camus * @skb: sk_buff pointer that contains data to be Transmitted. 5240dd07709SNoam Camus * @ndev: Pointer to net_device structure. 5250dd07709SNoam Camus * 5260dd07709SNoam Camus * returns: NETDEV_TX_OK, on success 5270dd07709SNoam Camus * NETDEV_TX_BUSY, if any of the descriptors are not free. 5280dd07709SNoam Camus * 5290dd07709SNoam Camus * This function is invoked from upper layers to initiate transmission. 5300dd07709SNoam Camus */ 5310dd07709SNoam Camus static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb, 5320dd07709SNoam Camus struct net_device *ndev) 5330dd07709SNoam Camus { 5340dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 5350dd07709SNoam Camus 5360dd07709SNoam Camus /* This driver handles one frame at a time */ 5370dd07709SNoam Camus netif_stop_queue(ndev); 5380dd07709SNoam Camus 5390dd07709SNoam Camus priv->tx_skb = skb; 5400dd07709SNoam Camus 541e5df49d5SElad Kanfi /* make sure tx_skb is actually written to the memory 542e5df49d5SElad Kanfi * before the HW is informed and the IRQ is fired. 543e5df49d5SElad Kanfi */ 544e5df49d5SElad Kanfi wmb(); 545e5df49d5SElad Kanfi 54693fcf83eSNoam Camus nps_enet_send_frame(ndev, skb); 54793fcf83eSNoam Camus 5480dd07709SNoam Camus return NETDEV_TX_OK; 5490dd07709SNoam Camus } 5500dd07709SNoam Camus 5510dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 5520dd07709SNoam Camus static void nps_enet_poll_controller(struct net_device *ndev) 5530dd07709SNoam Camus { 5540dd07709SNoam Camus disable_irq(ndev->irq); 5550dd07709SNoam Camus nps_enet_irq_handler(ndev->irq, ndev); 5560dd07709SNoam Camus enable_irq(ndev->irq); 5570dd07709SNoam Camus } 5580dd07709SNoam Camus #endif 5590dd07709SNoam Camus 5600dd07709SNoam Camus static const struct net_device_ops nps_netdev_ops = { 5610dd07709SNoam Camus .ndo_open = nps_enet_open, 5620dd07709SNoam Camus .ndo_stop = nps_enet_stop, 5630dd07709SNoam Camus .ndo_start_xmit = nps_enet_start_xmit, 5640dd07709SNoam Camus .ndo_set_mac_address = nps_enet_set_mac_address, 5650dd07709SNoam Camus .ndo_set_rx_mode = nps_enet_set_rx_mode, 5660dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 5670dd07709SNoam Camus .ndo_poll_controller = nps_enet_poll_controller, 5680dd07709SNoam Camus #endif 5690dd07709SNoam Camus }; 5700dd07709SNoam Camus 5710dd07709SNoam Camus static s32 nps_enet_probe(struct platform_device *pdev) 5720dd07709SNoam Camus { 5730dd07709SNoam Camus struct device *dev = &pdev->dev; 5740dd07709SNoam Camus struct net_device *ndev; 5750dd07709SNoam Camus struct nps_enet_priv *priv; 5760dd07709SNoam Camus s32 err = 0; 5770dd07709SNoam Camus 5780dd07709SNoam Camus if (!dev->of_node) 5790dd07709SNoam Camus return -ENODEV; 5800dd07709SNoam Camus 5810dd07709SNoam Camus ndev = alloc_etherdev(sizeof(struct nps_enet_priv)); 5820dd07709SNoam Camus if (!ndev) 5830dd07709SNoam Camus return -ENOMEM; 5840dd07709SNoam Camus 5850dd07709SNoam Camus platform_set_drvdata(pdev, ndev); 5860dd07709SNoam Camus SET_NETDEV_DEV(ndev, dev); 5870dd07709SNoam Camus priv = netdev_priv(ndev); 5880dd07709SNoam Camus 5890dd07709SNoam Camus /* The EZ NET specific entries in the device structure. */ 5900dd07709SNoam Camus ndev->netdev_ops = &nps_netdev_ops; 5910dd07709SNoam Camus ndev->watchdog_timeo = (400 * HZ / 1000); 5920dd07709SNoam Camus /* FIXME :: no multicast support yet */ 5930dd07709SNoam Camus ndev->flags &= ~IFF_MULTICAST; 5940dd07709SNoam Camus 595b6df9830SYueHaibing priv->regs_base = devm_platform_ioremap_resource(pdev, 0); 5960dd07709SNoam Camus if (IS_ERR(priv->regs_base)) { 5970dd07709SNoam Camus err = PTR_ERR(priv->regs_base); 5980dd07709SNoam Camus goto out_netdev; 5990dd07709SNoam Camus } 6000dd07709SNoam Camus dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base); 6010dd07709SNoam Camus 6020dd07709SNoam Camus /* set kernel MAC address to dev */ 6039ca01b25SJakub Kicinski err = of_get_ethdev_address(dev->of_node, ndev); 60483216e39SMichael Walle if (err) 6050dd07709SNoam Camus eth_hw_addr_random(ndev); 6060dd07709SNoam Camus 6070dd07709SNoam Camus /* Get IRQ number */ 6080dd07709SNoam Camus priv->irq = platform_get_irq(pdev, 0); 6090de449d5SPavel Skripkin if (priv->irq < 0) { 6100dd07709SNoam Camus err = -ENODEV; 6110dd07709SNoam Camus goto out_netdev; 6120dd07709SNoam Camus } 6130dd07709SNoam Camus 614b707b89fSJakub Kicinski netif_napi_add_weight(ndev, &priv->napi, nps_enet_poll, 6150dd07709SNoam Camus NPS_ENET_NAPI_POLL_WEIGHT); 6160dd07709SNoam Camus 6170dd07709SNoam Camus /* Register the driver. Should be the last thing in probe */ 6180dd07709SNoam Camus err = register_netdev(ndev); 6190dd07709SNoam Camus if (err) { 6200dd07709SNoam Camus dev_err(dev, "Failed to register ndev for %s, err = 0x%08x\n", 6210dd07709SNoam Camus ndev->name, (s32)err); 6220dd07709SNoam Camus goto out_netif_api; 6230dd07709SNoam Camus } 6240dd07709SNoam Camus 6250dd07709SNoam Camus dev_info(dev, "(rx/tx=%d)\n", priv->irq); 6260dd07709SNoam Camus return 0; 6270dd07709SNoam Camus 6280dd07709SNoam Camus out_netif_api: 6290dd07709SNoam Camus netif_napi_del(&priv->napi); 6300dd07709SNoam Camus out_netdev: 6310dd07709SNoam Camus free_netdev(ndev); 6320dd07709SNoam Camus 6330dd07709SNoam Camus return err; 6340dd07709SNoam Camus } 6350dd07709SNoam Camus 6360dd07709SNoam Camus static s32 nps_enet_remove(struct platform_device *pdev) 6370dd07709SNoam Camus { 6380dd07709SNoam Camus struct net_device *ndev = platform_get_drvdata(pdev); 6390dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 6400dd07709SNoam Camus 6410dd07709SNoam Camus unregister_netdev(ndev); 6420dd07709SNoam Camus netif_napi_del(&priv->napi); 643e4b8700eSPavel Skripkin free_netdev(ndev); 6440dd07709SNoam Camus 6450dd07709SNoam Camus return 0; 6460dd07709SNoam Camus } 6470dd07709SNoam Camus 6480dd07709SNoam Camus static const struct of_device_id nps_enet_dt_ids[] = { 6490dd07709SNoam Camus { .compatible = "ezchip,nps-mgt-enet" }, 6500dd07709SNoam Camus { /* Sentinel */ } 6510dd07709SNoam Camus }; 652fc971a2fSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, nps_enet_dt_ids); 6530dd07709SNoam Camus 6540dd07709SNoam Camus static struct platform_driver nps_enet_driver = { 6550dd07709SNoam Camus .probe = nps_enet_probe, 6560dd07709SNoam Camus .remove = nps_enet_remove, 6570dd07709SNoam Camus .driver = { 6580dd07709SNoam Camus .name = DRV_NAME, 6590dd07709SNoam Camus .of_match_table = nps_enet_dt_ids, 6600dd07709SNoam Camus }, 6610dd07709SNoam Camus }; 6620dd07709SNoam Camus 6630dd07709SNoam Camus module_platform_driver(nps_enet_driver); 6640dd07709SNoam Camus 6650dd07709SNoam Camus MODULE_AUTHOR("EZchip Semiconductor"); 6660dd07709SNoam Camus MODULE_LICENSE("GPL v2"); 667