aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/ti/davinci_emac.c
diff options
context:
space:
mode:
authorChristian Riesch <christian.riesch@omicron.at>2014-03-24 08:46:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-24 15:32:03 -0400
commitcd11cf505318ff24e42f35145f9cdf8596fa1958 (patch)
tree06ca0a0ed579d0e8aaab3a7b0f2921f3c9c20855 /drivers/net/ethernet/ti/davinci_emac.c
parent33b7107f59a61236d94ecd6b45e20283cd5abcc8 (diff)
net: davinci_emac: Fix rollback of emac_dev_open()
If an error occurs during the initialization in emac_dev_open() (the driver's ndo_open function), interrupts, DMA descriptors etc. must be freed. The current rollback code is buggy in several ways. 1) Freeing the interrupts. The current code will not free all interrupts that were requested by the driver. Furthermore, the code tries to do a platform_get_resource(priv->pdev, IORESOURCE_IRQ, -1) in its last iteration. This patch fixes these bugs. 2) Wrong order of err: and rollback: labels. If the setup of the PHY in the code fails, the interrupts that have been requested before are not freed: request irq if requesting irqs fails, goto rollback setup phy if phy setup fails, goto err return 0 rollback: free irqs err: This patch brings the code into the correct order. 3) The code calls napi_enable() and emac_int_enable(), but does not undo both in case of an error. This patch adds calls of emac_int_disable() and napi_disable() to the rollback code. 4) RX DMA descriptors are not freed in case of an error: Right before requesting the irqs, the function creates DMA descriptors for the RX channel. These RX descriptors are never freed when we jump to either rollback or err. This patch adds code for freeing the DMA descriptors in the case of an initialization error. This required a modification of cpdma_ctrl_stop() in davinci_cpdma.c: We must be able to call this function to free the DMA descriptors while the DMA channels are in IDLE state (before cpdma_ctlr_start() was called). Tested on a custom board with the Texas Instruments AM1808. Signed-off-by: Christian Riesch <christian.riesch@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ti/davinci_emac.c')
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 251430450005..8f0e69ce07ca 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1533,8 +1533,8 @@ static int emac_dev_open(struct net_device *ndev)
1533 u32 cnt; 1533 u32 cnt;
1534 struct resource *res; 1534 struct resource *res;
1535 int q, m, ret; 1535 int q, m, ret;
1536 int res_num = 0, irq_num = 0;
1536 int i = 0; 1537 int i = 0;
1537 int k = 0;
1538 struct emac_priv *priv = netdev_priv(ndev); 1538 struct emac_priv *priv = netdev_priv(ndev);
1539 1539
1540 pm_runtime_get(&priv->pdev->dev); 1540 pm_runtime_get(&priv->pdev->dev);
@@ -1564,14 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
1564 } 1564 }
1565 1565
1566 /* Request IRQ */ 1566 /* Request IRQ */
1567 while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
1568 res_num))) {
1569 for (irq_num = res->start; irq_num <= res->end; irq_num++) {
1570 dev_err(emac_dev, "Request IRQ %d\n", irq_num);
1571 if (request_irq(irq_num, emac_irq, 0, ndev->name,
1572 ndev)) {
1573 dev_err(emac_dev,
1574 "DaVinci EMAC: request_irq() failed\n");
1575 ret = -EBUSY;
1567 1576
1568 while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
1569 for (i = res->start; i <= res->end; i++) {
1570 if (request_irq(i, emac_irq, 0, ndev->name, ndev))
1571 goto rollback; 1577 goto rollback;
1578 }
1572 } 1579 }
1573 k++; 1580 res_num++;
1574 } 1581 }
1582 /* prepare counters for rollback in case of an error */
1583 res_num--;
1584 irq_num--;
1575 1585
1576 /* Start/Enable EMAC hardware */ 1586 /* Start/Enable EMAC hardware */
1577 emac_hw_enable(priv); 1587 emac_hw_enable(priv);
@@ -1638,19 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
1638 1648
1639 return 0; 1649 return 0;
1640 1650
1641rollback: 1651err:
1642 1652 emac_int_disable(priv);
1643 dev_err(emac_dev, "DaVinci EMAC: request_irq() failed"); 1653 napi_disable(&priv->napi);
1644 1654
1645 for (q = k; k >= 0; k--) { 1655rollback:
1646 for (m = i; m >= res->start; m--) 1656 for (q = res_num; q >= 0; q--) {
1657 res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
1658 /* at the first iteration, irq_num is already set to the
1659 * right value
1660 */
1661 if (q != res_num)
1662 irq_num = res->end;
1663
1664 for (m = irq_num; m >= res->start; m--)
1647 free_irq(m, ndev); 1665 free_irq(m, ndev);
1648 res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1);
1649 m = res->end;
1650 } 1666 }
1651 1667 cpdma_ctlr_stop(priv->dma);
1652 ret = -EBUSY;
1653err:
1654 pm_runtime_put(&priv->pdev->dev); 1668 pm_runtime_put(&priv->pdev->dev);
1655 return ret; 1669 return ret;
1656} 1670}