diff mbox

dpaa_eth: use correct device for DMA mapping API

Message ID 20170710151447.2814348-1-arnd@arndb.de
State New
Headers show

Commit Message

Arnd Bergmann July 10, 2017, 3:14 p.m. UTC
Geert Uytterhoeven ran into a build error without CONFIG_HAS_DMA,
as a result of the driver calling set_dma_ops(). While we can
fix the build error in the dma-mapping implementation, there is
another problem in this driver:

The configuration for the DMA is done by the platform code,
looking up information about the system from the device tree.
This copies the information only in an incomplete way, setting
the dma_map_ops and forcing a specific mask, but ignoring all
settings regarding IOMMU, coherence etc.

A better way to avoid the problem is to only ever pass a device
into the dma_mapping implementation that has been setup by the
platform code. In this case, that is the parent device, so we
can get that pointer at probe time. Fortunately, we already have
a pointer in the device specific structure for that, so we only
need to modify that.

Fixes: fb52728a9294 ("dpaa_eth: reuse the dma_ops provided by the FMan MAC device")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

---
Not tested, please see if this works before applying!
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

-- 
2.9.0

Comments

Geert Uytterhoeven July 10, 2017, 3:37 p.m. UTC | #1
Hi Arnd,

On Mon, Jul 10, 2017 at 5:14 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> Geert Uytterhoeven ran into a build error without CONFIG_HAS_DMA,

> as a result of the driver calling set_dma_ops(). While we can

> fix the build error in the dma-mapping implementation, there is

> another problem in this driver:

>

> The configuration for the DMA is done by the platform code,

> looking up information about the system from the device tree.

> This copies the information only in an incomplete way, setting

> the dma_map_ops and forcing a specific mask, but ignoring all

> settings regarding IOMMU, coherence etc.

>

> A better way to avoid the problem is to only ever pass a device

> into the dma_mapping implementation that has been setup by the

> platform code. In this case, that is the parent device, so we

> can get that pointer at probe time. Fortunately, we already have

> a pointer in the device specific structure for that, so we only

> need to modify that.


Thank you, that looks like a much better solution!

> Fixes: fb52728a9294 ("dpaa_eth: reuse the dma_ops provided by the FMan MAC device")

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>


Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>


> Not tested, please see if this works before applying!


Indeed, please test first.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Robin Murphy July 10, 2017, 3:55 p.m. UTC | #2
On 10/07/17 16:14, Arnd Bergmann wrote:
> Geert Uytterhoeven ran into a build error without CONFIG_HAS_DMA,

> as a result of the driver calling set_dma_ops(). While we can

> fix the build error in the dma-mapping implementation, there is

> another problem in this driver:

> 

> The configuration for the DMA is done by the platform code,

> looking up information about the system from the device tree.

> This copies the information only in an incomplete way, setting

> the dma_map_ops and forcing a specific mask, but ignoring all

> settings regarding IOMMU, coherence etc.

> 

> A better way to avoid the problem is to only ever pass a device

> into the dma_mapping implementation that has been setup by the

> platform code. In this case, that is the parent device, so we

> can get that pointer at probe time. Fortunately, we already have

> a pointer in the device specific structure for that, so we only

> need to modify that.

> 

> Fixes: fb52728a9294 ("dpaa_eth: reuse the dma_ops provided by the FMan MAC device")

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>


Acked-by: Robin Murphy <robin.murphy@arm.com>


Assuming all the DPAA subcomponents have the same DMA capabilities
(which to the best of my knowledge they probably do), this is a neater
approach than what I started a while back in the context of cleaning up
arch_setup_dma_ops() abuse. FWIW, that looked like this:

----->8-----
                goto err;
-----8<-----

We might possibly need to revisit this if and when the question of IOMMU
support in the fsl-mc driver comes up (all this stuff is completely
paged out of my head at the moment, so I'm not certain), but for now I
don't see any reason no to go with your patch.

Robin.

> ---

> Not tested, please see if this works before applying!

> ---

>  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 11 ++---------

>  1 file changed, 2 insertions(+), 9 deletions(-)

> 

> diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> index 757b873735a5..f7b0b928cd53 100644

> --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> @@ -2646,14 +2646,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)

>  	priv->buf_layout[RX].priv_data_size = DPAA_RX_PRIV_DATA_SIZE; /* Rx */

>  	priv->buf_layout[TX].priv_data_size = DPAA_TX_PRIV_DATA_SIZE; /* Tx */

>  

> -	/* device used for DMA mapping */

> -	set_dma_ops(dev, get_dma_ops(&pdev->dev));

> -	err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));

> -	if (err) {

> -		dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");

> -		goto dev_mask_failed;

> -	}

> -

>  	/* bp init */

>  	for (i = 0; i < DPAA_BPS_NUM; i++) {

>  		int err;

> @@ -2665,7 +2657,8 @@ static int dpaa_eth_probe(struct platform_device *pdev)

>  		dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM);

>  		/* avoid runtime computations by keeping the usable size here */

>  		dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size);

> -		dpaa_bps[i]->dev = dev;

> +		/* DMA operations are done on the platform-provided device */

> +		dpaa_bps[i]->dev = dev->parent;

>  

>  		err = dpaa_bp_alloc_pool(dpaa_bps[i]);

>  		if (err < 0) {

>diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index e2ca107f9d94..8eef0db5db30 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2539,10 +2539,9 @@ static int dpaa_eth_probe(struct platform_device
*pdev)
        priv->buf_layout[TX].priv_data_size = DPAA_TX_PRIV_DATA_SIZE; /*
Tx */

        /* device used for DMA mapping */
-       arch_setup_dma_ops(dev, 0, 0, NULL, false);
-       err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
+       err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
        if (err) {
-               dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
+               dev_err(dev, "dma_set_mask_and_coherent() failed\n");
                goto dev_mask_failed;
        }

diff --git a/drivers/net/ethernet/freescale/fman/mac.c
b/drivers/net/ethernet/freescale/fman/mac.c
index 0b31f8502ada..c81efbfa99c2 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -627,6 +627,10 @@ static struct platform_device
*dpaa_eth_add_device(int fman_id,
        if (ret)
                goto err;

+       ret = of_dma_configure(&pdev->dev, node);
+       if (ret)
+               goto err;
+
        ret = platform_device_add(pdev);
        if (ret)

Madalin Bucur July 11, 2017, 8:50 a.m. UTC | #3
> -----Original Message-----

> From: Arnd Bergmann [mailto:arnd@arndb.de]

> Sent: Monday, July 10, 2017 6:14 PM

> Subject: [PATCH] dpaa_eth: use correct device for DMA mapping API

> 

> Geert Uytterhoeven ran into a build error without CONFIG_HAS_DMA,

> as a result of the driver calling set_dma_ops(). While we can

> fix the build error in the dma-mapping implementation, there is

> another problem in this driver:

> 

> The configuration for the DMA is done by the platform code,

> looking up information about the system from the device tree.

> This copies the information only in an incomplete way, setting

> the dma_map_ops and forcing a specific mask, but ignoring all

> settings regarding IOMMU, coherence etc.

> 

> A better way to avoid the problem is to only ever pass a device

> into the dma_mapping implementation that has been setup by the

> platform code. In this case, that is the parent device, so we

> can get that pointer at probe time. Fortunately, we already have

> a pointer in the device specific structure for that, so we only

> need to modify that.

> 

> Fixes: fb52728a9294 ("dpaa_eth: reuse the dma_ops provided by the FMan MAC

> device")

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

> ---

> Not tested, please see if this works before applying!

> ---

>  drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 11 ++---------

>  1 file changed, 2 insertions(+), 9 deletions(-)

> 

> diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> index 757b873735a5..f7b0b928cd53 100644

> --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> @@ -2646,14 +2646,6 @@ static int dpaa_eth_probe(struct platform_device

> *pdev)

>  	priv->buf_layout[RX].priv_data_size = DPAA_RX_PRIV_DATA_SIZE; /* Rx

> */

>  	priv->buf_layout[TX].priv_data_size = DPAA_TX_PRIV_DATA_SIZE; /* Tx

> */

> 

> -	/* device used for DMA mapping */

> -	set_dma_ops(dev, get_dma_ops(&pdev->dev));

> -	err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));

> -	if (err) {

> -		dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");

> -		goto dev_mask_failed;

> -	}

> -

>  	/* bp init */

>  	for (i = 0; i < DPAA_BPS_NUM; i++) {

>  		int err;

> @@ -2665,7 +2657,8 @@ static int dpaa_eth_probe(struct platform_device

> *pdev)

>  		dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i,

> DPAA_BPS_NUM);

>  		/* avoid runtime computations by keeping the usable size here

> */

>  		dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size);

> -		dpaa_bps[i]->dev = dev;

> +		/* DMA operations are done on the platform-provided device */

> +		dpaa_bps[i]->dev = dev->parent;

> 

>  		err = dpaa_bp_alloc_pool(dpaa_bps[i]);

>  		if (err < 0) {

> --

> 2.9.0


Hi Arnd,

Thanks for looking into this, I've tested your fix, it seems to need more work:

[    0.894968]  platform: DMA map failed
[    0.898627]  platform: DMA map failed
[    0.902288]  platform: DMA map failed
[    0.905947]  platform: DMA map failed
[    0.909606]  platform: DMA map failed
[    0.913265]  platform: DMA map failed

You also missed this related change:

@@ -2806,7 +2799,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)
 		dpaa_bps_free(priv);
 bp_create_failed:
 fq_probe_failed:
-dev_mask_failed:
 mac_probe_failed:
 		dev_set_drvdata(dev, NULL);
 		free_netdev(net_dev);

I'll try to address your concern about performing the DMA mapping on a different
device than the one set up by the platform code.

Regards,
Madalin
Arnd Bergmann July 11, 2017, 9:18 a.m. UTC | #4
On Tue, Jul 11, 2017 at 10:50 AM, Madalin-cristian Bucur
<madalin.bucur@nxp.com> wrote:

> Hi Arnd,

>

> Thanks for looking into this, I've tested your fix, it seems to need more work:

>

> [    0.894968]  platform: DMA map failed

> [    0.898627]  platform: DMA map failed

> [    0.902288]  platform: DMA map failed

> [    0.905947]  platform: DMA map failed

> [    0.909606]  platform: DMA map failed

> [    0.913265]  platform: DMA map failed


I see: the assignment ended up after the first use, so ->dev was still
NULL here.

This should fix the problem you saw here:


> @@ -2806,7 +2799,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)

>                 dpaa_bps_free(priv);

>  bp_create_failed:

>  fq_probe_failed:

> -dev_mask_failed:

>  mac_probe_failed:

>                 dev_set_drvdata(dev, NULL);

>                 free_netdev(net_dev);

>

> I'll try to address your concern about performing the DMA mapping on a different

> device than the one set up by the platform code.


Thanks!

     Arnddiff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index f7b0b928cd53..988c0212ce7e 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2650,6 +2650,8 @@ static int dpaa_eth_probe(struct platform_device *pdev)
  for (i = 0; i < DPAA_BPS_NUM; i++) {
  int err;

+ /* DMA operations are done on the platform-provided device */
+ dpaa_bps[i]->dev = dev->parent;
  dpaa_bps[i] = dpaa_bp_alloc(dev);
  if (IS_ERR(dpaa_bps[i]))
  return PTR_ERR(dpaa_bps[i]);
@@ -2657,8 +2659,6 @@ static int dpaa_eth_probe(struct platform_device *pdev)
  dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM);
  /* avoid runtime computations by keeping the usable size here */
  dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size);
- /* DMA operations are done on the platform-provided device */
- dpaa_bps[i]->dev = dev->parent;

  err = dpaa_bp_alloc_pool(dpaa_bps[i]);
  if (err < 0) {

Madalin Bucur July 11, 2017, 2:22 p.m. UTC | #5
> -----Original Message-----

> From: arndbergmann@gmail.com [mailto:arndbergmann@gmail.com] On Behalf Of

> Arnd Bergmann

> Subject: Re: [PATCH] dpaa_eth: use correct device for DMA mapping API

> 

> On Tue, Jul 11, 2017 at 10:50 AM, Madalin-cristian Bucur

> <madalin.bucur@nxp.com> wrote:

> 

> > Hi Arnd,

> >

> > Thanks for looking into this, I've tested your fix, it seems to need

> more work:

> >

> > [    0.894968]  platform: DMA map failed

> > [    0.898627]  platform: DMA map failed

> > [    0.902288]  platform: DMA map failed

> > [    0.905947]  platform: DMA map failed

> > [    0.909606]  platform: DMA map failed

> > [    0.913265]  platform: DMA map failed

> 

> I see: the assignment ended up after the first use, so ->dev was still

> NULL here.

> 

> This should fix the problem you saw here:

> 

> diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> index f7b0b928cd53..988c0212ce7e 100644

> --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c

> @@ -2650,6 +2650,8 @@ static int dpaa_eth_probe(struct platform_device

> *pdev)

>   for (i = 0; i < DPAA_BPS_NUM; i++) {

>   int err;

> 

> + /* DMA operations are done on the platform-provided device */

> + dpaa_bps[i]->dev = dev->parent;

>   dpaa_bps[i] = dpaa_bp_alloc(dev);


Your new change de-references dpaa_bps[i] before it is set, this won't work either.

>   if (IS_ERR(dpaa_bps[i]))

>   return PTR_ERR(dpaa_bps[i]);

> @@ -2657,8 +2659,6 @@ static int dpaa_eth_probe(struct platform_device

> *pdev)

>   dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM);

>   /* avoid runtime computations by keeping the usable size here */

>   dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size);

> - /* DMA operations are done on the platform-provided device */

> - dpaa_bps[i]->dev = dev->parent;

> 

>   err = dpaa_bp_alloc_pool(dpaa_bps[i]);

>   if (err < 0) {

> 

> > @@ -2806,7 +2799,6 @@ static int dpaa_eth_probe(struct platform_device

> *pdev)

> >                 dpaa_bps_free(priv);

> >  bp_create_failed:

> >  fq_probe_failed:

> > -dev_mask_failed:

> >  mac_probe_failed:

> >                 dev_set_drvdata(dev, NULL);

> >                 free_netdev(net_dev);

> >

> > I'll try to address your concern about performing the DMA mapping on a

> different

> > device than the one set up by the platform code.

> 

> Thanks!

> 

>      Arnd
diff mbox

Patch

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 757b873735a5..f7b0b928cd53 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2646,14 +2646,6 @@  static int dpaa_eth_probe(struct platform_device *pdev)
 	priv->buf_layout[RX].priv_data_size = DPAA_RX_PRIV_DATA_SIZE; /* Rx */
 	priv->buf_layout[TX].priv_data_size = DPAA_TX_PRIV_DATA_SIZE; /* Tx */
 
-	/* device used for DMA mapping */
-	set_dma_ops(dev, get_dma_ops(&pdev->dev));
-	err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
-	if (err) {
-		dev_err(dev, "dma_coerce_mask_and_coherent() failed\n");
-		goto dev_mask_failed;
-	}
-
 	/* bp init */
 	for (i = 0; i < DPAA_BPS_NUM; i++) {
 		int err;
@@ -2665,7 +2657,8 @@  static int dpaa_eth_probe(struct platform_device *pdev)
 		dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM);
 		/* avoid runtime computations by keeping the usable size here */
 		dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size);
-		dpaa_bps[i]->dev = dev;
+		/* DMA operations are done on the platform-provided device */
+		dpaa_bps[i]->dev = dev->parent;
 
 		err = dpaa_bp_alloc_pool(dpaa_bps[i]);
 		if (err < 0) {