Skip to content

Commit cd11cf5

Browse files
Christian Rieschdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 33b7107 commit cd11cf5

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

drivers/net/ethernet/ti/davinci_cpdma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
355355
int i;
356356

357357
spin_lock_irqsave(&ctlr->lock, flags);
358-
if (ctlr->state != CPDMA_STATE_ACTIVE) {
358+
if (ctlr->state == CPDMA_STATE_TEARDOWN) {
359359
spin_unlock_irqrestore(&ctlr->lock, flags);
360360
return -EINVAL;
361361
}
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
891891
unsigned timeout;
892892

893893
spin_lock_irqsave(&chan->lock, flags);
894-
if (chan->state != CPDMA_STATE_ACTIVE) {
894+
if (chan->state == CPDMA_STATE_TEARDOWN) {
895895
spin_unlock_irqrestore(&chan->lock, flags);
896896
return -EINVAL;
897897
}

drivers/net/ethernet/ti/davinci_emac.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,8 +1533,8 @@ static int emac_dev_open(struct net_device *ndev)
15331533
u32 cnt;
15341534
struct resource *res;
15351535
int q, m, ret;
1536+
int res_num = 0, irq_num = 0;
15361537
int i = 0;
1537-
int k = 0;
15381538
struct emac_priv *priv = netdev_priv(ndev);
15391539

15401540
pm_runtime_get(&priv->pdev->dev);
@@ -1564,14 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
15641564
}
15651565

15661566
/* 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;
15671576

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))
15711577
goto rollback;
1578+
}
15721579
}
1573-
k++;
1580+
res_num++;
15741581
}
1582+
/* prepare counters for rollback in case of an error */
1583+
res_num--;
1584+
irq_num--;
15751585

15761586
/* Start/Enable EMAC hardware */
15771587
emac_hw_enable(priv);
@@ -1638,19 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
16381648

16391649
return 0;
16401650

1641-
rollback:
1642-
1643-
dev_err(emac_dev, "DaVinci EMAC: request_irq() failed");
1651+
err:
1652+
emac_int_disable(priv);
1653+
napi_disable(&priv->napi);
16441654

1645-
for (q = k; k >= 0; k--) {
1646-
for (m = i; m >= res->start; m--)
1655+
rollback:
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--)
16471665
free_irq(m, ndev);
1648-
res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1);
1649-
m = res->end;
16501666
}
1651-
1652-
ret = -EBUSY;
1653-
err:
1667+
cpdma_ctlr_stop(priv->dma);
16541668
pm_runtime_put(&priv->pdev->dev);
16551669
return ret;
16561670
}

0 commit comments

Comments
 (0)