aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linutronix.de>2013-04-23 03:31:39 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-25 04:11:50 -0400
commitb4727e69b81b71c6e9696185091e8256d863f9be (patch)
tree6dc2536dbd5d1e53641f701605923d2301074a51 /drivers/net
parentaef614e13dfbdd3b9ae44ad110159f75b9029bba (diff)
net/cpsw: redo rx skb allocation in rx path
In case that we run into OOM during the allocation of the new rx-skb we don't get one and we have one skb less than we used to have. If this continues to happen then we end up with no rx-skbs at all. This patch changes the following: - if we fail to allocate the new skb, then we treat the currently completed skb as the new one and so drop the currently received data. - instead of testing multiple times if the device is gone we rely one the status field which is set to -ENOSYS in case the channel is going down and incomplete requests are purged. cpdma_chan_stop() removes most of the packages with -ENOSYS. The currently active packet which is removed has the "tear down" bit set. So if that bit is set, we send ENOSYS as well otherwise we pass the status bits which are required to figure out which of the two possible just finished. Acked-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c33
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c7
2 files changed, 19 insertions, 21 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 05f11b854d0a..a066c41beac7 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -468,43 +468,36 @@ void cpsw_tx_handler(void *token, int len, int status)
468void cpsw_rx_handler(void *token, int len, int status) 468void cpsw_rx_handler(void *token, int len, int status)
469{ 469{
470 struct sk_buff *skb = token; 470 struct sk_buff *skb = token;
471 struct sk_buff *new_skb;
471 struct net_device *ndev = skb->dev; 472 struct net_device *ndev = skb->dev;
472 struct cpsw_priv *priv = netdev_priv(ndev); 473 struct cpsw_priv *priv = netdev_priv(ndev);
473 int ret = 0; 474 int ret = 0;
474 475
475 cpsw_dual_emac_src_port_detect(status, priv, ndev, skb); 476 cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
476 477
477 /* free and bail if we are shutting down */ 478 if (unlikely(status < 0)) {
478 if (unlikely(!netif_running(ndev)) || 479 /* the interface is going down, skbs are purged */
479 unlikely(!netif_carrier_ok(ndev))) {
480 dev_kfree_skb_any(skb); 480 dev_kfree_skb_any(skb);
481 return; 481 return;
482 } 482 }
483 if (likely(status >= 0)) { 483
484 new_skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max);
485 if (new_skb) {
484 skb_put(skb, len); 486 skb_put(skb, len);
485 cpts_rx_timestamp(priv->cpts, skb); 487 cpts_rx_timestamp(priv->cpts, skb);
486 skb->protocol = eth_type_trans(skb, ndev); 488 skb->protocol = eth_type_trans(skb, ndev);
487 netif_receive_skb(skb); 489 netif_receive_skb(skb);
488 priv->stats.rx_bytes += len; 490 priv->stats.rx_bytes += len;
489 priv->stats.rx_packets++; 491 priv->stats.rx_packets++;
490 skb = NULL; 492 } else {
491 } 493 priv->stats.rx_dropped++;
492 494 new_skb = skb;
493 if (unlikely(!netif_running(ndev))) {
494 if (skb)
495 dev_kfree_skb_any(skb);
496 return;
497 } 495 }
498 496
499 if (likely(!skb)) { 497 ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data,
500 skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max); 498 skb_tailroom(new_skb), 0);
501 if (WARN_ON(!skb)) 499 if (WARN_ON(ret < 0))
502 return; 500 dev_kfree_skb_any(new_skb);
503
504 ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
505 skb_tailroom(skb), 0);
506 }
507 WARN_ON(ret < 0);
508} 501}
509 502
510static irqreturn_t cpsw_interrupt(int irq, void *dev_id) 503static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 3cc20e7da01b..6b0a89f6f6a5 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -776,6 +776,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
776 struct cpdma_ctlr *ctlr = chan->ctlr; 776 struct cpdma_ctlr *ctlr = chan->ctlr;
777 struct cpdma_desc __iomem *desc; 777 struct cpdma_desc __iomem *desc;
778 int status, outlen; 778 int status, outlen;
779 int cb_status = 0;
779 struct cpdma_desc_pool *pool = ctlr->pool; 780 struct cpdma_desc_pool *pool = ctlr->pool;
780 dma_addr_t desc_dma; 781 dma_addr_t desc_dma;
781 unsigned long flags; 782 unsigned long flags;
@@ -811,8 +812,12 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
811 } 812 }
812 813
813 spin_unlock_irqrestore(&chan->lock, flags); 814 spin_unlock_irqrestore(&chan->lock, flags);
815 if (unlikely(status & CPDMA_DESC_TD_COMPLETE))
816 cb_status = -ENOSYS;
817 else
818 cb_status = status;
814 819
815 __cpdma_chan_free(chan, desc, outlen, status); 820 __cpdma_chan_free(chan, desc, outlen, cb_status);
816 return status; 821 return status;
817 822
818unlock_ret: 823unlock_ret: