diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 239dde7a006a..bf92ce7e4e3e 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -399,6 +399,7 @@ static long dma_buf_ioctl(struct file *file, { struct dma_buf *dmabuf; struct dma_buf_sync sync; + struct dma_buf_sync_partial sync_p; enum dma_data_direction dir; int ret; @@ -445,6 +446,44 @@ static long dma_buf_ioctl(struct file *file, case DMA_BUF_SET_NAME_B: return dma_buf_set_name(dmabuf, (const char __user *)arg); + case DMA_BUF_IOCTL_SYNC_PARTIAL: + if (copy_from_user(&sync_p, (void __user *) arg, sizeof(sync_p))) + return -EFAULT; + + if (sync_p.len == 0) + return -EINVAL; + + if (sync_p.len > dmabuf->size || sync_p.offset > dmabuf->size - sync_p.len) + return -EINVAL; + + if (sync_p.flags & ~DMA_BUF_SYNC_VALID_FLAGS_MASK) + return -EINVAL; + + switch (sync_p.flags & DMA_BUF_SYNC_RW) { + case DMA_BUF_SYNC_READ: + dir = DMA_FROM_DEVICE; + break; + case DMA_BUF_SYNC_WRITE: + dir = DMA_TO_DEVICE; + break; + case DMA_BUF_SYNC_RW: + dir = DMA_BIDIRECTIONAL; + break; + default: + return -EINVAL; + } + + if (sync_p.flags & DMA_BUF_SYNC_END) + ret = dma_buf_end_cpu_access_partial(dmabuf, dir, + sync_p.offset, + sync_p.len); + else + ret = dma_buf_begin_cpu_access_partial(dmabuf, dir, + sync_p.offset, + sync_p.len); + + return ret; + default: return -ENOTTY; } diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h index c6f38dcaef66..fa847a9f4641 100644 --- a/include/uapi/linux/dma-buf.h +++ b/include/uapi/linux/dma-buf.h @@ -49,4 +49,12 @@ struct dma_buf_sync { #define DMA_BUF_SET_NAME_A _IOW(DMA_BUF_BASE, 1, u32) #define DMA_BUF_SET_NAME_B _IOW(DMA_BUF_BASE, 1, u64) +struct dma_buf_sync_partial { + __u64 flags; + __u32 offset; + __u32 len; +}; + +#define DMA_BUF_IOCTL_SYNC_PARTIAL _IOW(DMA_BUF_BASE, 2, struct dma_buf_sync_partial) + #endif