diff options
Diffstat (limited to 'drivers/gpu/msm/kgsl_mmu.c')
-rw-r--r-- | drivers/gpu/msm/kgsl_mmu.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index ba564b2851f9..0df1ad02f16e 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -414,17 +414,29 @@ EXPORT_SYMBOL(kgsl_mmu_map); * @pagetable: Pagetable to release the memory from * @memdesc: Memory descriptor containing the GPU address to free */ -void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc) +void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) { + struct kgsl_pagetable *pagetable = memdesc->pagetable; + int unmap_fail = 0; + if (memdesc->size == 0 || memdesc->gpuaddr == 0) return; - if (PT_OP_VALID(pagetable, put_gpuaddr)) - pagetable->pt_ops->put_gpuaddr(pagetable, memdesc); + if (!kgsl_memdesc_is_global(memdesc)) + unmap_fail = kgsl_mmu_unmap(pagetable, memdesc); + + /* + * Do not free the gpuaddr/size if unmap fails. Because if we + * try to map this range in future, the iommu driver will throw + * a BUG_ON() because it feels we are overwriting a mapping. + */ + if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0)) + pagetable->pt_ops->put_gpuaddr(memdesc); if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; + + memdesc->pagetable = NULL; } EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); @@ -610,7 +622,12 @@ static int nommu_get_gpuaddr(struct kgsl_pagetable *pagetable, memdesc->gpuaddr = (uint64_t) sg_phys(memdesc->sgt->sgl); - return memdesc->gpuaddr != 0 ? 0 : -ENOMEM; + if (memdesc->gpuaddr) { + memdesc->pagetable = pagetable; + return 0; + } + + return -ENOMEM; } static struct kgsl_mmu_pt_ops nommu_pt_ops = { |