diff mbox

[3/3] sh_eth: Fix dma mapping issue

Message ID 1415862301-28032-4-git-send-email-ykaneko0929@gmail.com (mailing list archive)
State Changes Requested
Delegated to: Geert Uytterhoeven
Headers show

Commit Message

Yoshihiro Kaneko Nov. 13, 2014, 7:05 a.m. UTC
From: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>

When CONFIG_DMA_API_DEBUG=y, many DMA error messages reports.
In order to use DMA debug, This patch fix following issues.

Issue 1:
If dma_mapping_error function is not called appropriately after
DMA mapping, DMA debug will report error message when DMA unmap
function is called.

Issue 2:
If skb_reserve function is called after DMA mapping, the relationship
between mapping addr and mapping size will be broken.
In this case, DMA debug will report error messages when DMA sync
function and DMA unmap function are called.

Issue 3:
If the size of frame data is less than ETH_ZLEN, the size is resized
to ETH_ZLEN after DMA map function is called.
In the TX skb freeing function, dma unmap function is called with that
resized value. So, unmap size error will reported.

Issue 4:
In the rx function, DMA map function is called without DMA unmap function
is called for RX skb reallocating.
It will case the DMA debug error that number of debug entry is full and
DMA debug logic is stopped.

Signed-off-by: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>
---
 drivers/net/ethernet/renesas/sh_eth.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

Comments

Sergei Shtylyov Nov. 13, 2014, 11:05 p.m. UTC | #1
On 11/13/2014 10:05 AM, Yoshihiro Kaneko wrote:

> From: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>

> When CONFIG_DMA_API_DEBUG=y, many DMA error messages reports.
> In order to use DMA debug, This patch fix following issues.

> Issue 1:
> If dma_mapping_error function is not called appropriately after
> DMA mapping, DMA debug will report error message when DMA unmap
> function is called.

> Issue 2:
> If skb_reserve function is called after DMA mapping, the relationship
> between mapping addr and mapping size will be broken.
> In this case, DMA debug will report error messages when DMA sync
> function and DMA unmap function are called.

> Issue 3:
> If the size of frame data is less than ETH_ZLEN, the size is resized
> to ETH_ZLEN after DMA map function is called.
> In the TX skb freeing function, dma unmap function is called with that
> resized value. So, unmap size error will reported.

> Issue 4:
> In the rx function, DMA map function is called without DMA unmap function
> is called for RX skb reallocating.
> It will case the DMA debug error that number of debug entry is full and
> DMA debug logic is stopped.

    The rule of thumb is "fix one issue per patch". Please split accordingly.

> Signed-off-by: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
> Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>

    Thanks for beating me to it. Fixing these issues has been on my agenda for 
a long time... :-)

> ---
>   drivers/net/ethernet/renesas/sh_eth.c | 26 +++++++++++++++++++++++---
>   1 file changed, 23 insertions(+), 3 deletions(-)

> diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
> index 0e4a407..23318cf 100644
> --- a/drivers/net/ethernet/renesas/sh_eth.c
> +++ b/drivers/net/ethernet/renesas/sh_eth.c
> @@ -1136,6 +1136,11 @@ static void sh_eth_ring_format(struct net_device *ndev)
>   		dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
>   			       DMA_FROM_DEVICE);
>   		rxdesc->addr = virt_to_phys(skb->data);

    Can't we get rid of these bogus virt_to_phys() calls, while at it? 
dma_map_single() returns a DMA address, no?

> +		if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
> +			dev_kfree_skb(mdp->rx_skbuff[i]);
> +			mdp->rx_skbuff[i] = NULL;
> +			break;
> +		}
>   		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
>
>   		/* Rx descriptor address set */
> @@ -1364,7 +1369,7 @@ static int sh_eth_txfree(struct net_device *ndev)
>   		if (mdp->tx_skbuff[entry]) {
>   			dma_unmap_single(&ndev->dev, txdesc->addr,
>   					 txdesc->buffer_length, DMA_TO_DEVICE);
> -			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
> +			dev_kfree_skb_any(mdp->tx_skbuff[entry]);

    Hm, I'm not sure where is this described in the changelog...

>   			mdp->tx_skbuff[entry] = NULL;
>   			free_num++;
>   		}
> @@ -1466,11 +1471,19 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
>   			if (skb == NULL)
>   				break;	/* Better luck next round. */
>   			sh_eth_set_receive_align(skb);
> +			dma_unmap_single(&ndev->dev, rxdesc->addr,
> +					 rxdesc->buffer_length,
> +					 DMA_FROM_DEVICE);
>   			dma_map_single(&ndev->dev, skb->data,
>   				       rxdesc->buffer_length, DMA_FROM_DEVICE);
>
>   			skb_checksum_none_assert(skb);
>   			rxdesc->addr = virt_to_phys(skb->data);

    Likewise, can we get rid of this bogu?

> +			if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
> +				dev_kfree_skb_any(mdp->rx_skbuff[entry]);
> +				mdp->rx_skbuff[entry] = NULL;
> +				break;
> +			}
>   		}
>   		if (entry >= mdp->num_rx_ring - 1)
>   			rxdesc->status |=
> @@ -2104,12 +2117,18 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
>   	if (!mdp->cd->hw_swap)
>   		sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
>   				 skb->len + 2);
> -	txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
> -				      DMA_TO_DEVICE);
>   	if (skb->len < ETH_ZLEN)
>   		txdesc->buffer_length = ETH_ZLEN;
>   	else
>   		txdesc->buffer_length = skb->len;
> +	txdesc->addr = dma_map_single(&ndev->dev, skb->data,
> +				      txdesc->buffer_length,
> +				      DMA_TO_DEVICE);
> +	if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
> +		dev_kfree_skb_any(mdp->tx_skbuff[entry]);
> +		mdp->tx_skbuff[entry] = NULL;
> +		goto out;

    Why not just *return*?!

[...]

WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Horman Nov. 17, 2014, 4:09 a.m. UTC | #2
Hi Sergei,

On Fri, Nov 14, 2014 at 02:05:44AM +0300, Sergei Shtylyov wrote:
> On 11/13/2014 10:05 AM, Yoshihiro Kaneko wrote:
> 
> >From: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
> 
> >When CONFIG_DMA_API_DEBUG=y, many DMA error messages reports.
> >In order to use DMA debug, This patch fix following issues.
> 
> >Issue 1:
> >If dma_mapping_error function is not called appropriately after
> >DMA mapping, DMA debug will report error message when DMA unmap
> >function is called.
> 
> >Issue 2:
> >If skb_reserve function is called after DMA mapping, the relationship
> >between mapping addr and mapping size will be broken.
> >In this case, DMA debug will report error messages when DMA sync
> >function and DMA unmap function are called.
> 
> >Issue 3:
> >If the size of frame data is less than ETH_ZLEN, the size is resized
> >to ETH_ZLEN after DMA map function is called.
> >In the TX skb freeing function, dma unmap function is called with that
> >resized value. So, unmap size error will reported.
> 
> >Issue 4:
> >In the rx function, DMA map function is called without DMA unmap function
> >is called for RX skb reallocating.
> >It will case the DMA debug error that number of debug entry is full and
> >DMA debug logic is stopped.
> 
>    The rule of thumb is "fix one issue per patch". Please split accordingly.
> 
> >Signed-off-by: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
> >Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>
> 
>    Thanks for beating me to it. Fixing these issues has been on my agenda
> for a long time... :-)

as this patch is somewhat involved and as you have pointed out needs a bit
of work I'm wondering if you could take it over.

> >---
> >  drivers/net/ethernet/renesas/sh_eth.c | 26 +++++++++++++++++++++++---
> >  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> >diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
> >index 0e4a407..23318cf 100644
> >--- a/drivers/net/ethernet/renesas/sh_eth.c
> >+++ b/drivers/net/ethernet/renesas/sh_eth.c
> >@@ -1136,6 +1136,11 @@ static void sh_eth_ring_format(struct net_device *ndev)
> >  		dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
> >  			       DMA_FROM_DEVICE);
> >  		rxdesc->addr = virt_to_phys(skb->data);
> 
>    Can't we get rid of these bogus virt_to_phys() calls, while at it?
> dma_map_single() returns a DMA address, no?
> 
> >+		if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
> >+			dev_kfree_skb(mdp->rx_skbuff[i]);
> >+			mdp->rx_skbuff[i] = NULL;
> >+			break;
> >+		}
> >  		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
> >
> >  		/* Rx descriptor address set */
> >@@ -1364,7 +1369,7 @@ static int sh_eth_txfree(struct net_device *ndev)
> >  		if (mdp->tx_skbuff[entry]) {
> >  			dma_unmap_single(&ndev->dev, txdesc->addr,
> >  					 txdesc->buffer_length, DMA_TO_DEVICE);
> >-			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
> >+			dev_kfree_skb_any(mdp->tx_skbuff[entry]);
> 
>    Hm, I'm not sure where is this described in the changelog...
> 
> >  			mdp->tx_skbuff[entry] = NULL;
> >  			free_num++;
> >  		}
> >@@ -1466,11 +1471,19 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
> >  			if (skb == NULL)
> >  				break;	/* Better luck next round. */
> >  			sh_eth_set_receive_align(skb);
> >+			dma_unmap_single(&ndev->dev, rxdesc->addr,
> >+					 rxdesc->buffer_length,
> >+					 DMA_FROM_DEVICE);
> >  			dma_map_single(&ndev->dev, skb->data,
> >  				       rxdesc->buffer_length, DMA_FROM_DEVICE);
> >
> >  			skb_checksum_none_assert(skb);
> >  			rxdesc->addr = virt_to_phys(skb->data);
> 
>    Likewise, can we get rid of this bogu?
> 
> >+			if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
> >+				dev_kfree_skb_any(mdp->rx_skbuff[entry]);
> >+				mdp->rx_skbuff[entry] = NULL;
> >+				break;
> >+			}
> >  		}
> >  		if (entry >= mdp->num_rx_ring - 1)
> >  			rxdesc->status |=
> >@@ -2104,12 +2117,18 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> >  	if (!mdp->cd->hw_swap)
> >  		sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
> >  				 skb->len + 2);
> >-	txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
> >-				      DMA_TO_DEVICE);
> >  	if (skb->len < ETH_ZLEN)
> >  		txdesc->buffer_length = ETH_ZLEN;
> >  	else
> >  		txdesc->buffer_length = skb->len;
> >+	txdesc->addr = dma_map_single(&ndev->dev, skb->data,
> >+				      txdesc->buffer_length,
> >+				      DMA_TO_DEVICE);
> >+	if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
> >+		dev_kfree_skb_any(mdp->tx_skbuff[entry]);
> >+		mdp->tx_skbuff[entry] = NULL;
> >+		goto out;
> 
>    Why not just *return*?!
> 
> [...]
> 
> WBR, Sergei
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sergei Shtylyov Nov. 25, 2014, 8:07 p.m. UTC | #3
Hello.

On 11/17/2014 07:09 AM, Simon Horman wrote:

>>> From: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>

>>> When CONFIG_DMA_API_DEBUG=y, many DMA error messages reports.
>>> In order to use DMA debug, This patch fix following issues.

>>> Issue 1:
>>> If dma_mapping_error function is not called appropriately after
>>> DMA mapping, DMA debug will report error message when DMA unmap
>>> function is called.

>>> Issue 2:
>>> If skb_reserve function is called after DMA mapping, the relationship
>>> between mapping addr and mapping size will be broken.
>>> In this case, DMA debug will report error messages when DMA sync
>>> function and DMA unmap function are called.

>>> Issue 3:
>>> If the size of frame data is less than ETH_ZLEN, the size is resized
>>> to ETH_ZLEN after DMA map function is called.
>>> In the TX skb freeing function, dma unmap function is called with that
>>> resized value. So, unmap size error will reported.

>>> Issue 4:
>>> In the rx function, DMA map function is called without DMA unmap function
>>> is called for RX skb reallocating.
>>> It will case the DMA debug error that number of debug entry is full and
>>> DMA debug logic is stopped.

>>     The rule of thumb is "fix one issue per patch". Please split accordingly.

>>> Signed-off-by: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
>>> Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>

>>     Thanks for beating me to it. Fixing these issues has been on my agenda
>> for a long time... :-)

> as this patch is somewhat involved and as you have pointed out needs a bit
> of work I'm wondering if you could take it over.

    Perhaps I could... but I'm busy with other stuff... not sure when can I 
get to it.

[...]

WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 0e4a407..23318cf 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -1136,6 +1136,11 @@  static void sh_eth_ring_format(struct net_device *ndev)
 		dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
 			       DMA_FROM_DEVICE);
 		rxdesc->addr = virt_to_phys(skb->data);
+		if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
+			dev_kfree_skb(mdp->rx_skbuff[i]);
+			mdp->rx_skbuff[i] = NULL;
+			break;
+		}
 		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
 		/* Rx descriptor address set */
@@ -1364,7 +1369,7 @@  static int sh_eth_txfree(struct net_device *ndev)
 		if (mdp->tx_skbuff[entry]) {
 			dma_unmap_single(&ndev->dev, txdesc->addr,
 					 txdesc->buffer_length, DMA_TO_DEVICE);
-			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
+			dev_kfree_skb_any(mdp->tx_skbuff[entry]);
 			mdp->tx_skbuff[entry] = NULL;
 			free_num++;
 		}
@@ -1466,11 +1471,19 @@  static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 			if (skb == NULL)
 				break;	/* Better luck next round. */
 			sh_eth_set_receive_align(skb);
+			dma_unmap_single(&ndev->dev, rxdesc->addr,
+					 rxdesc->buffer_length,
+					 DMA_FROM_DEVICE);
 			dma_map_single(&ndev->dev, skb->data,
 				       rxdesc->buffer_length, DMA_FROM_DEVICE);
 
 			skb_checksum_none_assert(skb);
 			rxdesc->addr = virt_to_phys(skb->data);
+			if (dma_mapping_error(&ndev->dev, rxdesc->addr)) {
+				dev_kfree_skb_any(mdp->rx_skbuff[entry]);
+				mdp->rx_skbuff[entry] = NULL;
+				break;
+			}
 		}
 		if (entry >= mdp->num_rx_ring - 1)
 			rxdesc->status |=
@@ -2104,12 +2117,18 @@  static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	if (!mdp->cd->hw_swap)
 		sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
 				 skb->len + 2);
-	txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
-				      DMA_TO_DEVICE);
 	if (skb->len < ETH_ZLEN)
 		txdesc->buffer_length = ETH_ZLEN;
 	else
 		txdesc->buffer_length = skb->len;
+	txdesc->addr = dma_map_single(&ndev->dev, skb->data,
+				      txdesc->buffer_length,
+				      DMA_TO_DEVICE);
+	if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
+		dev_kfree_skb_any(mdp->tx_skbuff[entry]);
+		mdp->tx_skbuff[entry] = NULL;
+		goto out;
+	}
 
 	if (entry >= mdp->num_tx_ring - 1)
 		txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
@@ -2121,6 +2140,7 @@  static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	if (!(sh_eth_read(ndev, EDTRR) & sh_eth_get_edtrr_trns(mdp)))
 		sh_eth_write(ndev, sh_eth_get_edtrr_trns(mdp), EDTRR);
 
+out:
 	return NETDEV_TX_OK;
 }