diff mbox series

[1/2] dma-heap: add device link and unlink functions

Message ID 20230123123756.401692-2-christian.koenig@amd.com (mailing list archive)
State New, archived
Headers show
Series [1/2] dma-heap: add device link and unlink functions | expand

Commit Message

Christian König Jan. 23, 2023, 12:37 p.m. UTC
This allows device drivers to specify a DMA-heap where they want their
buffers to be allocated from. This information is then exposed as
sysfs link between the device and the DMA-heap.

Useful for userspace when in need to decide from which provider to
allocate a buffer.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/dma-buf/dma-heap.c | 41 ++++++++++++++++++++++++++++++--------
 include/linux/dma-heap.h   | 35 ++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 8 deletions(-)

Comments

John Stultz Jan. 24, 2023, 4:45 a.m. UTC | #1
On Mon, Jan 23, 2023 at 4:38 AM Christian König
<ckoenig.leichtzumerken@gmail.com> wrote:
>
> This allows device drivers to specify a DMA-heap where they want their
> buffers to be allocated from. This information is then exposed as
> sysfs link between the device and the DMA-heap.
>
> Useful for userspace when in need to decide from which provider to
> allocate a buffer.
>
> Signed-off-by: Christian König <christian.koenig@amd.com>

Hey Christian!
  Thanks so much for sending this out and also thanks for including me
(Adding TJ as well)!

This looks like a really interesting approach, but I have a few thoughts below.

> ---
>  drivers/dma-buf/dma-heap.c | 41 ++++++++++++++++++++++++++++++--------
>  include/linux/dma-heap.h   | 35 ++++++++++++++++++++++++++++++++
>  2 files changed, 68 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> index c9e41e8a9e27..0f7cf713c22f 100644
> --- a/drivers/dma-buf/dma-heap.c
> +++ b/drivers/dma-buf/dma-heap.c
> @@ -31,6 +31,7 @@
>   * @heap_devt          heap device node
>   * @list               list head connecting to list of heaps
>   * @heap_cdev          heap char device
> + * @dev:               heap device in sysfs
>   *
>   * Represents a heap of memory from which buffers can be made.
>   */
> @@ -41,6 +42,7 @@ struct dma_heap {
>         dev_t heap_devt;
>         struct list_head list;
>         struct cdev heap_cdev;
> +       struct device *dev;
>  };
>
>  static LIST_HEAD(heap_list);
> @@ -49,6 +51,33 @@ static dev_t dma_heap_devt;
>  static struct class *dma_heap_class;
>  static DEFINE_XARRAY_ALLOC(dma_heap_minors);
>
> +int dma_heap_create_device_link(struct device *dev, const char *heap)
> +{
> +       struct dma_heap *h;
> +
> +       /* check the name is valid */
> +       mutex_lock(&heap_list_lock);
> +       list_for_each_entry(h, &heap_list, list) {
> +               if (!strcmp(h->name, heap))
> +                       break;
> +       }
> +       mutex_unlock(&heap_list_lock);
> +
> +       if (list_entry_is_head(h, &heap_list, list)) {
> +               pr_err("dma_heap: Link to invalid heap requested %s\n", heap);
> +               return -EINVAL;
> +       }
> +
> +       return sysfs_create_link(&dev->kobj, &h->dev->kobj, DEVNAME);
> +}

So, one concern with this (if I'm reading this right) is it seems like
a single heap link may be insufficient.

There may be multiple heaps that a driver could work with (especially
if the device isn't very constrained), so when sharing a buffer with a
second device that is more constrained we'd have the same problem we
have now where userspace just needs to know which device is the more
constrained one to allocate for.

So it might be useful to have a sysfs "dma_heaps" directory with the
supported heaps linked from there? That way userland could find across
the various devices the heap-link that was common.

This still has the downside that every driver needs to be aware of
every heap, and when new heaps are added, it may take awhile before
folks might be able to assess if a device is compatible or not to
update it, so I suspect we'll have eventually some loose
constraint-based helpers to register links. But I think this at least
moves us in a workable direction, so again, I'm really glad to see you
send this out!

thanks
-john
diff mbox series

Patch

diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
index c9e41e8a9e27..0f7cf713c22f 100644
--- a/drivers/dma-buf/dma-heap.c
+++ b/drivers/dma-buf/dma-heap.c
@@ -31,6 +31,7 @@ 
  * @heap_devt		heap device node
  * @list		list head connecting to list of heaps
  * @heap_cdev		heap char device
+ * @dev:		heap device in sysfs
  *
  * Represents a heap of memory from which buffers can be made.
  */
@@ -41,6 +42,7 @@  struct dma_heap {
 	dev_t heap_devt;
 	struct list_head list;
 	struct cdev heap_cdev;
+	struct device *dev;
 };
 
 static LIST_HEAD(heap_list);
@@ -49,6 +51,33 @@  static dev_t dma_heap_devt;
 static struct class *dma_heap_class;
 static DEFINE_XARRAY_ALLOC(dma_heap_minors);
 
+int dma_heap_create_device_link(struct device *dev, const char *heap)
+{
+	struct dma_heap *h;
+
+	/* check the name is valid */
+	mutex_lock(&heap_list_lock);
+	list_for_each_entry(h, &heap_list, list) {
+		if (!strcmp(h->name, heap))
+			break;
+	}
+	mutex_unlock(&heap_list_lock);
+
+	if (list_entry_is_head(h, &heap_list, list)) {
+		pr_err("dma_heap: Link to invalid heap requested %s\n", heap);
+		return -EINVAL;
+	}
+
+	return sysfs_create_link(&dev->kobj, &h->dev->kobj, DEVNAME);
+}
+EXPORT_SYMBOL(dma_heap_create_device_link);
+
+void dma_heap_remove_device_link(struct device *dev)
+{
+	sysfs_remove_link(&dev->kobj, DEVNAME);
+}
+EXPORT_SYMBOL(dma_heap_remove_device_link);
+
 static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
 				 unsigned int fd_flags,
 				 unsigned int heap_flags)
@@ -219,7 +248,6 @@  const char *dma_heap_get_name(struct dma_heap *heap)
 struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
 {
 	struct dma_heap *heap, *h, *err_ret;
-	struct device *dev_ret;
 	unsigned int minor;
 	int ret;
 
@@ -261,14 +289,11 @@  struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
 		goto err1;
 	}
 
-	dev_ret = device_create(dma_heap_class,
-				NULL,
-				heap->heap_devt,
-				NULL,
-				heap->name);
-	if (IS_ERR(dev_ret)) {
+	heap->dev = device_create(dma_heap_class, NULL, heap->heap_devt, NULL,
+				  heap->name);
+	if (IS_ERR(heap->dev)) {
 		pr_err("dma_heap: Unable to create device\n");
-		err_ret = ERR_CAST(dev_ret);
+		err_ret = ERR_CAST(heap->dev);
 		goto err2;
 	}
 
diff --git a/include/linux/dma-heap.h b/include/linux/dma-heap.h
index 0c05561cad6e..097076766496 100644
--- a/include/linux/dma-heap.h
+++ b/include/linux/dma-heap.h
@@ -65,4 +65,39 @@  const char *dma_heap_get_name(struct dma_heap *heap);
  */
 struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info);
 
+#ifdef CONFIG_DMABUF_HEAPS
+
+/**
+ * dma_heap_create_device_link() - add link between device and heap
+ * @dev: the device which should be linked to a heap
+ * @heap: name of the heap to link to
+ *
+ * Add a sysfs link between a device and a DMA-heap. This link can then be used
+ * by userspace to figure out from which DMA-heap a device wants it's buffers
+ * to be allocated.
+ */
+int dma_heap_create_device_link(struct device *dev, const char *heap);
+
+/**
+ * dma_heap_remove_device_link() - remove link between device and heap
+ * @dev: the device which should be unlinked
+ *
+ * Removes the sysfs link between the device and it's DMA-heap again when a
+ * driver is unloaded.
+ */
+void dma_heap_remove_device_link(struct device *dev);
+
+#else
+
+int dma_heap_create_device_link(struct device *dev, const char *heap)
+{
+	return 0;
+}
+
+void dma_heap_remove_device_link(struct device *dev)
+{
+}
+
+#endif
+
 #endif /* _DMA_HEAPS_H */