diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 47042936a794..2cc7c300bc77 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -402,6 +402,62 @@ static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset, ion_dma_buf_vunmap(dmabuf, ptr); } +static int ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl, + unsigned int nents, unsigned int offset, + unsigned int length, + enum dma_data_direction dir, bool for_cpu) +{ + int i; + struct scatterlist *sg; + unsigned int len = 0; + dma_addr_t sg_dma_addr; + + for_each_sg(sgl, sg, nents, i) { + if (sg_dma_len(sg) == 0) + break; + + if (i > 0) { + pr_warn_ratelimited("Partial cmo only supported with 1 segment\n" + "is dma_set_max_seg_size being set on dev:%s\n", + dev_name(dev)); + return -EINVAL; + } + } + + for_each_sg(sgl, sg, nents, i) { + unsigned int sg_offset, sg_left, size = 0; + + if (i == 0) + sg_dma_addr = sg_dma_address(sg); + + len += sg->length; + if (len <= offset) { + sg_dma_addr += sg->length; + continue; + } + + sg_left = len - offset; + sg_offset = sg->length - sg_left; + + size = (length < sg_left) ? length : sg_left; + if (for_cpu) + dma_sync_single_range_for_cpu(dev, sg_dma_addr, + sg_offset, size, dir); + else + dma_sync_single_range_for_device(dev, sg_dma_addr, + sg_offset, size, dir); + + offset += size; + length -= size; + sg_dma_addr += sg->length; + + if (length == 0) + break; + } + + return 0; +} + static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction direction) { @@ -466,6 +522,56 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, return 0; } +static int ion_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction dir, + unsigned int offset, + unsigned int len) +{ + struct ion_buffer *buffer = dmabuf->priv; + struct ion_dma_buf_attachment *a; + int ret = 0; + + if (!(buffer->flags & ION_FLAG_CACHED)) + return 0; + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + + ret = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, + offset, len, dir, true); + } + mutex_unlock(&buffer->lock); + + return ret; +} + +static int ion_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, + enum dma_data_direction direction, + unsigned int offset, + unsigned int len) +{ + struct ion_buffer *buffer = dmabuf->priv; + struct ion_dma_buf_attachment *a; + int ret = 0; + + if (!(buffer->flags & ION_FLAG_CACHED)) + return 0; + + mutex_lock(&buffer->lock); + list_for_each_entry(a, &buffer->attachments, list) { + if (!a->mapped) + continue; + + ret = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, + offset, len, direction, false); + } + mutex_unlock(&buffer->lock); + + return ret; +} + static const struct dma_buf_ops dma_buf_ops = { .map_dma_buf = ion_map_dma_buf, .unmap_dma_buf = ion_unmap_dma_buf, @@ -475,6 +581,8 @@ static const struct dma_buf_ops dma_buf_ops = { .detach = ion_dma_buf_detatch, .begin_cpu_access = ion_dma_buf_begin_cpu_access, .end_cpu_access = ion_dma_buf_end_cpu_access, + .begin_cpu_access_partial = ion_dma_buf_begin_cpu_access_partial, + .end_cpu_access_partial = ion_dma_buf_end_cpu_access_partial, .map = ion_dma_buf_kmap, .unmap = ion_dma_buf_kunmap, .vmap = ion_dma_buf_vmap,