diff mbox series

driver core: platform: Allow using a dedicated dma_mask for platform_device

Message ID 20190628141550.22938-1-maxime.chevallier@bootlin.com (mailing list archive)
State New, archived
Headers show
Series driver core: platform: Allow using a dedicated dma_mask for platform_device | expand

Commit Message

Maxime Chevallier June 28, 2019, 2:15 p.m. UTC
This patch attempts to solve a long standing situation where
dev->dma_mask is a pointer to dev->dma_coherent_mask, meaning that any
change to the coherent mask will affect the streaming mask.

The API allows to use different values for both masks, but for now
platform_device built from DT will simply make the dma_mask point to the
coherent mask.

This is a problem on a least one driver, the PPv2 network driver, which
needs different streaming and coherent masks to overcome a HW
limitation. In this case, the issue is a performance degradation since
the streaming mask isn't as big as it ought to be, causing a lot of
buffer bounces.

There were previous attempts to fix this issue. One of them by Brian
Brooks, where the dma_mask is reallocated in the driver itself,
which wasn't considered to be the best approach :

https://lore.kernel.org/netdev/20180820024730.9147-1-brian.brooks@linaro.org/

This lead to a discussion pointing to another attempt to solve the issue,
by Christoph Hellwig :

https://lore.kernel.org/lkml/20180829062401.8701-2-hch@lst.de/

This more generic approach ended-up causing regressions on some mfd
drivers (the sm501 was one of the reports).

The current patch tries to be a bit less generic, and allows setting-up
the dma_mask for platform devices using a dedicated helper. In this case,
the dma_mask is allocated in struct platform_object, as suggested by
Russell King.

This helper is then used in platform_device creation code from the DT.

Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
Hi everyone,

This patch, if suitable, would require a lot of testing to detect
drivers that rely on the streaming mask being the same as the coherent
mask.

Thanks,

Maxime

 drivers/base/platform.c         | 17 +++++++++++++++++
 drivers/of/platform.c           |  7 +++++--
 include/linux/platform_device.h |  1 +
 3 files changed, 23 insertions(+), 2 deletions(-)

Comments

Greg KH June 29, 2019, 7:53 a.m. UTC | #1
On Fri, Jun 28, 2019 at 08:59:46AM -0700, Christoph Hellwig wrote:
> I'd much rather bite the bullet and make dev->dma_mask a scalar
> instead of a pointer.  The pointer causes way to much boiler plate code,
> and the semantics are way to subtile.  Below is a POV patch that
> compiles and boots with my usual x86 test config, and at least compiles
> with the arm and pmac32 defconfigs.  It probably breaks just about
> everything else, but should give us an idea what is involve in the
> switch:
> 
> ---
> >From ea73ba2d29f56ff6413066b10f018a671f2b26ac Mon Sep 17 00:00:00 2001
> From: Christoph Hellwig <hch@lst.de>
> Date: Fri, 28 Jun 2019 16:24:01 +0200
> Subject: device.h: make dma_mask a scalar instead of a pointer
> 
> Kill the dma_mask indirection to clean up the mess we acquired around
> it.

I have no objection to this at all.  I would love to see the indirection
go away.

thanks,

greg k-h
Maxime Chevallier July 1, 2019, 11:24 a.m. UTC | #2
Hi Christoph,

On Fri, 28 Jun 2019 08:59:46 -0700
Christoph Hellwig <hch@infradead.org> wrote:

>I'd much rather bite the bullet and make dev->dma_mask a scalar
>instead of a pointer.  The pointer causes way to much boiler plate code,
>and the semantics are way to subtile.

I agree that this the real solution, it just seemed a bit overwhelming
to me. I'll be happy to help with this though, now that you took a big
first step.

> Below is a POV patch that
>compiles and boots with my usual x86 test config, and at least compiles
>with the arm and pmac32 defconfigs.  It probably breaks just about
>everything else, but should give us an idea what is involve in the
>switch:

I'll test that on my boards too.

Thanks,

Maxime
Christoph Hellwig July 3, 2019, 5:21 p.m. UTC | #3
On Mon, Jul 01, 2019 at 01:24:39PM +0200, Maxime Chevallier wrote:
> I agree that this the real solution, it just seemed a bit overwhelming
> to me. I'll be happy to help with this though, now that you took a big
> first step.

I think the first step is to resurrect my original patch to default
to a 32-bit DMA mask for platform devices, as that will cut a lot
of crap from the platform device declarations.

IIRC the problem back then was that USB uses the fact that a DMA
mask exist to decide if it uses a DMA vs PIO path in the HCD core.

So I'll need some help from Greg or other USB folks to clean that up,
after that we can try to apply my patch again (preferably early in
the next merge window), and once that sticks clean up all the 32-bit
dma mask initialization for platform devices, and then turn the dma_mask
into a scalar.
diff mbox series

Patch

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4d1729853d1a..35e7bdb8576c 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -256,9 +256,26 @@  EXPORT_SYMBOL_GPL(platform_add_devices);
 
 struct platform_object {
 	struct platform_device pdev;
+	u64 dma_mask;
 	char name[];
 };
 
+/**
+ * platform_device_setup_dma_mask - Sets the dma_mask pointer
+ * @pdev: platform device to configure the device's mask
+ *
+ * Sets the dma_mask of the underlying device to point to a dedicated region,
+ * that belongs to the platform_device.
+ */
+void platform_device_setup_dma_mask(struct platform_device *pdev)
+{
+	struct platform_object *pa = container_of(pdev, struct platform_object,
+						  pdev);
+
+	pa->pdev.dev.dma_mask = &pa->dma_mask;
+}
+EXPORT_SYMBOL_GPL(platform_device_setup_dma_mask);
+
 /**
  * platform_device_put - destroy a platform device
  * @pdev: platform device to free
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 04ad312fd85b..4a6980e3356c 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -186,8 +186,11 @@  static struct platform_device *of_platform_device_create_pdata(
 		goto err_clear_flag;
 
 	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-	if (!dev->dev.dma_mask)
-		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+	if (!dev->dev.dma_mask) {
+		platform_device_setup_dma_mask(dev);
+		*dev->dev.dma_mask = dev->dev.coherent_dma_mask;
+	}
+
 	dev->dev.bus = &platform_bus_type;
 	dev->dev.platform_data = platform_data;
 	of_msi_configure(&dev->dev, dev->dev.of_node);
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index cc464850b71e..a95c2d224de9 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -181,6 +181,7 @@  extern int platform_device_add_properties(struct platform_device *pdev,
 extern int platform_device_add(struct platform_device *pdev);
 extern void platform_device_del(struct platform_device *pdev);
 extern void platform_device_put(struct platform_device *pdev);
+extern void platform_device_setup_dma_mask(struct platform_device *pdev);
 
 struct platform_driver {
 	int (*probe)(struct platform_device *);