Commit 866b7cdf authored by David S. Miller's avatar David S. Miller

Merge branch 'davinci_emac'

Christian Riesch says:

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

since commit 6892b41d (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
6892b41d 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: default avatarDavid S. Miller <davem@davemloft.net>
parents c27f0872 cd11cf50
...@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) ...@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
int i; int i;
spin_lock_irqsave(&ctlr->lock, flags); spin_lock_irqsave(&ctlr->lock, flags);
if (ctlr->state != CPDMA_STATE_ACTIVE) { if (ctlr->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&ctlr->lock, flags); spin_unlock_irqrestore(&ctlr->lock, flags);
return -EINVAL; return -EINVAL;
} }
...@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) ...@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
unsigned timeout; unsigned timeout;
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
if (chan->state != CPDMA_STATE_ACTIVE) { if (chan->state == CPDMA_STATE_TEARDOWN) {
spin_unlock_irqrestore(&chan->lock, flags); spin_unlock_irqrestore(&chan->lock, flags);
return -EINVAL; return -EINVAL;
} }
......
...@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev) ...@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
struct device *emac_dev = &ndev->dev; struct device *emac_dev = &ndev->dev;
u32 cnt; u32 cnt;
struct resource *res; struct resource *res;
int ret; int q, m, ret;
int res_num = 0, irq_num = 0;
int i = 0; int i = 0;
int k = 0;
struct emac_priv *priv = netdev_priv(ndev); struct emac_priv *priv = netdev_priv(ndev);
pm_runtime_get(&priv->pdev->dev); pm_runtime_get(&priv->pdev->dev);
...@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev) ...@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
} }
/* Request IRQ */ /* 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; goto rollback;
}
} }
k++; res_num++;
} }
/* prepare counters for rollback in case of an error */
res_num--;
irq_num--;
/* Start/Enable EMAC hardware */ /* Start/Enable EMAC hardware */
emac_hw_enable(priv); emac_hw_enable(priv);
...@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev) ...@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
return 0; return 0;
rollback:
dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
ret = -EBUSY;
err: 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); pm_runtime_put(&priv->pdev->dev);
return ret; return ret;
} }
...@@ -1659,6 +1680,9 @@ static int emac_dev_open(struct net_device *ndev) ...@@ -1659,6 +1680,9 @@ static int emac_dev_open(struct net_device *ndev)
*/ */
static int emac_dev_stop(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 emac_priv *priv = netdev_priv(ndev);
struct device *emac_dev = &ndev->dev; struct device *emac_dev = &ndev->dev;
...@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev) ...@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
if (priv->phydev) if (priv->phydev)
phy_disconnect(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)) if (netif_msg_drv(priv))
dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name); dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment