All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
@ 2015-03-12 22:48 Petri Gynther
  2015-03-13  1:05 ` Florian Fainelli
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Petri Gynther @ 2015-03-12 22:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, f.fainelli, jaedon.shin

Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
Rx packet processing loop, after the current Rx packet has already been
passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
valid Rx buffer exists.

To eliminate this situation:
1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
   queue if a new replacement Rx skb can't be allocated and DMA-mapped.
   In this case, the data on the current Rx skb is effectively dropped.
2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
   Rx packet processing loop, so that the new replacement Rx skb is
   already in place before the current Rx skb is processed.

Signed-off-by: Petri Gynther <pgynther@google.com>
---
 drivers/net/ethernet/broadcom/genet/bcmgenet.c | 99 +++++++++++---------------
 1 file changed, 43 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index d3be1aeb..875967e 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1336,36 +1336,47 @@ out:
 	return ret;
 }
 
-
-static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, struct enet_cb *cb)
+static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv,
+					  struct enet_cb *cb)
 {
 	struct device *kdev = &priv->pdev->dev;
 	struct sk_buff *skb;
+	struct sk_buff *rx_skb;
 	dma_addr_t mapping;
-	int ret;
 
+	/* Allocate a new Rx skb */
 	skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT);
-	if (!skb)
-		return -ENOMEM;
+	if (!skb) {
+		priv->mib.alloc_rx_buff_failed++;
+		netif_err(priv, rx_err, priv->dev,
+			  "%s: Rx skb allocation failed\n", __func__);
+		return NULL;
+	}
 
-	/* a caller did not release this control block */
-	WARN_ON(cb->skb != NULL);
-	cb->skb = skb;
-	mapping = dma_map_single(kdev, skb->data,
-				 priv->rx_buf_len, DMA_FROM_DEVICE);
-	ret = dma_mapping_error(kdev, mapping);
-	if (ret) {
+	/* DMA-map the new Rx skb */
+	mapping = dma_map_single(kdev, skb->data, priv->rx_buf_len,
+				 DMA_FROM_DEVICE);
+	if (dma_mapping_error(kdev, mapping)) {
 		priv->mib.rx_dma_failed++;
-		bcmgenet_free_cb(cb);
+		dev_kfree_skb_any(skb);
 		netif_err(priv, rx_err, priv->dev,
-			  "%s DMA map failed\n", __func__);
-		return ret;
+			  "%s: Rx skb DMA mapping failed\n", __func__);
+		return NULL;
 	}
 
+	/* Grab the current Rx skb from the ring and DMA-unmap it */
+	rx_skb = cb->skb;
+	if (likely(rx_skb))
+		dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
+				 priv->rx_buf_len, DMA_FROM_DEVICE);
+
+	/* Put the new Rx skb on the ring */
+	cb->skb = skb;
 	dma_unmap_addr_set(cb, dma_addr, mapping);
 	dmadesc_set_addr(priv, cb->bd_addr, mapping);
 
-	return 0;
+	/* Return the current Rx skb to caller */
+	return rx_skb;
 }
 
 /* bcmgenet_desc_rx - descriptor based rx process.
@@ -1381,7 +1392,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
 	struct sk_buff *skb;
 	u32 dma_length_status;
 	unsigned long dma_flag;
-	int len, err;
+	int len;
 	unsigned int rxpktprocessed = 0, rxpkttoprocess;
 	unsigned int p_index;
 	unsigned int discards;
@@ -1419,26 +1430,14 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
 	while ((rxpktprocessed < rxpkttoprocess) &&
 	       (rxpktprocessed < budget)) {
 		cb = &priv->rx_cbs[ring->read_ptr];
-		skb = cb->skb;
+		skb = bcmgenet_rx_refill(priv, cb);
 
-		/* We do not have a backing SKB, so we do not have a
-		 * corresponding DMA mapping for this incoming packet since
-		 * bcmgenet_rx_refill always either has both skb and mapping or
-		 * none.
-		 */
 		if (unlikely(!skb)) {
 			dev->stats.rx_dropped++;
 			dev->stats.rx_errors++;
-			goto refill;
+			goto next;
 		}
 
-		/* Unmap the packet contents such that we can use the
-		 * RSV from the 64 bytes descriptor when enabled and save
-		 * a 32-bits register read
-		 */
-		dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
-				 priv->rx_buf_len, DMA_FROM_DEVICE);
-
 		if (!priv->desc_64b_en) {
 			dma_length_status =
 				dmadesc_get_length_status(priv, cb->bd_addr);
@@ -1465,10 +1464,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
 				  "dropping fragmented packet!\n");
 			dev->stats.rx_dropped++;
 			dev->stats.rx_errors++;
-			dev_kfree_skb_any(cb->skb);
-			cb->skb = NULL;
-			goto refill;
+			dev_kfree_skb_any(skb);
+			goto next;
 		}
+
 		/* report errors */
 		if (unlikely(dma_flag & (DMA_RX_CRC_ERROR |
 						DMA_RX_OV |
@@ -1487,11 +1486,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
 				dev->stats.rx_length_errors++;
 			dev->stats.rx_dropped++;
 			dev->stats.rx_errors++;
-
-			/* discard the packet and advance consumer index.*/
-			dev_kfree_skb_any(cb->skb);
-			cb->skb = NULL;
-			goto refill;
+			dev_kfree_skb_any(skb);
+			goto next;
 		} /* error packet */
 
 		chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
@@ -1524,17 +1520,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
 
 		/* Notify kernel */
 		napi_gro_receive(&priv->napi, skb);
-		cb->skb = NULL;
 		netif_dbg(priv, rx_status, dev, "pushed up to kernel\n");
 
-		/* refill RX path on the current control block */
-refill:
-		err = bcmgenet_rx_refill(priv, cb);
-		if (err) {
-			priv->mib.alloc_rx_buff_failed++;
-			netif_err(priv, rx_err, dev, "Rx refill failed\n");
-		}
-
+next:
 		rxpktprocessed++;
 		if (likely(ring->read_ptr < ring->end_ptr))
 			ring->read_ptr++;
@@ -1553,7 +1541,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
 				     struct bcmgenet_rx_ring *ring)
 {
 	struct enet_cb *cb;
-	int ret = 0;
+	struct sk_buff *skb;
 	int i;
 
 	netif_dbg(priv, hw, priv->dev, "%s\n", __func__);
@@ -1561,15 +1549,14 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
 	/* loop here for each buffer needing assign */
 	for (i = 0; i < ring->size; i++) {
 		cb = ring->cbs + i;
-		if (cb->skb)
-			continue;
-
-		ret = bcmgenet_rx_refill(priv, cb);
-		if (ret)
-			break;
+		skb = bcmgenet_rx_refill(priv, cb);
+		if (skb)
+			dev_kfree_skb_any(skb);
+		if (!cb->skb)
+			return -ENOMEM;
 	}
 
-	return ret;
+	return 0;
 }
 
 static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
  2015-03-12 22:48 [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill() Petri Gynther
@ 2015-03-13  1:05 ` Florian Fainelli
  2015-03-13  3:03 ` David Miller
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Florian Fainelli @ 2015-03-13  1:05 UTC (permalink / raw)
  To: Petri Gynther, netdev; +Cc: davem, jaedon.shin

On 12/03/15 15:48, Petri Gynther wrote:
> Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
> Rx packet processing loop, after the current Rx packet has already been
> passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
> to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
> valid Rx buffer exists.
> 
> To eliminate this situation:
> 1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
>    queue if a new replacement Rx skb can't be allocated and DMA-mapped.
>    In this case, the data on the current Rx skb is effectively dropped.
> 2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
>    Rx packet processing loop, so that the new replacement Rx skb is
>    already in place before the current Rx skb is processed.

This looks good at first glance, I will give this a try and report back,
thanks!

> 
> Signed-off-by: Petri Gynther <pgynther@google.com>
> ---
>  drivers/net/ethernet/broadcom/genet/bcmgenet.c | 99 +++++++++++---------------
>  1 file changed, 43 insertions(+), 56 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index d3be1aeb..875967e 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -1336,36 +1336,47 @@ out:
>  	return ret;
>  }
>  
> -
> -static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, struct enet_cb *cb)
> +static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv,
> +					  struct enet_cb *cb)
>  {
>  	struct device *kdev = &priv->pdev->dev;
>  	struct sk_buff *skb;
> +	struct sk_buff *rx_skb;
>  	dma_addr_t mapping;
> -	int ret;
>  
> +	/* Allocate a new Rx skb */
>  	skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT);
> -	if (!skb)
> -		return -ENOMEM;
> +	if (!skb) {
> +		priv->mib.alloc_rx_buff_failed++;
> +		netif_err(priv, rx_err, priv->dev,
> +			  "%s: Rx skb allocation failed\n", __func__);
> +		return NULL;
> +	}
>  
> -	/* a caller did not release this control block */
> -	WARN_ON(cb->skb != NULL);
> -	cb->skb = skb;
> -	mapping = dma_map_single(kdev, skb->data,
> -				 priv->rx_buf_len, DMA_FROM_DEVICE);
> -	ret = dma_mapping_error(kdev, mapping);
> -	if (ret) {
> +	/* DMA-map the new Rx skb */
> +	mapping = dma_map_single(kdev, skb->data, priv->rx_buf_len,
> +				 DMA_FROM_DEVICE);
> +	if (dma_mapping_error(kdev, mapping)) {
>  		priv->mib.rx_dma_failed++;
> -		bcmgenet_free_cb(cb);
> +		dev_kfree_skb_any(skb);
>  		netif_err(priv, rx_err, priv->dev,
> -			  "%s DMA map failed\n", __func__);
> -		return ret;
> +			  "%s: Rx skb DMA mapping failed\n", __func__);
> +		return NULL;
>  	}
>  
> +	/* Grab the current Rx skb from the ring and DMA-unmap it */
> +	rx_skb = cb->skb;
> +	if (likely(rx_skb))
> +		dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
> +				 priv->rx_buf_len, DMA_FROM_DEVICE);
> +
> +	/* Put the new Rx skb on the ring */
> +	cb->skb = skb;
>  	dma_unmap_addr_set(cb, dma_addr, mapping);
>  	dmadesc_set_addr(priv, cb->bd_addr, mapping);
>  
> -	return 0;
> +	/* Return the current Rx skb to caller */
> +	return rx_skb;
>  }
>  
>  /* bcmgenet_desc_rx - descriptor based rx process.
> @@ -1381,7 +1392,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
>  	struct sk_buff *skb;
>  	u32 dma_length_status;
>  	unsigned long dma_flag;
> -	int len, err;
> +	int len;
>  	unsigned int rxpktprocessed = 0, rxpkttoprocess;
>  	unsigned int p_index;
>  	unsigned int discards;
> @@ -1419,26 +1430,14 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
>  	while ((rxpktprocessed < rxpkttoprocess) &&
>  	       (rxpktprocessed < budget)) {
>  		cb = &priv->rx_cbs[ring->read_ptr];
> -		skb = cb->skb;
> +		skb = bcmgenet_rx_refill(priv, cb);
>  
> -		/* We do not have a backing SKB, so we do not have a
> -		 * corresponding DMA mapping for this incoming packet since
> -		 * bcmgenet_rx_refill always either has both skb and mapping or
> -		 * none.
> -		 */
>  		if (unlikely(!skb)) {
>  			dev->stats.rx_dropped++;
>  			dev->stats.rx_errors++;
> -			goto refill;
> +			goto next;
>  		}
>  
> -		/* Unmap the packet contents such that we can use the
> -		 * RSV from the 64 bytes descriptor when enabled and save
> -		 * a 32-bits register read
> -		 */
> -		dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
> -				 priv->rx_buf_len, DMA_FROM_DEVICE);
> -
>  		if (!priv->desc_64b_en) {
>  			dma_length_status =
>  				dmadesc_get_length_status(priv, cb->bd_addr);
> @@ -1465,10 +1464,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
>  				  "dropping fragmented packet!\n");
>  			dev->stats.rx_dropped++;
>  			dev->stats.rx_errors++;
> -			dev_kfree_skb_any(cb->skb);
> -			cb->skb = NULL;
> -			goto refill;
> +			dev_kfree_skb_any(skb);
> +			goto next;
>  		}
> +
>  		/* report errors */
>  		if (unlikely(dma_flag & (DMA_RX_CRC_ERROR |
>  						DMA_RX_OV |
> @@ -1487,11 +1486,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
>  				dev->stats.rx_length_errors++;
>  			dev->stats.rx_dropped++;
>  			dev->stats.rx_errors++;
> -
> -			/* discard the packet and advance consumer index.*/
> -			dev_kfree_skb_any(cb->skb);
> -			cb->skb = NULL;
> -			goto refill;
> +			dev_kfree_skb_any(skb);
> +			goto next;
>  		} /* error packet */
>  
>  		chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
> @@ -1524,17 +1520,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
>  
>  		/* Notify kernel */
>  		napi_gro_receive(&priv->napi, skb);
> -		cb->skb = NULL;
>  		netif_dbg(priv, rx_status, dev, "pushed up to kernel\n");
>  
> -		/* refill RX path on the current control block */
> -refill:
> -		err = bcmgenet_rx_refill(priv, cb);
> -		if (err) {
> -			priv->mib.alloc_rx_buff_failed++;
> -			netif_err(priv, rx_err, dev, "Rx refill failed\n");
> -		}
> -
> +next:
>  		rxpktprocessed++;
>  		if (likely(ring->read_ptr < ring->end_ptr))
>  			ring->read_ptr++;
> @@ -1553,7 +1541,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
>  				     struct bcmgenet_rx_ring *ring)
>  {
>  	struct enet_cb *cb;
> -	int ret = 0;
> +	struct sk_buff *skb;
>  	int i;
>  
>  	netif_dbg(priv, hw, priv->dev, "%s\n", __func__);
> @@ -1561,15 +1549,14 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
>  	/* loop here for each buffer needing assign */
>  	for (i = 0; i < ring->size; i++) {
>  		cb = ring->cbs + i;
> -		if (cb->skb)
> -			continue;
> -
> -		ret = bcmgenet_rx_refill(priv, cb);
> -		if (ret)
> -			break;
> +		skb = bcmgenet_rx_refill(priv, cb);
> +		if (skb)
> +			dev_kfree_skb_any(skb);
> +		if (!cb->skb)
> +			return -ENOMEM;
>  	}
>  
> -	return ret;
> +	return 0;
>  }
>  
>  static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
  2015-03-12 22:48 [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill() Petri Gynther
  2015-03-13  1:05 ` Florian Fainelli
@ 2015-03-13  3:03 ` David Miller
  2015-03-13 14:42 ` Jaedon Shin
  2015-03-13 18:28 ` Florian Fainelli
  3 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2015-03-13  3:03 UTC (permalink / raw)
  To: pgynther; +Cc: netdev, f.fainelli, jaedon.shin

From: Petri Gynther <pgynther@google.com>
Date: Thu, 12 Mar 2015 15:48:00 -0700 (PDT)

> Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
> Rx packet processing loop, after the current Rx packet has already been
> passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
> to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
> valid Rx buffer exists.
> 
> To eliminate this situation:
> 1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
>    queue if a new replacement Rx skb can't be allocated and DMA-mapped.
>    In this case, the data on the current Rx skb is effectively dropped.
> 2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
>    Rx packet processing loop, so that the new replacement Rx skb is
>    already in place before the current Rx skb is processed.
> 
> Signed-off-by: Petri Gynther <pgynther@google.com>

I'll apply this after Florian reports back about his testing.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
  2015-03-12 22:48 [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill() Petri Gynther
  2015-03-13  1:05 ` Florian Fainelli
  2015-03-13  3:03 ` David Miller
@ 2015-03-13 14:42 ` Jaedon Shin
  2015-03-13 18:28 ` Florian Fainelli
  3 siblings, 0 replies; 6+ messages in thread
From: Jaedon Shin @ 2015-03-13 14:42 UTC (permalink / raw)
  To: Petri Gynther; +Cc: netdev, davem, f.fainelli


> On Mar 13, 2015, at 7:48 AM, Petri Gynther <pgynther@google.com> wrote:
> 
> Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
> Rx packet processing loop, after the current Rx packet has already been
> passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
> to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
> valid Rx buffer exists.
> 
> To eliminate this situation:
> 1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
>   queue if a new replacement Rx skb can't be allocated and DMA-mapped.
>   In this case, the data on the current Rx skb is effectively dropped.
> 2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
>   Rx packet processing loop, so that the new replacement Rx skb is
>   already in place before the current Rx skb is processed.
> 
> Signed-off-by: Petri Gynther <pgynther@google.com>
> ---
> drivers/net/ethernet/broadcom/genet/bcmgenet.c | 99 +++++++++++---------------
> 1 file changed, 43 insertions(+), 56 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> index d3be1aeb..875967e 100644
> --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
> @@ -1336,36 +1336,47 @@ out:
> 	return ret;
> }
> 
> -
> -static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, struct enet_cb *cb)
> +static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv,
> +					  struct enet_cb *cb)
> {
> 	struct device *kdev = &priv->pdev->dev;
> 	struct sk_buff *skb;
> +	struct sk_buff *rx_skb;
> 	dma_addr_t mapping;
> -	int ret;
> 
> +	/* Allocate a new Rx skb */
> 	skb = netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT);
> -	if (!skb)
> -		return -ENOMEM;
> +	if (!skb) {
> +		priv->mib.alloc_rx_buff_failed++;
> +		netif_err(priv, rx_err, priv->dev,
> +			  "%s: Rx skb allocation failed\n", __func__);
> +		return NULL;
> +	}
> 
> -	/* a caller did not release this control block */
> -	WARN_ON(cb->skb != NULL);
> -	cb->skb = skb;
> -	mapping = dma_map_single(kdev, skb->data,
> -				 priv->rx_buf_len, DMA_FROM_DEVICE);
> -	ret = dma_mapping_error(kdev, mapping);
> -	if (ret) {
> +	/* DMA-map the new Rx skb */
> +	mapping = dma_map_single(kdev, skb->data, priv->rx_buf_len,
> +				 DMA_FROM_DEVICE);
> +	if (dma_mapping_error(kdev, mapping)) {
> 		priv->mib.rx_dma_failed++;
> -		bcmgenet_free_cb(cb);
> +		dev_kfree_skb_any(skb);
> 		netif_err(priv, rx_err, priv->dev,
> -			  "%s DMA map failed\n", __func__);
> -		return ret;
> +			  "%s: Rx skb DMA mapping failed\n", __func__);
> +		return NULL;
> 	}
> 
> +	/* Grab the current Rx skb from the ring and DMA-unmap it */
> +	rx_skb = cb->skb;
> +	if (likely(rx_skb))
> +		dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
> +				 priv->rx_buf_len, DMA_FROM_DEVICE);
> +
> +	/* Put the new Rx skb on the ring */
> +	cb->skb = skb;
> 	dma_unmap_addr_set(cb, dma_addr, mapping);
> 	dmadesc_set_addr(priv, cb->bd_addr, mapping);
> 
> -	return 0;
> +	/* Return the current Rx skb to caller */
> +	return rx_skb;
> }
> 
> /* bcmgenet_desc_rx - descriptor based rx process.
> @@ -1381,7 +1392,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
> 	struct sk_buff *skb;
> 	u32 dma_length_status;
> 	unsigned long dma_flag;
> -	int len, err;
> +	int len;
> 	unsigned int rxpktprocessed = 0, rxpkttoprocess;
> 	unsigned int p_index;
> 	unsigned int discards;
> @@ -1419,26 +1430,14 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
> 	while ((rxpktprocessed < rxpkttoprocess) &&
> 	       (rxpktprocessed < budget)) {
> 		cb = &priv->rx_cbs[ring->read_ptr];
> -		skb = cb->skb;
> +		skb = bcmgenet_rx_refill(priv, cb);
> 
> -		/* We do not have a backing SKB, so we do not have a
> -		 * corresponding DMA mapping for this incoming packet since
> -		 * bcmgenet_rx_refill always either has both skb and mapping or
> -		 * none.
> -		 */
> 		if (unlikely(!skb)) {
> 			dev->stats.rx_dropped++;
> 			dev->stats.rx_errors++;
> -			goto refill;
> +			goto next;
> 		}
> 
> -		/* Unmap the packet contents such that we can use the
> -		 * RSV from the 64 bytes descriptor when enabled and save
> -		 * a 32-bits register read
> -		 */
> -		dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
> -				 priv->rx_buf_len, DMA_FROM_DEVICE);
> -
> 		if (!priv->desc_64b_en) {
> 			dma_length_status =
> 				dmadesc_get_length_status(priv, cb->bd_addr);
> @@ -1465,10 +1464,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
> 				  "dropping fragmented packet!\n");
> 			dev->stats.rx_dropped++;
> 			dev->stats.rx_errors++;
> -			dev_kfree_skb_any(cb->skb);
> -			cb->skb = NULL;
> -			goto refill;
> +			dev_kfree_skb_any(skb);
> +			goto next;
> 		}
> +
> 		/* report errors */
> 		if (unlikely(dma_flag & (DMA_RX_CRC_ERROR |
> 						DMA_RX_OV |
> @@ -1487,11 +1486,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
> 				dev->stats.rx_length_errors++;
> 			dev->stats.rx_dropped++;
> 			dev->stats.rx_errors++;
> -
> -			/* discard the packet and advance consumer index.*/
> -			dev_kfree_skb_any(cb->skb);
> -			cb->skb = NULL;
> -			goto refill;
> +			dev_kfree_skb_any(skb);
> +			goto next;
> 		} /* error packet */
> 
> 		chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
> @@ -1524,17 +1520,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
> 
> 		/* Notify kernel */
> 		napi_gro_receive(&priv->napi, skb);
> -		cb->skb = NULL;
> 		netif_dbg(priv, rx_status, dev, "pushed up to kernel\n");
> 
> -		/* refill RX path on the current control block */
> -refill:
> -		err = bcmgenet_rx_refill(priv, cb);
> -		if (err) {
> -			priv->mib.alloc_rx_buff_failed++;
> -			netif_err(priv, rx_err, dev, "Rx refill failed\n");
> -		}
> -
> +next:
> 		rxpktprocessed++;
> 		if (likely(ring->read_ptr < ring->end_ptr))
> 			ring->read_ptr++;
> @@ -1553,7 +1541,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
> 				     struct bcmgenet_rx_ring *ring)
> {
> 	struct enet_cb *cb;
> -	int ret = 0;
> +	struct sk_buff *skb;
> 	int i;
> 
> 	netif_dbg(priv, hw, priv->dev, "%s\n", __func__);
> @@ -1561,15 +1549,14 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv,
> 	/* loop here for each buffer needing assign */
> 	for (i = 0; i < ring->size; i++) {
> 		cb = ring->cbs + i;
> -		if (cb->skb)
> -			continue;
> -
> -		ret = bcmgenet_rx_refill(priv, cb);
> -		if (ret)
> -			break;
> +		skb = bcmgenet_rx_refill(priv, cb);
> +		if (skb)
> +			dev_kfree_skb_any(skb);
> +		if (!cb->skb)
> +			return -ENOMEM;
> 	}
> 
> -	return ret;
> +	return 0;
> }
> 
> static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
> -- 
> 2.2.0.rc0.207.ga3a616c
> 

Tested-by: Jaedon Shin <jaedon.shin@gmail.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
  2015-03-12 22:48 [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill() Petri Gynther
                   ` (2 preceding siblings ...)
  2015-03-13 14:42 ` Jaedon Shin
@ 2015-03-13 18:28 ` Florian Fainelli
  2015-03-13 19:48   ` David Miller
  3 siblings, 1 reply; 6+ messages in thread
From: Florian Fainelli @ 2015-03-13 18:28 UTC (permalink / raw)
  To: Petri Gynther, netdev; +Cc: davem, jaedon.shin

On 12/03/15 15:48, Petri Gynther wrote:
> Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
> Rx packet processing loop, after the current Rx packet has already been
> passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
> to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
> valid Rx buffer exists.
> 
> To eliminate this situation:
> 1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
>    queue if a new replacement Rx skb can't be allocated and DMA-mapped.
>    In this case, the data on the current Rx skb is effectively dropped.
> 2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
>    Rx packet processing loop, so that the new replacement Rx skb is
>    already in place before the current Rx skb is processed.

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Tested-by: Florian Fainelli <f.fainelli@gmail.com>

Thanks! Have not noticed any performance impact doing 64B/1500B testing.
-- 
Florian

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill()
  2015-03-13 18:28 ` Florian Fainelli
@ 2015-03-13 19:48   ` David Miller
  0 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2015-03-13 19:48 UTC (permalink / raw)
  To: f.fainelli; +Cc: pgynther, netdev, jaedon.shin

From: Florian Fainelli <f.fainelli@gmail.com>
Date: Fri, 13 Mar 2015 11:28:52 -0700

> On 12/03/15 15:48, Petri Gynther wrote:
>> Currently, bcmgenet_desc_rx() calls bcmgenet_rx_refill() at the end of
>> Rx packet processing loop, after the current Rx packet has already been
>> passed to napi_gro_receive(). However, bcmgenet_rx_refill() might fail
>> to allocate a new Rx skb, thus leaving a hole on the Rx queue where no
>> valid Rx buffer exists.
>> 
>> To eliminate this situation:
>> 1. Rewrite bcmgenet_rx_refill() to retain the current Rx skb on the Rx
>>    queue if a new replacement Rx skb can't be allocated and DMA-mapped.
>>    In this case, the data on the current Rx skb is effectively dropped.
>> 2. Modify bcmgenet_desc_rx() to call bcmgenet_rx_refill() at the top of
>>    Rx packet processing loop, so that the new replacement Rx skb is
>>    already in place before the current Rx skb is processed.
> 
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
> Tested-by: Florian Fainelli <f.fainelli@gmail.com>
> 
> Thanks! Have not noticed any performance impact doing 64B/1500B testing.

Applied, thanks everyone.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-03-13 19:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-12 22:48 [PATCH net-next] net: bcmgenet: rewrite bcmgenet_rx_refill() Petri Gynther
2015-03-13  1:05 ` Florian Fainelli
2015-03-13  3:03 ` David Miller
2015-03-13 14:42 ` Jaedon Shin
2015-03-13 18:28 ` Florian Fainelli
2015-03-13 19:48   ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.