10dd07709SNoam Camus /* 20dd07709SNoam Camus * Copyright(c) 2015 EZchip Technologies. 30dd07709SNoam Camus * 40dd07709SNoam Camus * This program is free software; you can redistribute it and/or modify it 50dd07709SNoam Camus * under the terms and conditions of the GNU General Public License, 60dd07709SNoam Camus * version 2, as published by the Free Software Foundation. 70dd07709SNoam Camus * 80dd07709SNoam Camus * This program is distributed in the hope it will be useful, but WITHOUT 90dd07709SNoam Camus * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 100dd07709SNoam Camus * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 110dd07709SNoam Camus * more details. 120dd07709SNoam Camus * 130dd07709SNoam Camus * The full GNU General Public License is included in this distribution in 140dd07709SNoam Camus * the file called "COPYING". 150dd07709SNoam Camus */ 160dd07709SNoam Camus 170dd07709SNoam Camus #include <linux/module.h> 180dd07709SNoam Camus #include <linux/etherdevice.h> 190dd07709SNoam Camus #include <linux/of_address.h> 200dd07709SNoam Camus #include <linux/of_irq.h> 210dd07709SNoam Camus #include <linux/of_net.h> 220dd07709SNoam Camus #include <linux/of_platform.h> 230dd07709SNoam Camus #include "nps_enet.h" 240dd07709SNoam Camus 250dd07709SNoam Camus #define DRV_NAME "nps_mgt_enet" 260dd07709SNoam Camus 270dd07709SNoam Camus static void nps_enet_clean_rx_fifo(struct net_device *ndev, u32 frame_len) 280dd07709SNoam Camus { 290dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 300dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(frame_len, sizeof(u32)); 310dd07709SNoam Camus 320dd07709SNoam Camus /* Empty Rx FIFO buffer by reading all words */ 330dd07709SNoam Camus for (i = 0; i < len; i++) 340dd07709SNoam Camus nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 350dd07709SNoam Camus } 360dd07709SNoam Camus 370dd07709SNoam Camus static void nps_enet_read_rx_fifo(struct net_device *ndev, 380dd07709SNoam Camus unsigned char *dst, u32 length) 390dd07709SNoam Camus { 400dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 410dd07709SNoam Camus s32 i, last = length & (sizeof(u32) - 1); 420dd07709SNoam Camus u32 *reg = (u32 *)dst, len = length / sizeof(u32); 430dd07709SNoam Camus bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32)); 440dd07709SNoam Camus 450dd07709SNoam Camus /* In case dst is not aligned we need an intermediate buffer */ 460dd07709SNoam Camus if (dst_is_aligned) 470dd07709SNoam Camus for (i = 0; i < len; i++, reg++) 480dd07709SNoam Camus *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 490dd07709SNoam Camus else { /* !dst_is_aligned */ 500dd07709SNoam Camus for (i = 0; i < len; i++, reg++) { 51*b0a8d1a0SArnd Bergmann u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 52*b0a8d1a0SArnd Bergmann put_unaligned(buf, reg); 530dd07709SNoam Camus } 540dd07709SNoam Camus } 550dd07709SNoam Camus 560dd07709SNoam Camus /* copy last bytes (if any) */ 570dd07709SNoam Camus if (last) { 580dd07709SNoam Camus u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF); 59*b0a8d1a0SArnd Bergmann memcpy((u8*)reg, &buf, last); 600dd07709SNoam Camus } 610dd07709SNoam Camus } 620dd07709SNoam Camus 630dd07709SNoam Camus static u32 nps_enet_rx_handler(struct net_device *ndev) 640dd07709SNoam Camus { 650dd07709SNoam Camus u32 frame_len, err = 0; 660dd07709SNoam Camus u32 work_done = 0; 670dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 680dd07709SNoam Camus struct sk_buff *skb; 690dd07709SNoam Camus struct nps_enet_rx_ctl rx_ctrl; 700dd07709SNoam Camus 710dd07709SNoam Camus rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); 720dd07709SNoam Camus frame_len = rx_ctrl.nr; 730dd07709SNoam Camus 740dd07709SNoam Camus /* Check if we got RX */ 750dd07709SNoam Camus if (!rx_ctrl.cr) 760dd07709SNoam Camus return work_done; 770dd07709SNoam Camus 780dd07709SNoam Camus /* If we got here there is a work for us */ 790dd07709SNoam Camus work_done++; 800dd07709SNoam Camus 810dd07709SNoam Camus /* Check Rx error */ 820dd07709SNoam Camus if (rx_ctrl.er) { 830dd07709SNoam Camus ndev->stats.rx_errors++; 840dd07709SNoam Camus err = 1; 850dd07709SNoam Camus } 860dd07709SNoam Camus 870dd07709SNoam Camus /* Check Rx CRC error */ 880dd07709SNoam Camus if (rx_ctrl.crc) { 890dd07709SNoam Camus ndev->stats.rx_crc_errors++; 900dd07709SNoam Camus ndev->stats.rx_dropped++; 910dd07709SNoam Camus err = 1; 920dd07709SNoam Camus } 930dd07709SNoam Camus 940dd07709SNoam Camus /* Check Frame length Min 64b */ 950dd07709SNoam Camus if (unlikely(frame_len < ETH_ZLEN)) { 960dd07709SNoam Camus ndev->stats.rx_length_errors++; 970dd07709SNoam Camus ndev->stats.rx_dropped++; 980dd07709SNoam Camus err = 1; 990dd07709SNoam Camus } 1000dd07709SNoam Camus 1010dd07709SNoam Camus if (err) 1020dd07709SNoam Camus goto rx_irq_clean; 1030dd07709SNoam Camus 1040dd07709SNoam Camus /* Skb allocation */ 1050dd07709SNoam Camus skb = netdev_alloc_skb_ip_align(ndev, frame_len); 1060dd07709SNoam Camus if (unlikely(!skb)) { 1070dd07709SNoam Camus ndev->stats.rx_errors++; 1080dd07709SNoam Camus ndev->stats.rx_dropped++; 1090dd07709SNoam Camus goto rx_irq_clean; 1100dd07709SNoam Camus } 1110dd07709SNoam Camus 1120dd07709SNoam Camus /* Copy frame from Rx fifo into the skb */ 1130dd07709SNoam Camus nps_enet_read_rx_fifo(ndev, skb->data, frame_len); 1140dd07709SNoam Camus 1150dd07709SNoam Camus skb_put(skb, frame_len); 1160dd07709SNoam Camus skb->protocol = eth_type_trans(skb, ndev); 1170dd07709SNoam Camus skb->ip_summed = CHECKSUM_UNNECESSARY; 1180dd07709SNoam Camus 1190dd07709SNoam Camus ndev->stats.rx_packets++; 1200dd07709SNoam Camus ndev->stats.rx_bytes += frame_len; 1210dd07709SNoam Camus netif_receive_skb(skb); 1220dd07709SNoam Camus 1230dd07709SNoam Camus goto rx_irq_frame_done; 1240dd07709SNoam Camus 1250dd07709SNoam Camus rx_irq_clean: 1260dd07709SNoam Camus /* Clean Rx fifo */ 1270dd07709SNoam Camus nps_enet_clean_rx_fifo(ndev, frame_len); 1280dd07709SNoam Camus 1290dd07709SNoam Camus rx_irq_frame_done: 1300dd07709SNoam Camus /* Ack Rx ctrl register */ 1310dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_RX_CTL, 0); 1320dd07709SNoam Camus 1330dd07709SNoam Camus return work_done; 1340dd07709SNoam Camus } 1350dd07709SNoam Camus 1360dd07709SNoam Camus static void nps_enet_tx_handler(struct net_device *ndev) 1370dd07709SNoam Camus { 1380dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 1390dd07709SNoam Camus struct nps_enet_tx_ctl tx_ctrl; 1400dd07709SNoam Camus 1410dd07709SNoam Camus tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); 1420dd07709SNoam Camus 1430dd07709SNoam Camus /* Check if we got TX */ 1440dd07709SNoam Camus if (!priv->tx_packet_sent || tx_ctrl.ct) 1450dd07709SNoam Camus return; 1460dd07709SNoam Camus 1473d99b74aSNoam Camus /* Ack Tx ctrl register */ 1483d99b74aSNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, 0); 1493d99b74aSNoam Camus 1500dd07709SNoam Camus /* Check Tx transmit error */ 1510dd07709SNoam Camus if (unlikely(tx_ctrl.et)) { 1520dd07709SNoam Camus ndev->stats.tx_errors++; 1530dd07709SNoam Camus } else { 1540dd07709SNoam Camus ndev->stats.tx_packets++; 1550dd07709SNoam Camus ndev->stats.tx_bytes += tx_ctrl.nt; 1560dd07709SNoam Camus } 1570dd07709SNoam Camus 1580dd07709SNoam Camus dev_kfree_skb(priv->tx_skb); 1590dd07709SNoam Camus priv->tx_packet_sent = false; 1600dd07709SNoam Camus 1610dd07709SNoam Camus if (netif_queue_stopped(ndev)) 1620dd07709SNoam Camus netif_wake_queue(ndev); 1630dd07709SNoam Camus } 1640dd07709SNoam Camus 1650dd07709SNoam Camus /** 1660dd07709SNoam Camus * nps_enet_poll - NAPI poll handler. 1670dd07709SNoam Camus * @napi: Pointer to napi_struct structure. 1680dd07709SNoam Camus * @budget: How many frames to process on one call. 1690dd07709SNoam Camus * 1700dd07709SNoam Camus * returns: Number of processed frames 1710dd07709SNoam Camus */ 1720dd07709SNoam Camus static int nps_enet_poll(struct napi_struct *napi, int budget) 1730dd07709SNoam Camus { 1740dd07709SNoam Camus struct net_device *ndev = napi->dev; 1750dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 1760dd07709SNoam Camus u32 work_done; 1770dd07709SNoam Camus 1780dd07709SNoam Camus nps_enet_tx_handler(ndev); 1790dd07709SNoam Camus work_done = nps_enet_rx_handler(ndev); 1800dd07709SNoam Camus if (work_done < budget) { 18141493795SNoam Camus struct nps_enet_buf_int_enable buf_int_enable; 18241493795SNoam Camus 1830dd07709SNoam Camus napi_complete(napi); 18441493795SNoam Camus buf_int_enable.rx_rdy = NPS_ENET_ENABLE; 18541493795SNoam Camus buf_int_enable.tx_done = NPS_ENET_ENABLE; 1860dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 1870dd07709SNoam Camus buf_int_enable.value); 1880dd07709SNoam Camus } 1890dd07709SNoam Camus 1900dd07709SNoam Camus return work_done; 1910dd07709SNoam Camus } 1920dd07709SNoam Camus 1930dd07709SNoam Camus /** 1940dd07709SNoam Camus * nps_enet_irq_handler - Global interrupt handler for ENET. 1950dd07709SNoam Camus * @irq: irq number. 1960dd07709SNoam Camus * @dev_instance: device instance. 1970dd07709SNoam Camus * 1980dd07709SNoam Camus * returns: IRQ_HANDLED for all cases. 1990dd07709SNoam Camus * 2000dd07709SNoam Camus * EZchip ENET has 2 interrupt causes, and depending on bits raised in 2010dd07709SNoam Camus * CTRL registers we may tell what is a reason for interrupt to fire up. 2020dd07709SNoam Camus * We got one for RX and the other for TX (completion). 2030dd07709SNoam Camus */ 2040dd07709SNoam Camus static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance) 2050dd07709SNoam Camus { 2060dd07709SNoam Camus struct net_device *ndev = dev_instance; 2070dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 2080dd20f3cSNoam Camus struct nps_enet_rx_ctl rx_ctrl; 2090dd20f3cSNoam Camus struct nps_enet_tx_ctl tx_ctrl; 2100dd07709SNoam Camus 2110dd20f3cSNoam Camus rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); 2120dd20f3cSNoam Camus tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); 2130dd07709SNoam Camus 2140dd20f3cSNoam Camus if ((!tx_ctrl.ct && priv->tx_packet_sent) || rx_ctrl.cr) 2150dd07709SNoam Camus if (likely(napi_schedule_prep(&priv->napi))) { 2160dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 2170dd07709SNoam Camus __napi_schedule(&priv->napi); 2180dd07709SNoam Camus } 2190dd07709SNoam Camus 2200dd07709SNoam Camus return IRQ_HANDLED; 2210dd07709SNoam Camus } 2220dd07709SNoam Camus 2230dd07709SNoam Camus static void nps_enet_set_hw_mac_address(struct net_device *ndev) 2240dd07709SNoam Camus { 2250dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 2260dd07709SNoam Camus struct nps_enet_ge_mac_cfg_1 ge_mac_cfg_1; 2270dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2; 2280dd07709SNoam Camus 2290dd07709SNoam Camus /* set MAC address in HW */ 2300dd07709SNoam Camus ge_mac_cfg_1.octet_0 = ndev->dev_addr[0]; 2310dd07709SNoam Camus ge_mac_cfg_1.octet_1 = ndev->dev_addr[1]; 2320dd07709SNoam Camus ge_mac_cfg_1.octet_2 = ndev->dev_addr[2]; 2330dd07709SNoam Camus ge_mac_cfg_1.octet_3 = ndev->dev_addr[3]; 2340dd07709SNoam Camus ge_mac_cfg_2->octet_4 = ndev->dev_addr[4]; 2350dd07709SNoam Camus ge_mac_cfg_2->octet_5 = ndev->dev_addr[5]; 2360dd07709SNoam Camus 2370dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1, 2380dd07709SNoam Camus ge_mac_cfg_1.value); 2390dd07709SNoam Camus 2400dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 2410dd07709SNoam Camus ge_mac_cfg_2->value); 2420dd07709SNoam Camus } 2430dd07709SNoam Camus 2440dd07709SNoam Camus /** 2450dd07709SNoam Camus * nps_enet_hw_reset - Reset the network device. 2460dd07709SNoam Camus * @ndev: Pointer to the network device. 2470dd07709SNoam Camus * 2480dd07709SNoam Camus * This function reset the PCS and TX fifo. 2490dd07709SNoam Camus * The programming model is to set the relevant reset bits 2500dd07709SNoam Camus * wait for some time for this to propagate and then unset 2510dd07709SNoam Camus * the reset bits. This way we ensure that reset procedure 2520dd07709SNoam Camus * is done successfully by device. 2530dd07709SNoam Camus */ 2540dd07709SNoam Camus static void nps_enet_hw_reset(struct net_device *ndev) 2550dd07709SNoam Camus { 2560dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 2570dd07709SNoam Camus struct nps_enet_ge_rst ge_rst; 2580dd07709SNoam Camus struct nps_enet_phase_fifo_ctl phase_fifo_ctl; 2590dd07709SNoam Camus 2600dd07709SNoam Camus ge_rst.value = 0; 2610dd07709SNoam Camus phase_fifo_ctl.value = 0; 2620dd07709SNoam Camus /* Pcs reset sequence*/ 2630dd07709SNoam Camus ge_rst.gmac_0 = NPS_ENET_ENABLE; 2640dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value); 2650dd07709SNoam Camus usleep_range(10, 20); 2660dd07709SNoam Camus ge_rst.value = 0; 2670dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value); 2680dd07709SNoam Camus 2690dd07709SNoam Camus /* Tx fifo reset sequence */ 2700dd07709SNoam Camus phase_fifo_ctl.rst = NPS_ENET_ENABLE; 2710dd07709SNoam Camus phase_fifo_ctl.init = NPS_ENET_ENABLE; 2720dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 2730dd07709SNoam Camus phase_fifo_ctl.value); 2740dd07709SNoam Camus usleep_range(10, 20); 2750dd07709SNoam Camus phase_fifo_ctl.value = 0; 2760dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL, 2770dd07709SNoam Camus phase_fifo_ctl.value); 2780dd07709SNoam Camus } 2790dd07709SNoam Camus 2800dd07709SNoam Camus static void nps_enet_hw_enable_control(struct net_device *ndev) 2810dd07709SNoam Camus { 2820dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 2830dd07709SNoam Camus struct nps_enet_ge_mac_cfg_0 ge_mac_cfg_0; 2840dd07709SNoam Camus struct nps_enet_buf_int_enable buf_int_enable; 2850dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2; 2860dd07709SNoam Camus struct nps_enet_ge_mac_cfg_3 *ge_mac_cfg_3 = &priv->ge_mac_cfg_3; 2870dd07709SNoam Camus s32 max_frame_length; 2880dd07709SNoam Camus 2890dd07709SNoam Camus ge_mac_cfg_0.value = 0; 2900dd07709SNoam Camus buf_int_enable.value = 0; 2910dd07709SNoam Camus /* Enable Rx and Tx statistics */ 2920dd07709SNoam Camus ge_mac_cfg_2->stat_en = NPS_ENET_GE_MAC_CFG_2_STAT_EN; 2930dd07709SNoam Camus 2940dd07709SNoam Camus /* Discard packets with different MAC address */ 2950dd07709SNoam Camus ge_mac_cfg_2->disc_da = NPS_ENET_ENABLE; 2960dd07709SNoam Camus 2970dd07709SNoam Camus /* Discard multicast packets */ 2980dd07709SNoam Camus ge_mac_cfg_2->disc_mc = NPS_ENET_ENABLE; 2990dd07709SNoam Camus 3000dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, 3010dd07709SNoam Camus ge_mac_cfg_2->value); 3020dd07709SNoam Camus 3030dd07709SNoam Camus /* Discard Packets bigger than max frame length */ 3040dd07709SNoam Camus max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN; 305de671567SNoam Camus if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) 3060dd07709SNoam Camus ge_mac_cfg_3->max_len = max_frame_length; 3070dd07709SNoam Camus 3080dd07709SNoam Camus /* Enable interrupts */ 3090dd07709SNoam Camus buf_int_enable.rx_rdy = NPS_ENET_ENABLE; 3100dd07709SNoam Camus buf_int_enable.tx_done = NPS_ENET_ENABLE; 3110dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 3120dd07709SNoam Camus buf_int_enable.value); 3130dd07709SNoam Camus 3140dd07709SNoam Camus /* Write device MAC address to HW */ 3150dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 3160dd07709SNoam Camus 3170dd07709SNoam Camus /* Rx and Tx HW features */ 3180dd07709SNoam Camus ge_mac_cfg_0.tx_pad_en = NPS_ENET_ENABLE; 3190dd07709SNoam Camus ge_mac_cfg_0.tx_crc_en = NPS_ENET_ENABLE; 3200dd07709SNoam Camus ge_mac_cfg_0.rx_crc_strip = NPS_ENET_ENABLE; 3210dd07709SNoam Camus 3220dd07709SNoam Camus /* IFG configuration */ 3230dd07709SNoam Camus ge_mac_cfg_0.rx_ifg = NPS_ENET_GE_MAC_CFG_0_RX_IFG; 3240dd07709SNoam Camus ge_mac_cfg_0.tx_ifg = NPS_ENET_GE_MAC_CFG_0_TX_IFG; 3250dd07709SNoam Camus 3260dd07709SNoam Camus /* preamble configuration */ 3270dd07709SNoam Camus ge_mac_cfg_0.rx_pr_check_en = NPS_ENET_ENABLE; 3280dd07709SNoam Camus ge_mac_cfg_0.tx_pr_len = NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN; 3290dd07709SNoam Camus 3300dd07709SNoam Camus /* enable flow control frames */ 3310dd07709SNoam Camus ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE; 3320dd07709SNoam Camus ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE; 3330dd07709SNoam Camus ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR; 334de671567SNoam Camus ge_mac_cfg_3->cf_drop = NPS_ENET_ENABLE; 3350dd07709SNoam Camus 3360dd07709SNoam Camus /* Enable Rx and Tx */ 3370dd07709SNoam Camus ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE; 3380dd07709SNoam Camus ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE; 3390dd07709SNoam Camus 340de671567SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, 341de671567SNoam Camus ge_mac_cfg_3->value); 3420dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 3430dd07709SNoam Camus ge_mac_cfg_0.value); 3440dd07709SNoam Camus } 3450dd07709SNoam Camus 3460dd07709SNoam Camus static void nps_enet_hw_disable_control(struct net_device *ndev) 3470dd07709SNoam Camus { 3480dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 3490dd07709SNoam Camus 3500dd07709SNoam Camus /* Disable interrupts */ 3510dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); 3520dd07709SNoam Camus 3530dd07709SNoam Camus /* Disable Rx and Tx */ 3540dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, 0); 3550dd07709SNoam Camus } 3560dd07709SNoam Camus 3570dd07709SNoam Camus static void nps_enet_send_frame(struct net_device *ndev, 3580dd07709SNoam Camus struct sk_buff *skb) 3590dd07709SNoam Camus { 3600dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 3610dd07709SNoam Camus struct nps_enet_tx_ctl tx_ctrl; 3620dd07709SNoam Camus short length = skb->len; 3630dd07709SNoam Camus u32 i, len = DIV_ROUND_UP(length, sizeof(u32)); 364*b0a8d1a0SArnd Bergmann u32 *src = (void *)skb->data; 3650dd07709SNoam Camus bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32)); 3660dd07709SNoam Camus 3670dd07709SNoam Camus tx_ctrl.value = 0; 3680dd07709SNoam Camus /* In case src is not aligned we need an intermediate buffer */ 3690dd07709SNoam Camus if (src_is_aligned) 3700dd07709SNoam Camus for (i = 0; i < len; i++, src++) 3710dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src); 372*b0a8d1a0SArnd Bergmann else /* !src_is_aligned */ 373*b0a8d1a0SArnd Bergmann for (i = 0; i < len; i++, src++) 374*b0a8d1a0SArnd Bergmann nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, 375*b0a8d1a0SArnd Bergmann get_unaligned(src)); 3760dd07709SNoam Camus 3770dd07709SNoam Camus /* Write the length of the Frame */ 3780dd07709SNoam Camus tx_ctrl.nt = length; 3790dd07709SNoam Camus 3800dd07709SNoam Camus /* Indicate SW is done */ 3810dd07709SNoam Camus priv->tx_packet_sent = true; 3820dd07709SNoam Camus tx_ctrl.ct = NPS_ENET_ENABLE; 3830dd07709SNoam Camus 3840dd07709SNoam Camus /* Send Frame */ 3850dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl.value); 3860dd07709SNoam Camus } 3870dd07709SNoam Camus 3880dd07709SNoam Camus /** 3890dd07709SNoam Camus * nps_enet_set_mac_address - Set the MAC address for this device. 3900dd07709SNoam Camus * @ndev: Pointer to net_device structure. 3910dd07709SNoam Camus * @p: 6 byte Address to be written as MAC address. 3920dd07709SNoam Camus * 3930dd07709SNoam Camus * This function copies the HW address from the sockaddr structure to the 3940dd07709SNoam Camus * net_device structure and updates the address in HW. 3950dd07709SNoam Camus * 3960dd07709SNoam Camus * returns: -EBUSY if the net device is busy or 0 if the address is set 3970dd07709SNoam Camus * successfully. 3980dd07709SNoam Camus */ 3990dd07709SNoam Camus static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p) 4000dd07709SNoam Camus { 4010dd07709SNoam Camus struct sockaddr *addr = p; 4020dd07709SNoam Camus s32 res; 4030dd07709SNoam Camus 4040dd07709SNoam Camus if (netif_running(ndev)) 4050dd07709SNoam Camus return -EBUSY; 4060dd07709SNoam Camus 4070dd07709SNoam Camus res = eth_mac_addr(ndev, p); 4080dd07709SNoam Camus if (!res) { 4090dd07709SNoam Camus ether_addr_copy(ndev->dev_addr, addr->sa_data); 4100dd07709SNoam Camus nps_enet_set_hw_mac_address(ndev); 4110dd07709SNoam Camus } 4120dd07709SNoam Camus 4130dd07709SNoam Camus return res; 4140dd07709SNoam Camus } 4150dd07709SNoam Camus 4160dd07709SNoam Camus /** 4170dd07709SNoam Camus * nps_enet_set_rx_mode - Change the receive filtering mode. 4180dd07709SNoam Camus * @ndev: Pointer to the network device. 4190dd07709SNoam Camus * 4200dd07709SNoam Camus * This function enables/disables promiscuous mode 4210dd07709SNoam Camus */ 4220dd07709SNoam Camus static void nps_enet_set_rx_mode(struct net_device *ndev) 4230dd07709SNoam Camus { 4240dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 4250dd07709SNoam Camus struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2; 4260dd07709SNoam Camus 4270dd07709SNoam Camus ge_mac_cfg_2.value = priv->ge_mac_cfg_2.value; 4280dd07709SNoam Camus 4290dd07709SNoam Camus if (ndev->flags & IFF_PROMISC) { 4300dd07709SNoam Camus ge_mac_cfg_2.disc_da = NPS_ENET_DISABLE; 4310dd07709SNoam Camus ge_mac_cfg_2.disc_mc = NPS_ENET_DISABLE; 4320dd07709SNoam Camus } else { 4330dd07709SNoam Camus ge_mac_cfg_2.disc_da = NPS_ENET_ENABLE; 4340dd07709SNoam Camus ge_mac_cfg_2.disc_mc = NPS_ENET_ENABLE; 4350dd07709SNoam Camus } 4360dd07709SNoam Camus 4370dd07709SNoam Camus nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2.value); 4380dd07709SNoam Camus } 4390dd07709SNoam Camus 4400dd07709SNoam Camus /** 4410dd07709SNoam Camus * nps_enet_open - Open the network device. 4420dd07709SNoam Camus * @ndev: Pointer to the network device. 4430dd07709SNoam Camus * 4440dd07709SNoam Camus * returns: 0, on success or non-zero error value on failure. 4450dd07709SNoam Camus * 4460dd07709SNoam Camus * This function sets the MAC address, requests and enables an IRQ 4470dd07709SNoam Camus * for the ENET device and starts the Tx queue. 4480dd07709SNoam Camus */ 4490dd07709SNoam Camus static s32 nps_enet_open(struct net_device *ndev) 4500dd07709SNoam Camus { 4510dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 4520dd07709SNoam Camus s32 err; 4530dd07709SNoam Camus 4540dd07709SNoam Camus /* Reset private variables */ 4550dd07709SNoam Camus priv->tx_packet_sent = false; 4560dd07709SNoam Camus priv->ge_mac_cfg_2.value = 0; 4570dd07709SNoam Camus priv->ge_mac_cfg_3.value = 0; 4580dd07709SNoam Camus 4590dd07709SNoam Camus /* ge_mac_cfg_3 default values */ 4600dd07709SNoam Camus priv->ge_mac_cfg_3.rx_ifg_th = NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH; 4610dd07709SNoam Camus priv->ge_mac_cfg_3.max_len = NPS_ENET_GE_MAC_CFG_3_MAX_LEN; 4620dd07709SNoam Camus 4630dd07709SNoam Camus /* Disable HW device */ 4640dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 4650dd07709SNoam Camus 4660dd07709SNoam Camus /* irq Rx allocation */ 4670dd07709SNoam Camus err = request_irq(priv->irq, nps_enet_irq_handler, 4680dd07709SNoam Camus 0, "enet-rx-tx", ndev); 4690dd07709SNoam Camus if (err) 4700dd07709SNoam Camus return err; 4710dd07709SNoam Camus 4720dd07709SNoam Camus napi_enable(&priv->napi); 4730dd07709SNoam Camus 4740dd07709SNoam Camus /* Enable HW device */ 4750dd07709SNoam Camus nps_enet_hw_reset(ndev); 4760dd07709SNoam Camus nps_enet_hw_enable_control(ndev); 4770dd07709SNoam Camus 4780dd07709SNoam Camus netif_start_queue(ndev); 4790dd07709SNoam Camus 4800dd07709SNoam Camus return 0; 4810dd07709SNoam Camus } 4820dd07709SNoam Camus 4830dd07709SNoam Camus /** 4840dd07709SNoam Camus * nps_enet_stop - Close the network device. 4850dd07709SNoam Camus * @ndev: Pointer to the network device. 4860dd07709SNoam Camus * 4870dd07709SNoam Camus * This function stops the Tx queue, disables interrupts for the ENET device. 4880dd07709SNoam Camus */ 4890dd07709SNoam Camus static s32 nps_enet_stop(struct net_device *ndev) 4900dd07709SNoam Camus { 4910dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 4920dd07709SNoam Camus 4930dd07709SNoam Camus napi_disable(&priv->napi); 4940dd07709SNoam Camus netif_stop_queue(ndev); 4950dd07709SNoam Camus nps_enet_hw_disable_control(ndev); 4960dd07709SNoam Camus free_irq(priv->irq, ndev); 4970dd07709SNoam Camus 4980dd07709SNoam Camus return 0; 4990dd07709SNoam Camus } 5000dd07709SNoam Camus 5010dd07709SNoam Camus /** 5020dd07709SNoam Camus * nps_enet_start_xmit - Starts the data transmission. 5030dd07709SNoam Camus * @skb: sk_buff pointer that contains data to be Transmitted. 5040dd07709SNoam Camus * @ndev: Pointer to net_device structure. 5050dd07709SNoam Camus * 5060dd07709SNoam Camus * returns: NETDEV_TX_OK, on success 5070dd07709SNoam Camus * NETDEV_TX_BUSY, if any of the descriptors are not free. 5080dd07709SNoam Camus * 5090dd07709SNoam Camus * This function is invoked from upper layers to initiate transmission. 5100dd07709SNoam Camus */ 5110dd07709SNoam Camus static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb, 5120dd07709SNoam Camus struct net_device *ndev) 5130dd07709SNoam Camus { 5140dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 5150dd07709SNoam Camus 5160dd07709SNoam Camus /* This driver handles one frame at a time */ 5170dd07709SNoam Camus netif_stop_queue(ndev); 5180dd07709SNoam Camus 5190dd07709SNoam Camus priv->tx_skb = skb; 5200dd07709SNoam Camus 52193fcf83eSNoam Camus nps_enet_send_frame(ndev, skb); 52293fcf83eSNoam Camus 5230dd07709SNoam Camus return NETDEV_TX_OK; 5240dd07709SNoam Camus } 5250dd07709SNoam Camus 5260dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 5270dd07709SNoam Camus static void nps_enet_poll_controller(struct net_device *ndev) 5280dd07709SNoam Camus { 5290dd07709SNoam Camus disable_irq(ndev->irq); 5300dd07709SNoam Camus nps_enet_irq_handler(ndev->irq, ndev); 5310dd07709SNoam Camus enable_irq(ndev->irq); 5320dd07709SNoam Camus } 5330dd07709SNoam Camus #endif 5340dd07709SNoam Camus 5350dd07709SNoam Camus static const struct net_device_ops nps_netdev_ops = { 5360dd07709SNoam Camus .ndo_open = nps_enet_open, 5370dd07709SNoam Camus .ndo_stop = nps_enet_stop, 5380dd07709SNoam Camus .ndo_start_xmit = nps_enet_start_xmit, 5390dd07709SNoam Camus .ndo_set_mac_address = nps_enet_set_mac_address, 5400dd07709SNoam Camus .ndo_set_rx_mode = nps_enet_set_rx_mode, 5410dd07709SNoam Camus #ifdef CONFIG_NET_POLL_CONTROLLER 5420dd07709SNoam Camus .ndo_poll_controller = nps_enet_poll_controller, 5430dd07709SNoam Camus #endif 5440dd07709SNoam Camus }; 5450dd07709SNoam Camus 5460dd07709SNoam Camus static s32 nps_enet_probe(struct platform_device *pdev) 5470dd07709SNoam Camus { 5480dd07709SNoam Camus struct device *dev = &pdev->dev; 5490dd07709SNoam Camus struct net_device *ndev; 5500dd07709SNoam Camus struct nps_enet_priv *priv; 5510dd07709SNoam Camus s32 err = 0; 5520dd07709SNoam Camus const char *mac_addr; 5530dd07709SNoam Camus struct resource *res_regs; 5540dd07709SNoam Camus 5550dd07709SNoam Camus if (!dev->of_node) 5560dd07709SNoam Camus return -ENODEV; 5570dd07709SNoam Camus 5580dd07709SNoam Camus ndev = alloc_etherdev(sizeof(struct nps_enet_priv)); 5590dd07709SNoam Camus if (!ndev) 5600dd07709SNoam Camus return -ENOMEM; 5610dd07709SNoam Camus 5620dd07709SNoam Camus platform_set_drvdata(pdev, ndev); 5630dd07709SNoam Camus SET_NETDEV_DEV(ndev, dev); 5640dd07709SNoam Camus priv = netdev_priv(ndev); 5650dd07709SNoam Camus 5660dd07709SNoam Camus /* The EZ NET specific entries in the device structure. */ 5670dd07709SNoam Camus ndev->netdev_ops = &nps_netdev_ops; 5680dd07709SNoam Camus ndev->watchdog_timeo = (400 * HZ / 1000); 5690dd07709SNoam Camus /* FIXME :: no multicast support yet */ 5700dd07709SNoam Camus ndev->flags &= ~IFF_MULTICAST; 5710dd07709SNoam Camus 5720dd07709SNoam Camus res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5730dd07709SNoam Camus priv->regs_base = devm_ioremap_resource(dev, res_regs); 5740dd07709SNoam Camus if (IS_ERR(priv->regs_base)) { 5750dd07709SNoam Camus err = PTR_ERR(priv->regs_base); 5760dd07709SNoam Camus goto out_netdev; 5770dd07709SNoam Camus } 5780dd07709SNoam Camus dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs_base); 5790dd07709SNoam Camus 5800dd07709SNoam Camus /* set kernel MAC address to dev */ 5810dd07709SNoam Camus mac_addr = of_get_mac_address(dev->of_node); 5820dd07709SNoam Camus if (mac_addr) 5830dd07709SNoam Camus ether_addr_copy(ndev->dev_addr, mac_addr); 5840dd07709SNoam Camus else 5850dd07709SNoam Camus eth_hw_addr_random(ndev); 5860dd07709SNoam Camus 5870dd07709SNoam Camus /* Get IRQ number */ 5880dd07709SNoam Camus priv->irq = platform_get_irq(pdev, 0); 5890dd07709SNoam Camus if (!priv->irq) { 5900dd07709SNoam Camus dev_err(dev, "failed to retrieve <irq Rx-Tx> value from device tree\n"); 5910dd07709SNoam Camus err = -ENODEV; 5920dd07709SNoam Camus goto out_netdev; 5930dd07709SNoam Camus } 5940dd07709SNoam Camus 5950dd07709SNoam Camus netif_napi_add(ndev, &priv->napi, nps_enet_poll, 5960dd07709SNoam Camus NPS_ENET_NAPI_POLL_WEIGHT); 5970dd07709SNoam Camus 5980dd07709SNoam Camus /* Register the driver. Should be the last thing in probe */ 5990dd07709SNoam Camus err = register_netdev(ndev); 6000dd07709SNoam Camus if (err) { 6010dd07709SNoam Camus dev_err(dev, "Failed to register ndev for %s, err = 0x%08x\n", 6020dd07709SNoam Camus ndev->name, (s32)err); 6030dd07709SNoam Camus goto out_netif_api; 6040dd07709SNoam Camus } 6050dd07709SNoam Camus 6060dd07709SNoam Camus dev_info(dev, "(rx/tx=%d)\n", priv->irq); 6070dd07709SNoam Camus return 0; 6080dd07709SNoam Camus 6090dd07709SNoam Camus out_netif_api: 6100dd07709SNoam Camus netif_napi_del(&priv->napi); 6110dd07709SNoam Camus out_netdev: 6120dd07709SNoam Camus if (err) 6130dd07709SNoam Camus free_netdev(ndev); 6140dd07709SNoam Camus 6150dd07709SNoam Camus return err; 6160dd07709SNoam Camus } 6170dd07709SNoam Camus 6180dd07709SNoam Camus static s32 nps_enet_remove(struct platform_device *pdev) 6190dd07709SNoam Camus { 6200dd07709SNoam Camus struct net_device *ndev = platform_get_drvdata(pdev); 6210dd07709SNoam Camus struct nps_enet_priv *priv = netdev_priv(ndev); 6220dd07709SNoam Camus 6230dd07709SNoam Camus unregister_netdev(ndev); 6240dd07709SNoam Camus free_netdev(ndev); 6250dd07709SNoam Camus netif_napi_del(&priv->napi); 6260dd07709SNoam Camus 6270dd07709SNoam Camus return 0; 6280dd07709SNoam Camus } 6290dd07709SNoam Camus 6300dd07709SNoam Camus static const struct of_device_id nps_enet_dt_ids[] = { 6310dd07709SNoam Camus { .compatible = "ezchip,nps-mgt-enet" }, 6320dd07709SNoam Camus { /* Sentinel */ } 6330dd07709SNoam Camus }; 6340dd07709SNoam Camus 6350dd07709SNoam Camus static struct platform_driver nps_enet_driver = { 6360dd07709SNoam Camus .probe = nps_enet_probe, 6370dd07709SNoam Camus .remove = nps_enet_remove, 6380dd07709SNoam Camus .driver = { 6390dd07709SNoam Camus .name = DRV_NAME, 6400dd07709SNoam Camus .of_match_table = nps_enet_dt_ids, 6410dd07709SNoam Camus }, 6420dd07709SNoam Camus }; 6430dd07709SNoam Camus 6440dd07709SNoam Camus module_platform_driver(nps_enet_driver); 6450dd07709SNoam Camus 6460dd07709SNoam Camus MODULE_AUTHOR("EZchip Semiconductor"); 6470dd07709SNoam Camus MODULE_LICENSE("GPL v2"); 648