1*0dd07709SNoam Camus /* 2*0dd07709SNoam Camus * Copyright(c) 2015 EZchip Technologies. 3*0dd07709SNoam Camus * 4*0dd07709SNoam Camus * This program is free software; you can redistribute it and/or modify it 5*0dd07709SNoam Camus * under the terms and conditions of the GNU General Public License, 6*0dd07709SNoam Camus * version 2, as published by the Free Software Foundation. 7*0dd07709SNoam Camus * 8*0dd07709SNoam Camus * This program is distributed in the hope it will be useful, but WITHOUT 9*0dd07709SNoam Camus * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10*0dd07709SNoam Camus * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11*0dd07709SNoam Camus * more details. 12*0dd07709SNoam Camus * 13*0dd07709SNoam Camus * The full GNU General Public License is included in this distribution in 14*0dd07709SNoam Camus * the file called "COPYING". 15*0dd07709SNoam Camus */ 16*0dd07709SNoam Camus 17*0dd07709SNoam Camus #include <linux/module.h> 18*0dd07709SNoam Camus #include <linux/etherdevice.h> 19*0dd07709SNoam Camus #include <linux/of_address.h> 20*0dd07709SNoam Camus #include <linux/of_irq.h> 21*0dd07709SNoam Camus #include <linux/of_net.h> 22*0dd07709SNoam Camus #include <linux/of_platform.h> 23*0dd07709SNoam Camus #include "nps_enet.h" 24*0dd07709SNoam Camus 25*0dd07709SNoam Camus #define DRV_NAME "nps_mgt_enet" 26*0dd07709SNoam Camus 27*0dd07709SNoam Camus static void nps_enet_clean_rx_fifo(struct net_device *ndev, u32 frame_len) 28*0dd07709SNoam Camus { 29*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 30*0dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(frame_len, sizeof(u32)); 31*0dd07709SNoam Camus 32*0dd07709SNoam Camus /* Empty Rx FIFO buffer by reading all words */ 33*0dd07709SNoam Camus for (i = 0; i < len; i++) 34*0dd07709SNoam Camus nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 35*0dd07709SNoam Camus } 36*0dd07709SNoam Camus 37*0dd07709SNoam Camus static void nps_enet_read_rx_fifo(struct net_device *ndev, 38*0dd07709SNoam Camus unsigned char *dst, u32 length) 39*0dd07709SNoam Camus { 40*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 41*0dd07709SNoam Camus s32 i, last = length & (sizeof(u32) - 1); 42*0dd07709SNoam Camus u32 *reg = (u32 *)dst, len = length / sizeof(u32); 43*0dd07709SNoam Camus bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32)); 44*0dd07709SNoam Camus 45*0dd07709SNoam Camus /* In case dst is not aligned we need an intermediate buffer */ 46*0dd07709SNoam Camus if (dst_is_aligned) 47*0dd07709SNoam Camus for (i = 0; i < len; i++, reg++) 48*0dd07709SNoam Camus *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 49*0dd07709SNoam Camus else { /* !dst_is_aligned */ 50*0dd07709SNoam Camus for (i = 0; i < len; i++, reg++) { 51*0dd07709SNoam Camus u32 buf = 52*0dd07709SNoam Camus nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 53*0dd07709SNoam Camus 54*0dd07709SNoam Camus /* to accommodate word-unaligned address of "reg" 55*0dd07709SNoam Camus * we have to do memcpy_toio() instead of simple "=". 56*0dd07709SNoam Camus */ 57*0dd07709SNoam Camus memcpy_toio((void __iomem *)reg, &buf, sizeof(buf)); 58*0dd07709SNoam Camus } 59*0dd07709SNoam Camus } 60*0dd07709SNoam Camus 61*0dd07709SNoam Camus /* copy last bytes (if any) */ 62*0dd07709SNoam Camus if (last) { 63*0dd07709SNoam Camus u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 64*0dd07709SNoam Camus 65*0dd07709SNoam Camus memcpy_toio((void __iomem *)reg, &buf, last); 66*0dd07709SNoam Camus } 67*0dd07709SNoam Camus } 68*0dd07709SNoam Camus 69*0dd07709SNoam Camus static u32 nps_enet_rx_handler(struct net_device *ndev) 70*0dd07709SNoam Camus { 71*0dd07709SNoam Camus u32 frame_len, err = 0; 72*0dd07709SNoam Camus u32 work_done = 0; 73*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 74*0dd07709SNoam Camus struct sk_buff *skb; 75*0dd07709SNoam Camus struct nps_enet_rx_ctl rx_ctrl; 76*0dd07709SNoam Camus 77*0dd07709SNoam Camus rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); 78*0dd07709SNoam Camus frame_len = rx_ctrl.nr; 79*0dd07709SNoam Camus 80*0dd07709SNoam Camus /* Check if we got RX */ 81*0dd07709SNoam Camus if (!rx_ctrl.cr) 82*0dd07709SNoam Camus return work_done; 83*0dd07709SNoam Camus 84*0dd07709SNoam Camus /* If we got here there is a work for us */ 85*0dd07709SNoam Camus work_done++; 86*0dd07709SNoam Camus 87*0dd07709SNoam Camus /* Check Rx error */ 88*0dd07709SNoam Camus if (rx_ctrl.er) { 89*0dd07709SNoam Camus ndev->stats.rx_errors++; 90*0dd07709SNoam Camus err = 1; 91*0dd07709SNoam Camus } 92*0dd07709SNoam Camus 93*0dd07709SNoam Camus /* Check Rx CRC error */ 94*0dd07709SNoam Camus if (rx_ctrl.crc) { 95*0dd07709SNoam Camus ndev->stats.rx_crc_errors++; 96*0dd07709SNoam Camus ndev->stats.rx_dropped++; 97*0dd07709SNoam Camus err = 1; 98*0dd07709SNoam Camus } 99*0dd07709SNoam Camus 100*0dd07709SNoam Camus /* Check Frame length Min 64b */ 101*0dd07709SNoam Camus if (unlikely(frame_len < ETH_ZLEN)) { 102*0dd07709SNoam Camus ndev->stats.rx_length_errors++; 103*0dd07709SNoam Camus ndev->stats.rx_dropped++; 104*0dd07709SNoam Camus err = 1; 105*0dd07709SNoam Camus } 106*0dd07709SNoam Camus 107*0dd07709SNoam Camus if (err) 108*0dd07709SNoam Camus goto rx_irq_clean; 109*0dd07709SNoam Camus 110*0dd07709SNoam Camus /* Skb allocation */ 111*0dd07709SNoam Camus skb = netdev_alloc_skb_ip_align(ndev, frame_len); 112*0dd07709SNoam Camus if (unlikely(!skb)) { 113*0dd07709SNoam Camus ndev->stats.rx_errors++; 114*0dd07709SNoam Camus ndev->stats.rx_dropped++; 115*0dd07709SNoam Camus goto rx_irq_clean; 116*0dd07709SNoam Camus } 117*0dd07709SNoam Camus 118*0dd07709SNoam Camus /* Copy frame from Rx fifo into the skb */ 119*0dd07709SNoam Camus nps_enet_read_rx_fifo(ndev, skb->data, frame_len); 120*0dd07709SNoam Camus 121*0dd07709SNoam Camus skb_put(skb, frame_len); 122*0dd07709SNoam Camus skb->protocol = eth_type_trans(skb, ndev); 123*0dd07709SNoam Camus skb->ip_summed = CHECKSUM_UNNECESSARY; 124*0dd07709SNoam Camus 125*0dd07709SNoam Camus ndev->stats.rx_packets++; 126*0dd07709SNoam Camus ndev->stats.rx_bytes += frame_len; 127*0dd07709SNoam Camus netif_receive_skb(skb); 128*0dd07709SNoam Camus 129*0dd07709SNoam Camus goto rx_irq_frame_done; 130*0dd07709SNoam Camus 131*0dd07709SNoam Camus rx_irq_clean: 132*0dd07709SNoam Camus /* Clean Rx fifo */ 133*0dd07709SNoam Camus nps_enet_clean_rx_fifo(ndev, frame_len); 134*0dd07709SNoam Camus 135*0dd07709SNoam Camus rx_irq_frame_done: 136*0dd07709SNoam Camus /* Ack Rx ctrl register */ 137*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_RX_CTL, 0); 138*0dd07709SNoam Camus 139*0dd07709SNoam Camus return work_done; 140*0dd07709SNoam Camus } 141*0dd07709SNoam Camus 142*0dd07709SNoam Camus static void nps_enet_tx_handler(struct net_device *ndev) 143*0dd07709SNoam Camus { 144*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 145*0dd07709SNoam Camus struct nps_enet_tx_ctl tx_ctrl; 146*0dd07709SNoam Camus 147*0dd07709SNoam Camus tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); 148*0dd07709SNoam Camus 149*0dd07709SNoam Camus /* Check if we got TX */ 150*0dd07709SNoam Camus if (!priv->tx_packet_sent || tx_ctrl.ct) 151*0dd07709SNoam Camus return; 152*0dd07709SNoam Camus 153*0dd07709SNoam Camus /* Check Tx transmit error */ 154*0dd07709SNoam Camus if (unlikely(tx_ctrl.et)) { 155*0dd07709SNoam Camus ndev->stats.tx_errors++; 156*0dd07709SNoam Camus } else { 157*0dd07709SNoam Camus ndev->stats.tx_packets++; 158*0dd07709SNoam Camus ndev->stats.tx_bytes += tx_ctrl.nt; 159*0dd07709SNoam Camus } 160*0dd07709SNoam Camus 161*0dd07709SNoam Camus if (priv->tx_skb) { 162*0dd07709SNoam Camus dev_kfree_skb(priv->tx_skb); 163*0dd07709SNoam Camus priv->tx_skb = NULL; 164*0dd07709SNoam Camus } 165*0dd07709SNoam Camus 166*0dd07709SNoam Camus priv->tx_packet_sent = false; 167*0dd07709SNoam Camus 168*0dd07709SNoam Camus if (netif_queue_stopped(ndev)) 169*0dd07709SNoam Camus netif_wake_queue(ndev); 170*0dd07709SNoam Camus } 171*0dd07709SNoam Camus 172*0dd07709SNoam Camus /** 173*0dd07709SNoam Camus * nps_enet_poll - NAPI poll handler. 174*0dd07709SNoam Camus * @napi: Pointer to napi_struct structure. 175*0dd07709SNoam Camus * @budget: How many frames to process on one call. 176*0dd07709SNoam Camus * 177*0dd07709SNoam Camus * returns: Number of processed frames 178*0dd07709SNoam Camus */ 179*0dd07709SNoam Camus static int nps_enet_poll(struct napi_struct *napi, int budget) 180*0dd07709SNoam Camus { 181*0dd07709SNoam Camus struct net_device *ndev = napi->dev; 182*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 183*0dd07709SNoam Camus struct nps_enet_buf_int_enable buf_int_enable; 184*0dd07709SNoam Camus u32 work_done; 185*0dd07709SNoam Camus 186*0dd07709SNoam Camus buf_int_enable.rx_rdy = NPS_ENET_ENABLE; 187*0dd07709SNoam Camus buf_int_enable.tx_done = NPS_ENET_ENABLE; 188*0dd07709SNoam Camus nps_enet_tx_handler(ndev); 189*0dd07709SNoam Camus work_done = nps_enet_rx_handler(ndev); 190*0dd07709SNoam Camus if (work_done < budget) { 191*0dd07709SNoam Camus napi_complete(napi); 192*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 193*0dd07709SNoam Camus buf_int_enable.value); 194*0dd07709SNoam Camus } 195*0dd07709SNoam Camus 196*0dd07709SNoam Camus return work_done; 197*0dd07709SNoam Camus } 198*0dd07709SNoam Camus 199*0dd07709SNoam Camus /** 200*0dd07709SNoam Camus * nps_enet_irq_handler - Global interrupt handler for ENET. 201*0dd07709SNoam Camus * @irq: irq number. 202*0dd07709SNoam Camus * @dev_instance: device instance. 203*0dd07709SNoam Camus * 204*0dd07709SNoam Camus * returns: IRQ_HANDLED for all cases. 205*0dd07709SNoam Camus * 206*0dd07709SNoam Camus * EZchip ENET has 2 interrupt causes, and depending on bits raised in 207*0dd07709SNoam Camus * CTRL registers we may tell what is a reason for interrupt to fire up. 208*0dd07709SNoam Camus * We got one for RX and the other for TX (completion). 209*0dd07709SNoam Camus */ 210*0dd07709SNoam Camus static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance) 211*0dd07709SNoam Camus { 212*0dd07709SNoam Camus struct net_device *ndev = dev_instance; 213*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 214*0dd07709SNoam Camus struct nps_enet_buf_int_cause buf_int_cause; 215*0dd07709SNoam Camus 216*0dd07709SNoam Camus buf_int_cause.value = 217*0dd07709SNoam Camus nps_enet_reg_get(priv, NPS_ENET_REG_BUF_INT_CAUSE); 218*0dd07709SNoam Camus 219*0dd07709SNoam Camus if (buf_int_cause.tx_done || buf_int_cause.rx_rdy) 220*0dd07709SNoam Camus if (likely(napi_schedule_prep(&priv->napi))) { 221*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 222*0dd07709SNoam Camus __napi_schedule(&priv->napi); 223*0dd07709SNoam Camus } 224*0dd07709SNoam Camus 225*0dd07709SNoam Camus return IRQ_HANDLED; 226*0dd07709SNoam Camus } 227*0dd07709SNoam Camus 228*0dd07709SNoam Camus static void nps_enet_set_hw_mac_address(struct net_device *ndev) 229*0dd07709SNoam Camus { 230*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 231*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_1 ge_mac_cfg_1; 232*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2; 233*0dd07709SNoam Camus 234*0dd07709SNoam Camus /* set MAC address in HW */ 235*0dd07709SNoam Camus ge_mac_cfg_1.octet_0 = ndev->dev_addr[0]; 236*0dd07709SNoam Camus ge_mac_cfg_1.octet_1 = ndev->dev_addr[1]; 237*0dd07709SNoam Camus ge_mac_cfg_1.octet_2 = ndev->dev_addr[2]; 238*0dd07709SNoam Camus ge_mac_cfg_1.octet_3 = ndev->dev_addr[3]; 239*0dd07709SNoam Camus ge_mac_cfg_2->octet_4 = ndev->dev_addr[4]; 240*0dd07709SNoam Camus ge_mac_cfg_2->octet_5 = ndev->dev_addr[5]; 241*0dd07709SNoam Camus 242*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1, 243*0dd07709SNoam Camus ge_mac_cfg_1.value); 244*0dd07709SNoam Camus 245*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 246*0dd07709SNoam Camus ge_mac_cfg_2->value); 247*0dd07709SNoam Camus } 248*0dd07709SNoam Camus 249*0dd07709SNoam Camus /** 250*0dd07709SNoam Camus * nps_enet_hw_reset - Reset the network device. 251*0dd07709SNoam Camus * @ndev: Pointer to the network device. 252*0dd07709SNoam Camus * 253*0dd07709SNoam Camus * This function reset the PCS and TX fifo. 254*0dd07709SNoam Camus * The programming model is to set the relevant reset bits 255*0dd07709SNoam Camus * wait for some time for this to propagate and then unset 256*0dd07709SNoam Camus * the reset bits. This way we ensure that reset procedure 257*0dd07709SNoam Camus * is done successfully by device. 258*0dd07709SNoam Camus */ 259*0dd07709SNoam Camus static void nps_enet_hw_reset(struct net_device *ndev) 260*0dd07709SNoam Camus { 261*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 262*0dd07709SNoam Camus struct nps_enet_ge_rst ge_rst; 263*0dd07709SNoam Camus struct nps_enet_phase_fifo_ctl phase_fifo_ctl; 264*0dd07709SNoam Camus 265*0dd07709SNoam Camus ge_rst.value = 0; 266*0dd07709SNoam Camus phase_fifo_ctl.value = 0; 267*0dd07709SNoam Camus /* Pcs reset sequence*/ 268*0dd07709SNoam Camus ge_rst.gmac_0 = NPS_ENET_ENABLE; 269*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value); 270*0dd07709SNoam Camus usleep_range(10, 20); 271*0dd07709SNoam Camus ge_rst.value = 0; 272*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value); 273*0dd07709SNoam Camus 274*0dd07709SNoam Camus /* Tx fifo reset sequence */ 275*0dd07709SNoam Camus phase_fifo_ctl.rst = NPS_ENET_ENABLE; 276*0dd07709SNoam Camus phase_fifo_ctl.init = NPS_ENET_ENABLE; 277*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 278*0dd07709SNoam Camus phase_fifo_ctl.value); 279*0dd07709SNoam Camus usleep_range(10, 20); 280*0dd07709SNoam Camus phase_fifo_ctl.value = 0; 281*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 282*0dd07709SNoam Camus phase_fifo_ctl.value); 283*0dd07709SNoam Camus } 284*0dd07709SNoam Camus 285*0dd07709SNoam Camus static void nps_enet_hw_enable_control(struct net_device *ndev) 286*0dd07709SNoam Camus { 287*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 288*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_0 ge_mac_cfg_0; 289*0dd07709SNoam Camus struct nps_enet_buf_int_enable buf_int_enable; 290*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2; 291*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_3 *ge_mac_cfg_3 = &priv->ge_mac_cfg_3; 292*0dd07709SNoam Camus s32 max_frame_length; 293*0dd07709SNoam Camus 294*0dd07709SNoam Camus ge_mac_cfg_0.value = 0; 295*0dd07709SNoam Camus buf_int_enable.value = 0; 296*0dd07709SNoam Camus /* Enable Rx and Tx statistics */ 297*0dd07709SNoam Camus ge_mac_cfg_2->stat_en = NPS_ENET_GE_MAC_CFG_2_STAT_EN; 298*0dd07709SNoam Camus 299*0dd07709SNoam Camus /* Discard packets with different MAC address */ 300*0dd07709SNoam Camus ge_mac_cfg_2->disc_da = NPS_ENET_ENABLE; 301*0dd07709SNoam Camus 302*0dd07709SNoam Camus /* Discard multicast packets */ 303*0dd07709SNoam Camus ge_mac_cfg_2->disc_mc = NPS_ENET_ENABLE; 304*0dd07709SNoam Camus 305*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 306*0dd07709SNoam Camus ge_mac_cfg_2->value); 307*0dd07709SNoam Camus 308*0dd07709SNoam Camus /* Discard Packets bigger than max frame length */ 309*0dd07709SNoam Camus max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN; 310*0dd07709SNoam Camus if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) { 311*0dd07709SNoam Camus ge_mac_cfg_3->max_len = max_frame_length; 312*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, 313*0dd07709SNoam Camus ge_mac_cfg_3->value); 314*0dd07709SNoam Camus } 315*0dd07709SNoam Camus 316*0dd07709SNoam Camus /* Enable interrupts */ 317*0dd07709SNoam Camus buf_int_enable.rx_rdy = NPS_ENET_ENABLE; 318*0dd07709SNoam Camus buf_int_enable.tx_done = NPS_ENET_ENABLE; 319*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 320*0dd07709SNoam Camus buf_int_enable.value); 321*0dd07709SNoam Camus 322*0dd07709SNoam Camus /* Write device MAC address to HW */ 323*0dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 324*0dd07709SNoam Camus 325*0dd07709SNoam Camus /* Rx and Tx HW features */ 326*0dd07709SNoam Camus ge_mac_cfg_0.tx_pad_en = NPS_ENET_ENABLE; 327*0dd07709SNoam Camus ge_mac_cfg_0.tx_crc_en = NPS_ENET_ENABLE; 328*0dd07709SNoam Camus ge_mac_cfg_0.rx_crc_strip = NPS_ENET_ENABLE; 329*0dd07709SNoam Camus 330*0dd07709SNoam Camus /* IFG configuration */ 331*0dd07709SNoam Camus ge_mac_cfg_0.rx_ifg = NPS_ENET_GE_MAC_CFG_0_RX_IFG; 332*0dd07709SNoam Camus ge_mac_cfg_0.tx_ifg = NPS_ENET_GE_MAC_CFG_0_TX_IFG; 333*0dd07709SNoam Camus 334*0dd07709SNoam Camus /* preamble configuration */ 335*0dd07709SNoam Camus ge_mac_cfg_0.rx_pr_check_en = NPS_ENET_ENABLE; 336*0dd07709SNoam Camus ge_mac_cfg_0.tx_pr_len = NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN; 337*0dd07709SNoam Camus 338*0dd07709SNoam Camus /* enable flow control frames */ 339*0dd07709SNoam Camus ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE; 340*0dd07709SNoam Camus ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE; 341*0dd07709SNoam Camus ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR; 342*0dd07709SNoam Camus 343*0dd07709SNoam Camus /* Enable Rx and Tx */ 344*0dd07709SNoam Camus ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE; 345*0dd07709SNoam Camus ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE; 346*0dd07709SNoam Camus 347*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 348*0dd07709SNoam Camus ge_mac_cfg_0.value); 349*0dd07709SNoam Camus } 350*0dd07709SNoam Camus 351*0dd07709SNoam Camus static void nps_enet_hw_disable_control(struct net_device *ndev) 352*0dd07709SNoam Camus { 353*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 354*0dd07709SNoam Camus 355*0dd07709SNoam Camus /* Disable interrupts */ 356*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 357*0dd07709SNoam Camus 358*0dd07709SNoam Camus /* Disable Rx and Tx */ 359*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 0); 360*0dd07709SNoam Camus } 361*0dd07709SNoam Camus 362*0dd07709SNoam Camus static void nps_enet_send_frame(struct net_device *ndev, 363*0dd07709SNoam Camus struct sk_buff *skb) 364*0dd07709SNoam Camus { 365*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 366*0dd07709SNoam Camus struct nps_enet_tx_ctl tx_ctrl; 367*0dd07709SNoam Camus short length = skb->len; 368*0dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(length, sizeof(u32)); 369*0dd07709SNoam Camus u32 *src = (u32 *)virt_to_phys(skb->data); 370*0dd07709SNoam Camus bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32)); 371*0dd07709SNoam Camus 372*0dd07709SNoam Camus tx_ctrl.value = 0; 373*0dd07709SNoam Camus /* In case src is not aligned we need an intermediate buffer */ 374*0dd07709SNoam Camus if (src_is_aligned) 375*0dd07709SNoam Camus for (i = 0; i < len; i++, src++) 376*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src); 377*0dd07709SNoam Camus else { /* !src_is_aligned */ 378*0dd07709SNoam Camus for (i = 0; i < len; i++, src++) { 379*0dd07709SNoam Camus u32 buf; 380*0dd07709SNoam Camus 381*0dd07709SNoam Camus /* to accommodate word-unaligned address of "src" 382*0dd07709SNoam Camus * we have to do memcpy_fromio() instead of simple "=" 383*0dd07709SNoam Camus */ 384*0dd07709SNoam Camus memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf)); 385*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf); 386*0dd07709SNoam Camus } 387*0dd07709SNoam Camus } 388*0dd07709SNoam Camus /* Write the length of the Frame */ 389*0dd07709SNoam Camus tx_ctrl.nt = length; 390*0dd07709SNoam Camus 391*0dd07709SNoam Camus /* Indicate SW is done */ 392*0dd07709SNoam Camus priv->tx_packet_sent = true; 393*0dd07709SNoam Camus tx_ctrl.ct = NPS_ENET_ENABLE; 394*0dd07709SNoam Camus 395*0dd07709SNoam Camus /* Send Frame */ 396*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl.value); 397*0dd07709SNoam Camus } 398*0dd07709SNoam Camus 399*0dd07709SNoam Camus /** 400*0dd07709SNoam Camus * nps_enet_set_mac_address - Set the MAC address for this device. 401*0dd07709SNoam Camus * @ndev: Pointer to net_device structure. 402*0dd07709SNoam Camus * @p: 6 byte Address to be written as MAC address. 403*0dd07709SNoam Camus * 404*0dd07709SNoam Camus * This function copies the HW address from the sockaddr structure to the 405*0dd07709SNoam Camus * net_device structure and updates the address in HW. 406*0dd07709SNoam Camus * 407*0dd07709SNoam Camus * returns: -EBUSY if the net device is busy or 0 if the address is set 408*0dd07709SNoam Camus * successfully. 409*0dd07709SNoam Camus */ 410*0dd07709SNoam Camus static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p) 411*0dd07709SNoam Camus { 412*0dd07709SNoam Camus struct sockaddr *addr = p; 413*0dd07709SNoam Camus s32 res; 414*0dd07709SNoam Camus 415*0dd07709SNoam Camus if (netif_running(ndev)) 416*0dd07709SNoam Camus return -EBUSY; 417*0dd07709SNoam Camus 418*0dd07709SNoam Camus res = eth_mac_addr(ndev, p); 419*0dd07709SNoam Camus if (!res) { 420*0dd07709SNoam Camus ether_addr_copy(ndev->dev_addr, addr->sa_data); 421*0dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 422*0dd07709SNoam Camus } 423*0dd07709SNoam Camus 424*0dd07709SNoam Camus return res; 425*0dd07709SNoam Camus } 426*0dd07709SNoam Camus 427*0dd07709SNoam Camus /** 428*0dd07709SNoam Camus * nps_enet_set_rx_mode - Change the receive filtering mode. 429*0dd07709SNoam Camus * @ndev: Pointer to the network device. 430*0dd07709SNoam Camus * 431*0dd07709SNoam Camus * This function enables/disables promiscuous mode 432*0dd07709SNoam Camus */ 433*0dd07709SNoam Camus static void nps_enet_set_rx_mode(struct net_device *ndev) 434*0dd07709SNoam Camus { 435*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 436*0dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2; 437*0dd07709SNoam Camus 438*0dd07709SNoam Camus ge_mac_cfg_2.value = priv->ge_mac_cfg_2.value; 439*0dd07709SNoam Camus 440*0dd07709SNoam Camus if (ndev->flags & IFF_PROMISC) { 441*0dd07709SNoam Camus ge_mac_cfg_2.disc_da = NPS_ENET_DISABLE; 442*0dd07709SNoam Camus ge_mac_cfg_2.disc_mc = NPS_ENET_DISABLE; 443*0dd07709SNoam Camus } else { 444*0dd07709SNoam Camus ge_mac_cfg_2.disc_da = NPS_ENET_ENABLE; 445*0dd07709SNoam Camus ge_mac_cfg_2.disc_mc = NPS_ENET_ENABLE; 446*0dd07709SNoam Camus } 447*0dd07709SNoam Camus 448*0dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2.value); 449*0dd07709SNoam Camus } 450*0dd07709SNoam Camus 451*0dd07709SNoam Camus /** 452*0dd07709SNoam Camus * nps_enet_open - Open the network device. 453*0dd07709SNoam Camus * @ndev: Pointer to the network device. 454*0dd07709SNoam Camus * 455*0dd07709SNoam Camus * returns: 0, on success or non-zero error value on failure. 456*0dd07709SNoam Camus * 457*0dd07709SNoam Camus * This function sets the MAC address, requests and enables an IRQ 458*0dd07709SNoam Camus * for the ENET device and starts the Tx queue. 459*0dd07709SNoam Camus */ 460*0dd07709SNoam Camus static s32 nps_enet_open(struct net_device *ndev) 461*0dd07709SNoam Camus { 462*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 463*0dd07709SNoam Camus s32 err; 464*0dd07709SNoam Camus 465*0dd07709SNoam Camus /* Reset private variables */ 466*0dd07709SNoam Camus priv->tx_packet_sent = false; 467*0dd07709SNoam Camus priv->ge_mac_cfg_2.value = 0; 468*0dd07709SNoam Camus priv->ge_mac_cfg_3.value = 0; 469*0dd07709SNoam Camus 470*0dd07709SNoam Camus /* ge_mac_cfg_3 default values */ 471*0dd07709SNoam Camus priv->ge_mac_cfg_3.rx_ifg_th = NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH; 472*0dd07709SNoam Camus priv->ge_mac_cfg_3.max_len = NPS_ENET_GE_MAC_CFG_3_MAX_LEN; 473*0dd07709SNoam Camus 474*0dd07709SNoam Camus /* Disable HW device */ 475*0dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 476*0dd07709SNoam Camus 477*0dd07709SNoam Camus /* irq Rx allocation */ 478*0dd07709SNoam Camus err = request_irq(priv->irq, nps_enet_irq_handler, 479*0dd07709SNoam Camus 0, "enet-rx-tx", ndev); 480*0dd07709SNoam Camus if (err) 481*0dd07709SNoam Camus return err; 482*0dd07709SNoam Camus 483*0dd07709SNoam Camus napi_enable(&priv->napi); 484*0dd07709SNoam Camus 485*0dd07709SNoam Camus /* Enable HW device */ 486*0dd07709SNoam Camus nps_enet_hw_reset(ndev); 487*0dd07709SNoam Camus nps_enet_hw_enable_control(ndev); 488*0dd07709SNoam Camus 489*0dd07709SNoam Camus netif_start_queue(ndev); 490*0dd07709SNoam Camus 491*0dd07709SNoam Camus return 0; 492*0dd07709SNoam Camus } 493*0dd07709SNoam Camus 494*0dd07709SNoam Camus /** 495*0dd07709SNoam Camus * nps_enet_stop - Close the network device. 496*0dd07709SNoam Camus * @ndev: Pointer to the network device. 497*0dd07709SNoam Camus * 498*0dd07709SNoam Camus * This function stops the Tx queue, disables interrupts for the ENET device. 499*0dd07709SNoam Camus */ 500*0dd07709SNoam Camus static s32 nps_enet_stop(struct net_device *ndev) 501*0dd07709SNoam Camus { 502*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 503*0dd07709SNoam Camus 504*0dd07709SNoam Camus napi_disable(&priv->napi); 505*0dd07709SNoam Camus netif_stop_queue(ndev); 506*0dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 507*0dd07709SNoam Camus free_irq(priv->irq, ndev); 508*0dd07709SNoam Camus 509*0dd07709SNoam Camus return 0; 510*0dd07709SNoam Camus } 511*0dd07709SNoam Camus 512*0dd07709SNoam Camus /** 513*0dd07709SNoam Camus * nps_enet_start_xmit - Starts the data transmission. 514*0dd07709SNoam Camus * @skb: sk_buff pointer that contains data to be Transmitted. 515*0dd07709SNoam Camus * @ndev: Pointer to net_device structure. 516*0dd07709SNoam Camus * 517*0dd07709SNoam Camus * returns: NETDEV_TX_OK, on success 518*0dd07709SNoam Camus * NETDEV_TX_BUSY, if any of the descriptors are not free. 519*0dd07709SNoam Camus * 520*0dd07709SNoam Camus * This function is invoked from upper layers to initiate transmission. 521*0dd07709SNoam Camus */ 522*0dd07709SNoam Camus static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb, 523*0dd07709SNoam Camus struct net_device *ndev) 524*0dd07709SNoam Camus { 525*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 526*0dd07709SNoam Camus 527*0dd07709SNoam Camus /* This driver handles one frame at a time */ 528*0dd07709SNoam Camus netif_stop_queue(ndev); 529*0dd07709SNoam Camus 530*0dd07709SNoam Camus nps_enet_send_frame(ndev, skb); 531*0dd07709SNoam Camus 532*0dd07709SNoam Camus priv->tx_skb = skb; 533*0dd07709SNoam Camus 534*0dd07709SNoam Camus return NETDEV_TX_OK; 535*0dd07709SNoam Camus } 536*0dd07709SNoam Camus 537*0dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 538*0dd07709SNoam Camus static void nps_enet_poll_controller(struct net_device *ndev) 539*0dd07709SNoam Camus { 540*0dd07709SNoam Camus disable_irq(ndev->irq); 541*0dd07709SNoam Camus nps_enet_irq_handler(ndev->irq, ndev); 542*0dd07709SNoam Camus enable_irq(ndev->irq); 543*0dd07709SNoam Camus } 544*0dd07709SNoam Camus #endif 545*0dd07709SNoam Camus 546*0dd07709SNoam Camus static const struct net_device_ops nps_netdev_ops = { 547*0dd07709SNoam Camus .ndo_open = nps_enet_open, 548*0dd07709SNoam Camus .ndo_stop = nps_enet_stop, 549*0dd07709SNoam Camus .ndo_start_xmit = nps_enet_start_xmit, 550*0dd07709SNoam Camus .ndo_set_mac_address = nps_enet_set_mac_address, 551*0dd07709SNoam Camus .ndo_set_rx_mode = nps_enet_set_rx_mode, 552*0dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 553*0dd07709SNoam Camus .ndo_poll_controller = nps_enet_poll_controller, 554*0dd07709SNoam Camus #endif 555*0dd07709SNoam Camus }; 556*0dd07709SNoam Camus 557*0dd07709SNoam Camus static s32 nps_enet_probe(struct platform_device *pdev) 558*0dd07709SNoam Camus { 559*0dd07709SNoam Camus struct device *dev = &pdev->dev; 560*0dd07709SNoam Camus struct net_device *ndev; 561*0dd07709SNoam Camus struct nps_enet_priv *priv; 562*0dd07709SNoam Camus s32 err = 0; 563*0dd07709SNoam Camus const char *mac_addr; 564*0dd07709SNoam Camus struct resource *res_regs; 565*0dd07709SNoam Camus 566*0dd07709SNoam Camus if (!dev->of_node) 567*0dd07709SNoam Camus return -ENODEV; 568*0dd07709SNoam Camus 569*0dd07709SNoam Camus ndev = alloc_etherdev(sizeof(struct nps_enet_priv)); 570*0dd07709SNoam Camus if (!ndev) 571*0dd07709SNoam Camus return -ENOMEM; 572*0dd07709SNoam Camus 573*0dd07709SNoam Camus platform_set_drvdata(pdev, ndev); 574*0dd07709SNoam Camus SET_NETDEV_DEV(ndev, dev); 575*0dd07709SNoam Camus priv = netdev_priv(ndev); 576*0dd07709SNoam Camus 577*0dd07709SNoam Camus /* The EZ NET specific entries in the device structure. */ 578*0dd07709SNoam Camus ndev->netdev_ops = &nps_netdev_ops; 579*0dd07709SNoam Camus ndev->watchdog_timeo = (400 * HZ / 1000); 580*0dd07709SNoam Camus /* FIXME :: no multicast support yet */ 581*0dd07709SNoam Camus ndev->flags &= ~IFF_MULTICAST; 582*0dd07709SNoam Camus 583*0dd07709SNoam Camus res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 584*0dd07709SNoam Camus priv->regs_base = devm_ioremap_resource(dev, res_regs); 585*0dd07709SNoam Camus if (IS_ERR(priv->regs_base)) { 586*0dd07709SNoam Camus err = PTR_ERR(priv->regs_base); 587*0dd07709SNoam Camus goto out_netdev; 588*0dd07709SNoam Camus } 589*0dd07709SNoam Camus dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base); 590*0dd07709SNoam Camus 591*0dd07709SNoam Camus /* set kernel MAC address to dev */ 592*0dd07709SNoam Camus mac_addr = of_get_mac_address(dev->of_node); 593*0dd07709SNoam Camus if (mac_addr) 594*0dd07709SNoam Camus ether_addr_copy(ndev->dev_addr, mac_addr); 595*0dd07709SNoam Camus else 596*0dd07709SNoam Camus eth_hw_addr_random(ndev); 597*0dd07709SNoam Camus 598*0dd07709SNoam Camus /* Get IRQ number */ 599*0dd07709SNoam Camus priv->irq = platform_get_irq(pdev, 0); 600*0dd07709SNoam Camus if (!priv->irq) { 601*0dd07709SNoam Camus dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n"); 602*0dd07709SNoam Camus err = -ENODEV; 603*0dd07709SNoam Camus goto out_netdev; 604*0dd07709SNoam Camus } 605*0dd07709SNoam Camus 606*0dd07709SNoam Camus netif_napi_add(ndev, &priv->napi, nps_enet_poll, 607*0dd07709SNoam Camus NPS_ENET_NAPI_POLL_WEIGHT); 608*0dd07709SNoam Camus 609*0dd07709SNoam Camus /* Register the driver. Should be the last thing in probe */ 610*0dd07709SNoam Camus err = register_netdev(ndev); 611*0dd07709SNoam Camus if (err) { 612*0dd07709SNoam Camus dev_err(dev, "Failed to register ndev for %s, err = 0x%08x\n", 613*0dd07709SNoam Camus ndev->name, (s32)err); 614*0dd07709SNoam Camus goto out_netif_api; 615*0dd07709SNoam Camus } 616*0dd07709SNoam Camus 617*0dd07709SNoam Camus dev_info(dev, "(rx/tx=%d)\n", priv->irq); 618*0dd07709SNoam Camus return 0; 619*0dd07709SNoam Camus 620*0dd07709SNoam Camus out_netif_api: 621*0dd07709SNoam Camus netif_napi_del(&priv->napi); 622*0dd07709SNoam Camus out_netdev: 623*0dd07709SNoam Camus if (err) 624*0dd07709SNoam Camus free_netdev(ndev); 625*0dd07709SNoam Camus 626*0dd07709SNoam Camus return err; 627*0dd07709SNoam Camus } 628*0dd07709SNoam Camus 629*0dd07709SNoam Camus static s32 nps_enet_remove(struct platform_device *pdev) 630*0dd07709SNoam Camus { 631*0dd07709SNoam Camus struct net_device *ndev = platform_get_drvdata(pdev); 632*0dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 633*0dd07709SNoam Camus 634*0dd07709SNoam Camus unregister_netdev(ndev); 635*0dd07709SNoam Camus free_netdev(ndev); 636*0dd07709SNoam Camus netif_napi_del(&priv->napi); 637*0dd07709SNoam Camus 638*0dd07709SNoam Camus return 0; 639*0dd07709SNoam Camus } 640*0dd07709SNoam Camus 641*0dd07709SNoam Camus static const struct of_device_id nps_enet_dt_ids[] = { 642*0dd07709SNoam Camus { .compatible = "ezchip,nps-mgt-enet" }, 643*0dd07709SNoam Camus { /* Sentinel */ } 644*0dd07709SNoam Camus }; 645*0dd07709SNoam Camus 646*0dd07709SNoam Camus static struct platform_driver nps_enet_driver = { 647*0dd07709SNoam Camus .probe = nps_enet_probe, 648*0dd07709SNoam Camus .remove = nps_enet_remove, 649*0dd07709SNoam Camus .driver = { 650*0dd07709SNoam Camus .name = DRV_NAME, 651*0dd07709SNoam Camus .of_match_table = nps_enet_dt_ids, 652*0dd07709SNoam Camus }, 653*0dd07709SNoam Camus }; 654*0dd07709SNoam Camus 655*0dd07709SNoam Camus module_platform_driver(nps_enet_driver); 656*0dd07709SNoam Camus 657*0dd07709SNoam Camus MODULE_AUTHOR("EZchip Semiconductor"); 658*0dd07709SNoam Camus MODULE_LICENSE("GPL v2"); 659