]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'davinci_emac'
authorDavid S. Miller <davem@davemloft.net>
Mon, 24 Mar 2014 19:32:34 +0000 (15:32 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 Mar 2014 19:32:34 +0000 (15:32 -0400)
Christian Riesch says:

====================
net: davinci_emac: Fix interrupt requests and error handling

since commit 6892b41d9701283085b655c6086fb57a5d63fa47 (Linux 3.11) the
davinci_emac driver is broken. After doing ifconfig down, ifconfig up,
requesting the interrupts for the driver fails. The interface remains dead
until the board is rebooted.

The first patch in this patchset reverts commit
6892b41d9701283085b655c6086fb57a5d63fa47 partially and makes the driver
useable again.

During the work on the first patch, a number of bugs in the error handling
of the driver's ndo_open code were found. The second patch fixes these bugs.

I believe the first patch meets the rules for stable kernels, I therefore added
the stable tag to this patch. The second patch is just cleanup, the code
that is fixed by this patch is only executed in case of an error.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_emac.c

index 364d0c7952c023d0cc60de6cc8d73460b000fbd1..88ef27067bf24a8b2569f533b63ac223d52280fe 100644 (file)
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
        int i;
 
        spin_lock_irqsave(&ctlr->lock, flags);
-       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+       if (ctlr->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&ctlr->lock, flags);
                return -EINVAL;
        }
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
        unsigned                timeout;
 
        spin_lock_irqsave(&chan->lock, flags);
-       if (chan->state != CPDMA_STATE_ACTIVE) {
+       if (chan->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&chan->lock, flags);
                return -EINVAL;
        }
index cd9b164a0434acb3a51066b5d0e17262a4bdc0dd..8f0e69ce07ca3e03cfbf4cf1b22c92c9af27beeb 100644 (file)
@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
        struct device *emac_dev = &ndev->dev;
        u32 cnt;
        struct resource *res;
-       int ret;
+       int q, m, ret;
+       int res_num = 0, irq_num = 0;
        int i = 0;
-       int k = 0;
        struct emac_priv *priv = netdev_priv(ndev);
 
        pm_runtime_get(&priv->pdev->dev);
@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
        }
 
        /* Request IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
+                                           res_num))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++) {
+                       dev_err(emac_dev, "Request IRQ %d\n", irq_num);
+                       if (request_irq(irq_num, emac_irq, 0, ndev->name,
+                                       ndev)) {
+                               dev_err(emac_dev,
+                                       "DaVinci EMAC: request_irq() failed\n");
+                               ret = -EBUSY;
 
-       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
-                                            0, ndev->name, ndev))
                                goto rollback;
+                       }
                }
-               k++;
+               res_num++;
        }
+       /* prepare counters for rollback in case of an error */
+       res_num--;
+       irq_num--;
 
        /* Start/Enable EMAC hardware */
        emac_hw_enable(priv);
@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
 
        return 0;
 
-rollback:
-
-       dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
-       ret = -EBUSY;
 err:
+       emac_int_disable(priv);
+       napi_disable(&priv->napi);
+
+rollback:
+       for (q = res_num; q >= 0; q--) {
+               res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
+               /* at the first iteration, irq_num is already set to the
+                * right value
+                */
+               if (q != res_num)
+                       irq_num = res->end;
+
+               for (m = irq_num; m >= res->start; m--)
+                       free_irq(m, ndev);
+       }
+       cpdma_ctlr_stop(priv->dma);
        pm_runtime_put(&priv->pdev->dev);
        return ret;
 }
@@ -1659,6 +1680,9 @@ err:
  */
 static int emac_dev_stop(struct net_device *ndev)
 {
+       struct resource *res;
+       int i = 0;
+       int irq_num;
        struct emac_priv *priv = netdev_priv(ndev);
        struct device *emac_dev = &ndev->dev;
 
@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
        if (priv->phydev)
                phy_disconnect(priv->phydev);
 
+       /* Free IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++)
+                       free_irq(irq_num, priv->ndev);
+               i++;
+       }
+
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);