summaryrefslogtreecommitdiff
path: root/drivers/gpu/msm/kgsl_sharedmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/msm/kgsl_sharedmem.c')
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c57
1 files changed, 29 insertions, 28 deletions
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index fa95b4dfe718..7f4a5a3b251f 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -623,6 +623,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
uint64_t size, unsigned int op)
{
void *addr = NULL;
+ struct sg_table *sgt = NULL;
+ struct scatterlist *sg;
+ unsigned int i, pos = 0;
int ret = 0;
if (size == 0 || size > UINT_MAX)
@@ -650,40 +653,38 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
* If the buffer is not to mapped to kernel, perform cache
* operations after mapping to kernel.
*/
- if (memdesc->sgt != NULL) {
- struct scatterlist *sg;
- unsigned int i, pos = 0;
+ if (memdesc->sgt != NULL)
+ sgt = memdesc->sgt;
+ else {
+ if (memdesc->pages == NULL)
+ return ret;
+
+ sgt = kgsl_alloc_sgt_from_pages(memdesc);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
+ }
- for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
- uint64_t sg_offset, sg_left;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ uint64_t sg_offset, sg_left;
- if (offset >= (pos + sg->length)) {
- pos += sg->length;
- continue;
- }
- sg_offset = offset > pos ? offset - pos : 0;
- sg_left = (sg->length - sg_offset > size) ? size :
- sg->length - sg_offset;
- ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
- sg_left, op);
- size -= sg_left;
- if (size == 0)
- break;
+ if (offset >= (pos + sg->length)) {
pos += sg->length;
+ continue;
}
- } else if (memdesc->pages != NULL) {
- addr = vmap(memdesc->pages, memdesc->page_count,
- VM_IOREMAP, pgprot_writecombine(PAGE_KERNEL));
- if (addr == NULL)
- return -ENOMEM;
+ sg_offset = offset > pos ? offset - pos : 0;
+ sg_left = (sg->length - sg_offset > size) ? size :
+ sg->length - sg_offset;
+ ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
+ sg_left, op);
+ size -= sg_left;
+ if (size == 0)
+ break;
+ pos += sg->length;
+ }
- /* Make sure the offset + size do not overflow the address */
- if (addr + ((size_t) offset + (size_t) size) < addr)
- return -ERANGE;
+ if (memdesc->sgt == NULL)
+ kgsl_free_sgt(sgt);
- ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
- vunmap(addr);
- }
return ret;
}
EXPORT_SYMBOL(kgsl_cache_range_op);