From 11d2647af2b38fc5b40db76871d97dcfd0eec833 Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Fri, 15 Sep 2017 05:32:09 -0700 Subject: video: tegra: host: enable lazy unmapping on context devices Since context devices are a limited resource, these devices are dynamically allocated and re-used across multiple processes If lazy unmapping is enabled for context devices, one process can see all the mappings of other process mapped into same context device Hence lazy unmapping was disabled so far. To fix this handle allocation of context devices as following - store a unique prev_identifier into iommu_ctx - iommu_context_dev_allocate() will receive an identifier to compare - if same identifier is stashed into any of the free context device, return that context device since it will have all the mappings stashed - if not, look for a device which does not have prev_identifier set and is clean - if no device is available without prev_identifier, pick any one of the free device but explicitly call dma_buf_release_stash() to remove stashed mappings This ensures that new processes cannot see mappings of old process even if context device is reused. And since this is handled now, enable lazy unmapping on context devices too Bug 1950747 Change-Id: I40bf2e05691ddf1a65646f8706d165c1538db3ae Signed-off-by: Deepak Nibade Signed-off-by: Pritesh Raithatha Reviewed-on: https://git-master.nvidia.com/r/1560847 Reviewed-on: https://git-master.nvidia.com/r/1565250 Reviewed-by: svc-mobile-coverity GVS: Gerrit_Virtual_Submit Reviewed-by: Sachin Nikam Reviewed-by: Bharat Nihalani --- drivers/video/tegra/host/chip_support.h | 2 +- drivers/video/tegra/host/host1x/host1x_vm_t186.c | 4 +- drivers/video/tegra/host/iommu_context_dev.c | 51 +++++++++++++++++++++--- drivers/video/tegra/host/iommu_context_dev.h | 2 +- drivers/video/tegra/host/nvhost_vm.c | 2 +- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h index 23fcf6f39..1fcd53c15 100644 --- a/drivers/video/tegra/host/chip_support.h +++ b/drivers/video/tegra/host/chip_support.h @@ -65,7 +65,7 @@ struct nvhost_cdma_ops { }; struct nvhost_vm_ops { - int (*init)(struct nvhost_vm *vm); + int (*init)(struct nvhost_vm *vm, void *identifier); void (*deinit)(struct nvhost_vm *vm); int (*pin_static_buffer)(struct platform_device *pdev, void *vaddr, dma_addr_t paddr, diff --git a/drivers/video/tegra/host/host1x/host1x_vm_t186.c b/drivers/video/tegra/host/host1x/host1x_vm_t186.c index 65f0742c6..c198ec84e 100644 --- a/drivers/video/tegra/host/host1x/host1x_vm_t186.c +++ b/drivers/video/tegra/host/host1x/host1x_vm_t186.c @@ -27,14 +27,14 @@ /* 5 second timeout */ #define NVHOST_VM_WAIT_TIMEOUT (5000) -static int host1x_vm_init(struct nvhost_vm *vm) +static int host1x_vm_init(struct nvhost_vm *vm, void *identifier) { struct platform_device *pdev; unsigned int i = 0; /* wait until we have a context device */ do { - pdev = iommu_context_dev_allocate(); + pdev = iommu_context_dev_allocate(identifier); if (!pdev) { ++i; mdelay(1); diff --git a/drivers/video/tegra/host/iommu_context_dev.c b/drivers/video/tegra/host/iommu_context_dev.c index ead02e9dd..af9de61f3 100644 --- a/drivers/video/tegra/host/iommu_context_dev.c +++ b/drivers/video/tegra/host/iommu_context_dev.c @@ -47,24 +47,65 @@ struct iommu_ctx { struct list_head list; struct device_dma_parameters dma_parms; bool allocated; + void *prev_identifier; }; static LIST_HEAD(iommu_ctx_list); static LIST_HEAD(iommu_static_mappings_list); static DEFINE_MUTEX(iommu_ctx_list_mutex); -struct platform_device *iommu_context_dev_allocate(void) +struct platform_device *iommu_context_dev_allocate(void *identifier) { - struct iommu_ctx *ctx; + struct iommu_ctx *ctx, *ctx_new = NULL; + bool dirty = false; mutex_lock(&iommu_ctx_list_mutex); + /* + * First check if we have same identifier stashed into + * some context device + * If yes, use that context device since it will have all + * the mappings stashed too + */ list_for_each_entry(ctx, &iommu_ctx_list, list) { - if (!ctx->allocated) { + if (!ctx->allocated && identifier == ctx->prev_identifier) { ctx->allocated = true; mutex_unlock(&iommu_ctx_list_mutex); return ctx->pdev; } } + + /* + * Otherwise, find a device which does not have any identifier stashed + * If there is no device left without identifier stashed, use any of + * the free device and explicitly remove all the stashings from it + */ + list_for_each_entry(ctx, &iommu_ctx_list, list) { + if (!ctx->allocated && !ctx_new) { + ctx_new = ctx; + dirty = true; + } + if (!ctx->allocated && !ctx->prev_identifier) { + ctx_new = ctx; + dirty = false; + break; + } + } + + if (ctx_new) { + if (dirty) { + /* + * Ensure that all stashed mappings are removed from this context device + * before this context device gets reassigned to some other process + */ + dma_buf_release_stash(&ctx_new->pdev->dev); + } + + ctx_new->prev_identifier = identifier; + ctx_new->allocated = true; + mutex_unlock(&iommu_ctx_list_mutex); + return ctx_new->pdev; + } + mutex_unlock(&iommu_ctx_list_mutex); return NULL; @@ -200,8 +241,8 @@ static int iommu_context_dev_probe(struct platform_device *pdev) pdev->dev.dma_parms = &ctx->dma_parms; dma_set_max_seg_size(&pdev->dev, UINT_MAX); - /* disable lazy unmapping for context devices */ - dma_buf_disable_lazy_unmapping(&pdev->dev); + /* flag required to handle stashings in context devices */ + pdev->dev.context_dev = true; dev_info(&pdev->dev, "initialized (streamid=%d)", iommu_get_hwid(pdev->dev.archdata.iommu, &pdev->dev, 0)); diff --git a/drivers/video/tegra/host/iommu_context_dev.h b/drivers/video/tegra/host/iommu_context_dev.h index e219265c2..9f0f40519 100644 --- a/drivers/video/tegra/host/iommu_context_dev.h +++ b/drivers/video/tegra/host/iommu_context_dev.h @@ -19,7 +19,7 @@ #ifndef IOMMU_CONTEXT_DEV_H #define IOMMU_CONTEXT_DEV_H -struct platform_device *iommu_context_dev_allocate(void); +struct platform_device *iommu_context_dev_allocate(void *identifier); void iommu_context_dev_release(struct platform_device *pdev); int iommu_context_dev_get_streamid(struct platform_device *pdev); int iommu_context_dev_map_static(void *vaddr, dma_addr_t paddr, size_t size); diff --git a/drivers/video/tegra/host/nvhost_vm.c b/drivers/video/tegra/host/nvhost_vm.c index aaa03eb9b..979bb31fd 100644 --- a/drivers/video/tegra/host/nvhost_vm.c +++ b/drivers/video/tegra/host/nvhost_vm.c @@ -224,7 +224,7 @@ struct nvhost_vm *nvhost_vm_allocate(struct platform_device *pdev, mutex_unlock(&host->vm_mutex); if (vm_op().init && vm->enable_hw) { - err = vm_op().init(vm); + err = vm_op().init(vm, identifier); if (err) goto err_init; } -- cgit v1.2.2