]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
ethernet: xilinx: Improve Rx error handling
authorKedareswara rao Appana <appanad@xilinx.com>
Mon, 18 Sep 2017 07:34:40 +0000 (13:04 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Thu, 15 Mar 2018 14:17:49 +0000 (15:17 +0100)
While running iperf in bi-directional mode seeing the
Receive memory overrun interrupts when reading through devmem the driver is not
updating the over run errors. This patch updates the same.

Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/net/ethernet/xilinx/xilinx_axienet.h
drivers/net/ethernet/xilinx/xilinx_axienet_main.c

index 175ff3a5d6a58fa8dbd280ce4a27bbe16238cfba..b5b2823c2e955120af32639f79c9767eb6b54dd4 100644 (file)
@@ -456,6 +456,7 @@ struct axidma_bd {
  * @tx_irq:    Axidma TX IRQ number
  * @rx_irq:    Axidma RX IRQ number
  * @phy_mode:  Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X
+ * @eth_irq:   Axi Ethernet IRQ number
  * @options:   AxiEthernet option word
  * @last_link: Phy link state in which the PHY was negotiated earlier
  * @features:  Stores the extended features supported by the axienet hw
@@ -510,6 +511,7 @@ struct axienet_local {
        int tx_irq;
        int rx_irq;
        phy_interface_t phy_mode;
+       int eth_irq;
 
        u32 options;                    /* Current options word */
        u32 last_link;
index 0775e975de1d87697fe7279b27186e7b995fc98f..bf24e4a9ff07465229278f8c2641dd6c9b46a8ec 100644 (file)
@@ -595,6 +595,9 @@ static void axienet_device_reset(struct net_device *ndev)
                axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
                if (axienet_status & XAE_INT_RXRJECT_MASK)
                        axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+
+               /* Enable Receive errors */
+               axienet_iow(lp, XAE_IE_OFFSET, XAE_INT_RECV_ERROR_MASK);
        }
 
        if (lp->axienet_config->mactype == XAXIENET_10G_25G) {
@@ -1241,6 +1244,35 @@ static int xaxienet_rx_poll(struct napi_struct *napi, int quota)
        return work_done;
 }
 
+/**
+ * axienet_err_irq - Axi Ethernet error irq.
+ * @irq:       irq number
+ * @_ndev:     net_device pointer
+ *
+ * Return: IRQ_HANDLED for all cases.
+ *
+ * This is the Axi DMA error ISR. It updates the rx memory over run condition.
+ */
+static irqreturn_t axienet_err_irq(int irq, void *_ndev)
+{
+       unsigned int status;
+       struct net_device *ndev = _ndev;
+       struct axienet_local *lp = netdev_priv(ndev);
+
+       status = axienet_ior(lp, XAE_IS_OFFSET);
+       if (status & XAE_INT_RXFIFOOVR_MASK) {
+               ndev->stats.rx_fifo_errors++;
+               axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXFIFOOVR_MASK);
+       }
+
+       if (status & XAE_INT_RXRJECT_MASK) {
+               axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+               axienet_device_reset(ndev);
+       }
+
+       return IRQ_HANDLED;
+}
+
 /**
  * axienet_tx_irq - Tx Done Isr.
  * @irq:       irq number
@@ -1440,8 +1472,18 @@ static int axienet_open(struct net_device *ndev)
        if (ret)
                goto err_rx_irq;
 
+       if (!lp->eth_hasnobuf && (lp->axienet_config->mactype == XAXIENET_1G)) {
+               /* Enable interrupts for Axi Ethernet */
+               ret = request_irq(lp->eth_irq, axienet_err_irq, 0, ndev->name,
+                                 ndev);
+               if (ret)
+                       goto err_eth_irq;
+       }
+
        return 0;
 
+err_eth_irq:
+       free_irq(lp->rx_irq, ndev);
 err_rx_irq:
        free_irq(lp->tx_irq, ndev);
 err_tx_irq:
@@ -1485,6 +1527,9 @@ static int axienet_stop(struct net_device *ndev)
        free_irq(lp->tx_irq, ndev);
        free_irq(lp->rx_irq, ndev);
 
+       if ((lp->axienet_config->mactype == XAXIENET_1G) && !lp->eth_hasnobuf)
+               free_irq(lp->eth_irq, ndev);
+
        if (ndev->phydev)
                phy_disconnect(ndev->phydev);
 
@@ -2263,6 +2308,9 @@ static int axienet_probe(struct platform_device *pdev)
        lp->eth_hasnobuf = of_property_read_bool(pdev->dev.of_node,
                                                 "xlnx,eth-hasnobuf");
 
+       if ((lp->axienet_config->mactype == XAXIENET_1G) && !lp->eth_hasnobuf)
+               lp->eth_irq = platform_get_irq(pdev, 0);
+
 #ifdef CONFIG_XILINX_AXI_EMAC_HWTSTAMP
        struct resource txtsres, rxtsres;