diff mbox

dpaa_eth: use correct device for DMA mapping API

Message ID 20170710151447.2814348-1-arnd@arndb.de
State RFC, archived
Delegated to: David Miller
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(-)

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
Madalin Bucur July 11, 2017, 8:50 a.m. UTC | #2
> -----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
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) {