drm/prime: Support dedicated DMA device for dma-buf imports

Importing dma-bufs via PRIME requires a DMA-capable device. Devices on
peripheral busses, such as USB, often cannot perform DMA by themselves.
Without DMA-capable device PRIME import fails. DRM drivers for USB
devices already use a separate DMA device for dma-buf imports. Make the
mechanism generally available.

Besides the case of USB, there are embedded DRM devices without DMA
capability. DMA is performed by a separate controller. DRM drivers should
set this accordingly.

Add the field dma_dev to struct drm_device to refer to the device's DMA
device. For USB this should be the USB controller. Use dma_dev in the
PRIME import helpers, if set.

v2:
- acquire internal reference on dma_dev (Jani)
- add DMA-controller usecase to docs (Maxime)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20250307080836.42848-2-tzimmermann@suse.de
This commit is contained in:
Thomas Zimmermann 2025-03-07 09:03:59 +01:00
parent c6a84bc969
commit 143ec8d3f9
3 changed files with 63 additions and 1 deletions

View file

@ -500,6 +500,25 @@ void drm_dev_unplug(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_dev_unplug);
/**
* drm_dev_set_dma_dev - set the DMA device for a DRM device
* @dev: DRM device
* @dma_dev: DMA device or NULL
*
* Sets the DMA device of the given DRM device. Only required if
* the DMA device is different from the DRM device's parent. After
* calling this function, the DRM device holds a reference on
* @dma_dev. Pass NULL to clear the DMA device.
*/
void drm_dev_set_dma_dev(struct drm_device *dev, struct device *dma_dev)
{
dma_dev = get_device(dma_dev);
put_device(dev->dma_dev);
dev->dma_dev = dma_dev;
}
EXPORT_SYMBOL(drm_dev_set_dma_dev);
/*
* Available recovery methods for wedged device. To be sent along with device
* wedged uevent.
@ -654,6 +673,8 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)
{
drm_fs_inode_free(dev->anon_inode);
put_device(dev->dma_dev);
dev->dma_dev = NULL;
put_device(dev->dev);
/* Prevent use-after-free in drm_managed_release when debugging is
* enabled. Slightly awkward, but can't really be helped. */

View file

@ -997,7 +997,7 @@ EXPORT_SYMBOL(drm_gem_prime_import_dev);
struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
struct dma_buf *dma_buf)
{
return drm_gem_prime_import_dev(dev, dma_buf, dev->dev);
return drm_gem_prime_import_dev(dev, dma_buf, drm_dev_dma_dev(dev));
}
EXPORT_SYMBOL(drm_gem_prime_import);

View file

@ -64,6 +64,28 @@ struct drm_device {
/** @dev: Device structure of bus-device */
struct device *dev;
/**
* @dma_dev:
*
* Device for DMA operations. Only required if the device @dev
* cannot perform DMA by itself. Should be NULL otherwise. Call
* drm_dev_dma_dev() to get the DMA device instead of using this
* field directly. Call drm_dev_set_dma_dev() to set this field.
*
* DRM devices are sometimes bound to virtual devices that cannot
* perform DMA by themselves. Drivers should set this field to the
* respective DMA controller.
*
* Devices on USB and other peripheral busses also cannot perform
* DMA by themselves. The @dma_dev field should point the bus
* controller that does DMA on behalve of such a device. Required
* for importing buffers via dma-buf.
*
* If set, the DRM core automatically releases the reference on the
* device.
*/
struct device *dma_dev;
/**
* @managed:
*
@ -327,4 +349,23 @@ struct drm_device {
struct dentry *debugfs_root;
};
void drm_dev_set_dma_dev(struct drm_device *dev, struct device *dma_dev);
/**
* drm_dev_dma_dev - returns the DMA device for a DRM device
* @dev: DRM device
*
* Returns the DMA device of the given DRM device. By default, this
* the DRM device's parent. See drm_dev_set_dma_dev().
*
* Returns:
* A DMA-capable device for the DRM device.
*/
static inline struct device *drm_dev_dma_dev(struct drm_device *dev)
{
if (dev->dma_dev)
return dev->dma_dev;
return dev->dev;
}
#endif