]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
ethernet: xilinx: Improve Rx error handling
authorKedareswara rao Appana <appana.durga.rao@xilinx.com>
Tue, 10 Nov 2015 06:47:45 +0000 (12:17 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 11 Nov 2015 08:46:51 +0000 (09:46 +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 f99dc13fdead3df9a21205d3f65c613f286d6d04..87659568c71da1b8c983924e1c8409e7bf47dfc5 100644 (file)
@@ -417,6 +417,7 @@ struct axidma_bd {
  * @tx_lock:   Spin lock for tx path
  * @tx_irq:    Axidma TX IRQ number
  * @rx_irq:    Axidma RX IRQ number
+ * @eth_irq:   Axi Ethernet IRQ number
  * @phy_type:  Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X
  * @options:   AxiEthernet option word
  * @last_link: Phy link state in which the PHY was negotiated earlier
@@ -468,6 +469,7 @@ struct axienet_local {
 
        int tx_irq;
        int rx_irq;
+       int eth_irq;
        u32 phy_type;
 
        u32 options;                    /* Current options word */
index 5c4baadf0d6556813b3bf82cf88711fdf776aed7..6b1781227bf297ce04d620bfa45393bd79bc6def 100644 (file)
@@ -518,6 +518,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);
        }
 
        axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
@@ -1060,6 +1063,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
@@ -1225,10 +1257,20 @@ static int axienet_open(struct net_device *ndev)
        if (ret)
                goto err_rx_irq;
 
+       if (!lp->eth_hasnobuf) {
+               /* Enable interrupts for Axi Ethernet */
+               ret = request_irq(lp->eth_irq, axienet_err_irq, 0, ndev->name,
+                                 ndev);
+               if (ret)
+                       goto err_eth_irq;
+       }
+
        napi_enable(&lp->napi);
 
        return 0;
 
+err_eth_irq:
+       free_irq(lp->rx_irq, ndev);
 err_rx_irq:
        free_irq(lp->tx_irq, ndev);
 err_tx_irq:
@@ -1272,6 +1314,9 @@ static int axienet_stop(struct net_device *ndev)
        free_irq(lp->tx_irq, ndev);
        free_irq(lp->rx_irq, ndev);
 
+       if (!lp->eth_hasnobuf)
+               free_irq(lp->eth_irq, ndev);
+
        if (lp->phy_dev)
                phy_disconnect(lp->phy_dev);
        lp->phy_dev = NULL;
@@ -2025,6 +2070,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->eth_hasnobuf)
+               lp->eth_irq = platform_get_irq(pdev, 0);
+
 #ifdef CONFIG_XILINX_AXI_EMAC_HWTSTAMP
        struct resource txtsres;