Skip to content

Commit

Permalink
Merge branch 'davinci_emac'
Browse files Browse the repository at this point in the history
Christian Riesch says:

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

since commit 6892b41 (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
6892b41 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 <[email protected]>
  • Loading branch information
davem330 committed Mar 24, 2014
2 parents c27f087 + cd11cf5 commit 866b7cd
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 13 deletions.
4 changes: 2 additions & 2 deletions drivers/net/ethernet/ti/davinci_cpdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
53 changes: 42 additions & 11 deletions drivers/net/ethernet/ti/davinci_emac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand All @@ -1659,6 +1680,9 @@ static int emac_dev_open(struct net_device *ndev)
*/
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;

Expand All @@ -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);

Expand Down

0 comments on commit 866b7cd

Please sign in to comment.