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/[email protected]/ This lead to a discussion pointing to another attempt to solve the issue, by Christoph Hellwig : https://lore.kernel.org/lkml/[email protected]/ 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 <[email protected]> Signed-off-by: Maxime Chevallier <[email protected]> --- 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(-) 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 *); -- 2.20.1

