History

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.

Christian Riesch committed 12 years ago

Commit cd11cf51 parent 33b71072 files · +31 −17Browse files

Unified · Split

2 files
  1. drivers/net/ethernet/ti/davinci_cpdma.c +2 −2
  2. drivers/net/ethernet/ti/davinci_emac.c +29 −15
drivers/net/ethernet/ti/davinci_cpdma.c+2−2
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) · 354 unmodified lines
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) · 529 unmodified lines
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+29−15
@@ -1533,8 +1533,8 @@ static int emac_dev_open(struct net_device *ndev) · 1532 unmodified lines
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) · 23 unmodified lines
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) · 60 unmodified lines
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 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t