diff options
Diffstat (limited to 'driver/product/kernel/patches/integrate_kds_with_dma_buf.patch')
-rwxr-xr-x | driver/product/kernel/patches/integrate_kds_with_dma_buf.patch | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/driver/product/kernel/patches/integrate_kds_with_dma_buf.patch b/driver/product/kernel/patches/integrate_kds_with_dma_buf.patch new file mode 100755 index 0000000..37458cf --- /dev/null +++ b/driver/product/kernel/patches/integrate_kds_with_dma_buf.patch @@ -0,0 +1,188 @@ +diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig +index 9aa618a..30e07ea 100644 +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -192,4 +192,12 @@ config DMA_SHARED_BUFFER + APIs extension; the file's descriptor can then be passed on to other + driver. + ++config DMA_SHARED_BUFFER_USES_KDS ++ bool "Synchronize access to dma_buf with KDS" ++ default n ++ select KDS ++ depends on DMA_SHARED_BUFFER ++ help ++ This option adds a KDS resource within every dma_buf allocation. ++ + endmenu +diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c +index 20258e1..e4083fd 100644 +--- a/drivers/base/dma-buf.c ++++ b/drivers/base/dma-buf.c +@@ -27,6 +27,8 @@ + #include <linux/dma-buf.h> + #include <linux/anon_inodes.h> + #include <linux/export.h> ++#include <linux/poll.h> ++#include <linux/sched.h> + + static inline int is_dma_buf_file(struct file *); + +@@ -40,6 +42,8 @@ static int dma_buf_release(struct inode *inode, struct file *file) + dmabuf = file->private_data; + + dmabuf->ops->release(dmabuf); ++ kds_callback_term(&dmabuf->kds_cb); ++ kds_resource_term(&dmabuf->kds); + kfree(dmabuf); + return 0; + } +@@ -61,9 +65,90 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) + return dmabuf->ops->mmap(dmabuf, vma); + } + ++ ++static void dma_buf_kds_cb_fn (void *param1, void *param2) ++{ ++ struct kds_resource_set **rset_ptr = param1; ++ struct kds_resource_set *rset = *rset_ptr; ++ wait_queue_head_t *wait_queue = param2; ++ ++ kfree(rset_ptr); ++ kds_resource_set_release(&rset); ++ wake_up(wait_queue); ++} ++ ++static int dma_buf_kds_check(struct kds_resource *kds, ++ long unsigned int exclusive, int *poll_ret) ++{ ++ /* Synchronous wait with 0 timeout - poll availability */ ++ struct kds_resource_set *rset = kds_waitall(1,&exclusive,&kds,0); ++ ++ if (IS_ERR(rset)) ++ return POLLERR; ++ ++ if (rset){ ++ kds_resource_set_release(&rset); ++ *poll_ret = POLLIN | POLLRDNORM; ++ if (exclusive) ++ *poll_ret |= POLLOUT | POLLWRNORM; ++ return 1; ++ }else{ ++ return 0; ++ } ++} ++ ++static unsigned int dma_buf_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct dma_buf *dmabuf; ++ struct kds_resource *kds; ++ unsigned int ret = 0; ++ ++ if (!is_dma_buf_file(file)) ++ return POLLERR; ++ ++ dmabuf = file->private_data; ++ kds = &dmabuf->kds; ++ ++ if (poll_does_not_wait(wait)){ ++ /* Check for exclusive access (superset of shared) first */ ++ if(!dma_buf_kds_check(kds, 1ul, &ret)) ++ dma_buf_kds_check(kds, 0ul, &ret); ++ }else{ ++ int events = poll_requested_events(wait); ++ unsigned long exclusive; ++ wait_queue_head_t *wq; ++ struct kds_resource_set **rset_ptr = kmalloc(sizeof(*rset_ptr), GFP_KERNEL); ++ ++ if (!rset_ptr) ++ return POLL_ERR; ++ ++ if (events & POLLOUT){ ++ wq = &dmabuf->wq_exclusive; ++ exclusive = 1; ++ }else{ ++ wq = &dmabuf->wq_shared; ++ exclusive = 0; ++ } ++ poll_wait(file, wq, wait); ++ ret = kds_async_waitall(rset_ptr, KDS_FLAG_LOCKED_WAIT, &dmabuf->kds_cb, ++ rset_ptr, wq, 1, &exclusive, &kds); ++ ++ if (IS_ERR_VALUE(ret)){ ++ ret = POLL_ERR; ++ kfree(rset_ptr); ++ }else{ ++ /* Can't allow access until callback */ ++ ret = 0; ++ } ++ } ++ return ret; ++} ++ + static const struct file_operations dma_buf_fops = { + .release = dma_buf_release, + .mmap = dma_buf_mmap_internal, ++ .poll = dma_buf_poll, + }; + + /* +@@ -120,6 +205,11 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops, + mutex_init(&dmabuf->lock); + INIT_LIST_HEAD(&dmabuf->attachments); + ++ init_waitqueue_head(&dmabuf->wq_exclusive); ++ init_waitqueue_head(&dmabuf->wq_shared); ++ kds_resource_init(&dmabuf->kds); ++ kds_callback_init(&dmabuf->kds_cb, 1, dma_buf_kds_cb_fn); ++ + return dmabuf; + } + EXPORT_SYMBOL_GPL(dma_buf_export); +diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h +index eb48f38..6e824d2 100644 +--- a/include/linux/dma-buf.h ++++ b/include/linux/dma-buf.h +@@ -30,6 +30,8 @@ + #include <linux/list.h> + #include <linux/dma-mapping.h> + #include <linux/fs.h> ++#include <linux/kds.h> ++#include <linux/wait.h> + + struct device; + struct dma_buf; +@@ -121,6 +123,10 @@ struct dma_buf { + const struct dma_buf_ops *ops; + /* mutex to serialize list manipulation and attach/detach */ + struct mutex lock; ++ struct kds_resource kds; ++ wait_queue_head_t wq_exclusive; ++ wait_queue_head_t wq_shared; ++ struct kds_callback kds_cb; + void *priv; + }; + +@@ -156,6 +162,21 @@ static inline void get_dma_buf(struct dma_buf *dmabuf) + get_file(dmabuf->file); + } + ++/** ++ * get_dma_buf_kds_resource - get a KDS resource for this dma-buf ++ * @dmabuf: [in] pointer to dma_buf ++ * ++ * Returns a KDS resource that represents the dma-buf. This should be used by ++ * drivers to synchronize access to the buffer. Note that the caller should ++ * ensure that a reference to the dma-buf exists from the call to ++ * kds_async_wait until kds_resource_set_release is called. ++ */ ++static inline struct kds_resource * ++ get_dma_buf_kds_resource(struct dma_buf *dmabuf) ++{ ++ return &dmabuf->kds; ++} ++ + #ifdef CONFIG_DMA_SHARED_BUFFER + struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, + struct device *dev); |