<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    Am 04.03.24 um 14:59 schrieb Paul Cercueil:<br>
    <blockquote type="cite" cite="mid:d17bd8aa17ac82773d0bdd6ce4edfe4a6249f179.camel@crapouillou.net">[SNIP]<span style="white-space: pre-wrap">
</span>
      <blockquote type="cite">
        <blockquote type="cite">
          <pre class="moz-quote-pre" wrap="">+        dma_to_ram = buffer->direction == IIO_BUFFER_DIRECTION_IN;
+
+       if (dma_to_ram) {
+               /*
+                * If we're writing to the DMABUF, make sure we
don't have
+                * readers
+                */
+               retl = dma_resv_wait_timeout(dmabuf->resv,
+                                            DMA_RESV_USAGE_READ,
true,
+                                            timeout);
+               if (retl == 0)
+                       retl = -EBUSY;
+               if (retl < 0) {
+                       ret = (int)retl;
+                       goto err_resv_unlock;
+               }
+       }
+
+       if (buffer->access->lock_queue)
+               buffer->access->lock_queue(buffer);
+
+       ret = dma_resv_reserve_fences(dmabuf->resv, 1);
+       if (ret)
+               goto err_queue_unlock;
+
+       dma_resv_add_fence(dmabuf->resv, &fence->base,
+                          dma_resv_usage_rw(dma_to_ram));
</pre>
        </blockquote>
        <pre class="moz-quote-pre" wrap="">
That is incorrect use of the function dma_resv_usage_rw(). That
function 
is for retrieving fences and not adding them.

See the function implementation and comments, when you use it like
this 
you get exactly what you don't want.
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
No, I get exactly what I want. If "dma_to_ram", I get
DMA_RESV_USAGE_READ, otherwise I get DMA_RESV_USAGE_WRITE.</pre>
    </blockquote>
    <br>
    Ah, so basically !dma_to_ram means that you have a write access to
    the buffer?<br>
    <br>
    <blockquote type="cite" cite="mid:d17bd8aa17ac82773d0bdd6ce4edfe4a6249f179.camel@crapouillou.net">
      <pre class="moz-quote-pre" wrap="">If you really don't like the macro, I can inline things here.</pre>
    </blockquote>
    <br>
    Yeah, that would still be incorrect use.<br>
    <br>
    The dma__resv_usage_rw() is for retrieving the fences to sync to for
    read and write operations and should never be used together with
    dma_fence_resv_add().<br>
    <br>
    Regards,<br>
    Christian.<br>
    <br>
    <blockquote type="cite" cite="mid:d17bd8aa17ac82773d0bdd6ce4edfe4a6249f179.camel@crapouillou.net">
      <pre class="moz-quote-pre" wrap="">

Cheers,
-Paul

</pre>
      <blockquote type="cite">
        <pre class="moz-quote-pre" wrap="">
Regards,
Christian.

</pre>
        <blockquote type="cite">
          <pre class="moz-quote-pre" wrap="">+        dma_resv_unlock(dmabuf->resv);
+
+       cookie = dma_fence_begin_signalling();
+
+       ret = buffer->access->enqueue_dmabuf(buffer, priv->block,
&fence->base,
+                                            priv->sgt,
iio_dmabuf.bytes_used,
+                                            cyclic);
+       if (ret) {
+               /*
+                * DMABUF enqueue failed, but we already added the
fence.
+                * Signal the error through the fence completion
mechanism.
+                */
+               iio_buffer_signal_dmabuf_done(&fence->base, ret);
+       }
+
+       if (buffer->access->unlock_queue)
+               buffer->access->unlock_queue(buffer);
+
+       dma_fence_end_signalling(cookie);
+       dma_buf_put(dmabuf);
+
+       return ret;
+
+err_queue_unlock:
+       if (buffer->access->unlock_queue)
+               buffer->access->unlock_queue(buffer);
+err_resv_unlock:
+       dma_resv_unlock(dmabuf->resv);
+err_fence_put:
+       dma_fence_put(&fence->base);
+err_attachment_put:
+       iio_buffer_dmabuf_put(attach);
+err_dmabuf_put:
+       dma_buf_put(dmabuf);
+
+       return ret;
+}
+
+static void iio_buffer_cleanup(struct work_struct *work)
+{
+       struct iio_dma_fence *fence =
+               container_of(work, struct iio_dma_fence, work);
+       struct iio_dmabuf_priv *priv = fence->priv;
+       struct dma_buf_attachment *attach = priv->attach;
+
+       dma_fence_put(&fence->base);
+       iio_buffer_dmabuf_put(attach);
+}
+
+void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int
ret)
+{
+       struct iio_dma_fence *iio_fence =
+               container_of(fence, struct iio_dma_fence, base);
+       bool cookie = dma_fence_begin_signalling();
+
+       /*
+        * Get a reference to the fence, so that it's not freed as
soon as
+        * it's signaled.
+        */
+       dma_fence_get(fence);
+
+       fence->error = ret;
+       dma_fence_signal(fence);
+       dma_fence_end_signalling(cookie);
+
+       /*
+        * The fence will be unref'd in iio_buffer_cleanup.
+        * It can't be done here, as the unref functions might try
to lock the
+        * resv object, which can deadlock.
+        */
+       INIT_WORK(&iio_fence->work, iio_buffer_cleanup);
+       schedule_work(&iio_fence->work);
+}
+EXPORT_SYMBOL_GPL(iio_buffer_signal_dmabuf_done);
+
+static long iio_buffer_chrdev_ioctl(struct file *filp,
+                                   unsigned int cmd, unsigned
long arg)
+{
+       struct iio_dev_buffer_pair *ib = filp->private_data;
+       void __user *_arg = (void __user *)arg;
+       bool nonblock = filp->f_flags & O_NONBLOCK;
+
+       switch (cmd) {
+       case IIO_BUFFER_DMABUF_ATTACH_IOCTL:
+               return iio_buffer_attach_dmabuf(ib, _arg,
nonblock);
+       case IIO_BUFFER_DMABUF_DETACH_IOCTL:
+               return iio_buffer_detach_dmabuf(ib, _arg,
nonblock);
+       case IIO_BUFFER_DMABUF_ENQUEUE_IOCTL:
+               return iio_buffer_enqueue_dmabuf(ib, _arg,
nonblock);
+       default:
+               return -EINVAL;
+       }
+}
+
  static const struct file_operations iio_buffer_chrdev_fileops = {
      .owner = THIS_MODULE,
      .llseek = noop_llseek,
      .read = iio_buffer_read,
      .write = iio_buffer_write,
+       .unlocked_ioctl = iio_buffer_chrdev_ioctl,
+       .compat_ioctl = compat_ptr_ioctl,
      .poll = iio_buffer_poll,
      .release = iio_buffer_chrdev_release,
  };
@@ -1953,6 +2414,7 @@ static void iio_buffer_release(struct kref
*ref)
  {
      struct iio_buffer *buffer = container_of(ref, struct
iio_buffer, ref);
  
+       mutex_destroy(&buffer->dmabufs_mutex);
      buffer->access->release(buffer);
  }
  
diff --git a/include/linux/iio/buffer_impl.h
b/include/linux/iio/buffer_impl.h
index 89c3fd7c29ca..f4b1147291e5 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -9,8 +9,12 @@
  #include <uapi/linux/iio/buffer.h>
  #include <linux/iio/buffer.h>
  
+struct dma_buf_attachment;
+struct dma_fence;
  struct iio_dev;
+struct iio_dma_buffer_block;
  struct iio_buffer;
+struct sg_table;
  
  /**
   * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the
buffer can not be
@@ -39,6 +43,13 @@ struct iio_buffer;
   *                      device stops sampling. Calles are
balanced with @enable.
   * @release:                called when the last reference to the
buffer is dropped,
   *                  should free all resources allocated by the
buffer.
+ * @attach_dmabuf:     called from userspace via ioctl to attach
one external
+ *                     DMABUF.
+ * @detach_dmabuf:     called from userspace via ioctl to detach
one previously
+ *                     attached DMABUF.
+ * @enqueue_dmabuf:    called from userspace via ioctl to queue
this DMABUF
+ *                     object to this buffer. Requires a valid
DMABUF fd, that
+ *                     was previouly attached to this buffer.
   * @modes:          Supported operating modes by this buffer
type
   * @flags:          A bitmask combination of
INDIO_BUFFER_FLAG_*
   *
@@ -68,6 +79,17 @@ struct iio_buffer_access_funcs {
  
      void (*release)(struct iio_buffer *buffer);
  
+       struct iio_dma_buffer_block * (*attach_dmabuf)(struct
iio_buffer *buffer,
+                                                      struct
dma_buf_attachment *attach);
+       void (*detach_dmabuf)(struct iio_buffer *buffer,
+                             struct iio_dma_buffer_block *block);
+       int (*enqueue_dmabuf)(struct iio_buffer *buffer,
+                             struct iio_dma_buffer_block *block,
+                             struct dma_fence *fence, struct
sg_table *sgt,
+                             size_t size, bool cyclic);
+       void (*lock_queue)(struct iio_buffer *buffer);
+       void (*unlock_queue)(struct iio_buffer *buffer);
+
      unsigned int modes;
      unsigned int flags;
  };
@@ -136,6 +158,12 @@ struct iio_buffer {
  
      /* @ref: Reference count of the buffer. */
      struct kref ref;
+
+       /* @dmabufs: List of DMABUF attachments */
+       struct list_head dmabufs; /* P: dmabufs_mutex */
+
+       /* @dmabufs_mutex: Protects dmabufs */
+       struct mutex dmabufs_mutex;
  };
  
  /**
@@ -156,9 +184,14 @@ int iio_update_buffers(struct iio_dev
*indio_dev,
   **/
  void iio_buffer_init(struct iio_buffer *buffer);
  
+void iio_buffer_dmabuf_get(struct dma_buf_attachment *attach);
+void iio_buffer_dmabuf_put(struct dma_buf_attachment *attach);
+
  struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer);
  void iio_buffer_put(struct iio_buffer *buffer);
  
+void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int
ret);
+
  #else /* CONFIG_IIO_BUFFER */
  
  static inline void iio_buffer_get(struct iio_buffer *buffer) {}
diff --git a/include/uapi/linux/iio/buffer.h
b/include/uapi/linux/iio/buffer.h
index 13939032b3f6..c666aa95e532 100644
--- a/include/uapi/linux/iio/buffer.h
+++ b/include/uapi/linux/iio/buffer.h
@@ -5,6 +5,28 @@
  #ifndef _UAPI_IIO_BUFFER_H_
  #define _UAPI_IIO_BUFFER_H_
  
+#include <linux/types.h>
+
+/* Flags for iio_dmabuf.flags */
+#define IIO_BUFFER_DMABUF_CYCLIC               (1 << 0)
+#define IIO_BUFFER_DMABUF_SUPPORTED_FLAGS      0x00000001
+
+/**
+ * struct iio_dmabuf - Descriptor for a single IIO DMABUF object
+ * @fd:                file descriptor of the DMABUF object
+ * @flags:     one or more IIO_BUFFER_DMABUF_* flags
+ * @bytes_used:        number of bytes used in this DMABUF for
the data transfer.
+ *             Should generally be set to the DMABUF's size.
+ */
+struct iio_dmabuf {
+       __u32 fd;
+       __u32 flags;
+       __u64 bytes_used;
+};
+
  #define IIO_BUFFER_GET_FD_IOCTL                  _IOWR('i',
0x91, int)
+#define IIO_BUFFER_DMABUF_ATTACH_IOCTL         _IOW('i', 0x92,
int)
+#define IIO_BUFFER_DMABUF_DETACH_IOCTL         _IOW('i', 0x93,
int)
+#define IIO_BUFFER_DMABUF_ENQUEUE_IOCTL                _IOW('i',
0x94, struct iio_dmabuf)
  
  #endif /* _UAPI_IIO_BUFFER_H_ */

</pre>
        </blockquote>
        <pre class="moz-quote-pre" wrap="">
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
</pre>
    </blockquote>
    <br>
  </body>
</html>