diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 999fb72688d226317d0565c936a286386ae6dd98..411232f07c3ff4ab4319388f71a556435ff8ec9f 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -699,6 +699,28 @@ static void cpsw_rx_handler(void *token, int len, int status) cpsw_dual_emac_src_port_detect(status, priv, ndev, skb); if (unlikely(status < 0) || unlikely(!netif_running(ndev))) { + bool ndev_status = false; + struct cpsw_slave *slave = priv->slaves; + int n; + + if (priv->data.dual_emac) { + /* In dual emac mode check for all interfaces */ + for (n = priv->data.slaves; n; n--, slave++) + if (netif_running(slave->ndev)) + ndev_status = true; + } + + if (ndev_status && (status >= 0)) { + /* The packet received is for the interface which + * is already down and the other interface is up + * and running, intead of freeing which results + * in reducing of the number of rx descriptor in + * DMA engine, requeue skb back to cpdma. + */ + new_skb = skb; + goto requeue; + } + /* the interface is going down, skbs are purged */ dev_kfree_skb_any(skb); return; @@ -717,6 +739,7 @@ static void cpsw_rx_handler(void *token, int len, int status) new_skb = skb; } +requeue: ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data, skb_tailroom(new_skb), 0); if (WARN_ON(ret < 0))