summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linutronix.de>2013-04-23 07:31:36 +0000
committerDavid S. Miller <davem@davemloft.net>2013-04-25 04:11:49 -0400
commitaacebbf8026ecdae1b55db3912e65c6b1308f5ed (patch)
treef9b54c50ec8822b253feefd1b41ded0e20e681d7 /drivers
parent817f6d1a13754b043e1a6c1cb713763022860689 (diff)
net/cpsw: don't continue if we miss to allocate rx skbs
if during "ifconfig up" we run out of mem we continue regardless how many skbs we got. In worst case we have zero RX skbs and can't ever receive further packets since the RX skbs are never reallocated. If cpdma_chan_submit() fails we even leak the skb. This patch changes the behavior here: If we fail to allocate an skb during bring up we don't continue and report that error. Same goes for errors from cpdma_chan_submit(). While here I changed to __netdev_alloc_skb_ip_align() so GFP_KERNEL can be used. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Acked-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 25c364209a21..5f581bc511ba 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -867,6 +867,15 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
}
}
+static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+ if (!slave->phy)
+ return;
+ phy_stop(slave->phy);
+ phy_disconnect(slave->phy);
+ slave->phy = NULL;
+}
+
static int cpsw_ndo_open(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
@@ -912,14 +921,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
struct sk_buff *skb;
ret = -ENOMEM;
- skb = netdev_alloc_skb_ip_align(priv->ndev,
- priv->rx_packet_max);
+ skb = __netdev_alloc_skb_ip_align(priv->ndev,
+ priv->rx_packet_max, GFP_KERNEL);
if (!skb)
- break;
+ goto err_cleanup;
ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
skb_tailroom(skb), 0, GFP_KERNEL);
- if (WARN_ON(ret < 0))
- break;
+ if (ret < 0) {
+ kfree_skb(skb);
+ goto err_cleanup;
+ }
}
/* continue even if we didn't manage to submit all
* receive descs
@@ -944,15 +955,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
if (priv->data.dual_emac)
priv->slaves[priv->emac_port].open_stat = true;
return 0;
-}
-static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
-{
- if (!slave->phy)
- return;
- phy_stop(slave->phy);
- phy_disconnect(slave->phy);
- slave->phy = NULL;
+err_cleanup:
+ cpdma_ctlr_stop(priv->dma);
+ for_each_slave(priv, cpsw_slave_stop, priv);
+ pm_runtime_put_sync(&priv->pdev->dev);
+ netif_carrier_off(priv->ndev);
+ return ret;
}
static int cpsw_ndo_stop(struct net_device *ndev)