diff options
| author | Deepak Nibade <dnibade@nvidia.com> | 2017-09-15 08:32:09 -0400 |
|---|---|---|
| committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-10-13 16:42:01 -0400 |
| commit | 11d2647af2b38fc5b40db76871d97dcfd0eec833 (patch) | |
| tree | 4c43fdc6d6c880bd7c708e199afbe26e82175afa | |
| parent | 00f54f1ae8d0335707a26cca6ef9317ae691635c (diff) | |
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 <dnibade@nvidia.com>
Signed-off-by: Pritesh Raithatha <praithatha@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1560847
Reviewed-on: https://git-master.nvidia.com/r/1565250
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
| -rw-r--r-- | drivers/video/tegra/host/chip_support.h | 2 | ||||
| -rw-r--r-- | drivers/video/tegra/host/host1x/host1x_vm_t186.c | 4 | ||||
| -rw-r--r-- | drivers/video/tegra/host/iommu_context_dev.c | 51 | ||||
| -rw-r--r-- | drivers/video/tegra/host/iommu_context_dev.h | 2 | ||||
| -rw-r--r-- | 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 { | |||
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct nvhost_vm_ops { | 67 | struct nvhost_vm_ops { |
| 68 | int (*init)(struct nvhost_vm *vm); | 68 | int (*init)(struct nvhost_vm *vm, void *identifier); |
| 69 | void (*deinit)(struct nvhost_vm *vm); | 69 | void (*deinit)(struct nvhost_vm *vm); |
| 70 | int (*pin_static_buffer)(struct platform_device *pdev, | 70 | int (*pin_static_buffer)(struct platform_device *pdev, |
| 71 | void *vaddr, dma_addr_t paddr, | 71 | 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 @@ | |||
| 27 | /* 5 second timeout */ | 27 | /* 5 second timeout */ |
| 28 | #define NVHOST_VM_WAIT_TIMEOUT (5000) | 28 | #define NVHOST_VM_WAIT_TIMEOUT (5000) |
| 29 | 29 | ||
| 30 | static int host1x_vm_init(struct nvhost_vm *vm) | 30 | static int host1x_vm_init(struct nvhost_vm *vm, void *identifier) |
| 31 | { | 31 | { |
| 32 | struct platform_device *pdev; | 32 | struct platform_device *pdev; |
| 33 | unsigned int i = 0; | 33 | unsigned int i = 0; |
| 34 | 34 | ||
| 35 | /* wait until we have a context device */ | 35 | /* wait until we have a context device */ |
| 36 | do { | 36 | do { |
| 37 | pdev = iommu_context_dev_allocate(); | 37 | pdev = iommu_context_dev_allocate(identifier); |
| 38 | if (!pdev) { | 38 | if (!pdev) { |
| 39 | ++i; | 39 | ++i; |
| 40 | mdelay(1); | 40 | 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 { | |||
| 47 | struct list_head list; | 47 | struct list_head list; |
| 48 | struct device_dma_parameters dma_parms; | 48 | struct device_dma_parameters dma_parms; |
| 49 | bool allocated; | 49 | bool allocated; |
| 50 | void *prev_identifier; | ||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | static LIST_HEAD(iommu_ctx_list); | 53 | static LIST_HEAD(iommu_ctx_list); |
| 53 | static LIST_HEAD(iommu_static_mappings_list); | 54 | static LIST_HEAD(iommu_static_mappings_list); |
| 54 | static DEFINE_MUTEX(iommu_ctx_list_mutex); | 55 | static DEFINE_MUTEX(iommu_ctx_list_mutex); |
| 55 | 56 | ||
| 56 | struct platform_device *iommu_context_dev_allocate(void) | 57 | struct platform_device *iommu_context_dev_allocate(void *identifier) |
| 57 | { | 58 | { |
| 58 | struct iommu_ctx *ctx; | 59 | struct iommu_ctx *ctx, *ctx_new = NULL; |
| 60 | bool dirty = false; | ||
| 59 | 61 | ||
| 60 | mutex_lock(&iommu_ctx_list_mutex); | 62 | mutex_lock(&iommu_ctx_list_mutex); |
| 63 | /* | ||
| 64 | * First check if we have same identifier stashed into | ||
| 65 | * some context device | ||
| 66 | * If yes, use that context device since it will have all | ||
| 67 | * the mappings stashed too | ||
| 68 | */ | ||
| 61 | list_for_each_entry(ctx, &iommu_ctx_list, list) { | 69 | list_for_each_entry(ctx, &iommu_ctx_list, list) { |
| 62 | if (!ctx->allocated) { | 70 | if (!ctx->allocated && identifier == ctx->prev_identifier) { |
| 63 | ctx->allocated = true; | 71 | ctx->allocated = true; |
| 64 | mutex_unlock(&iommu_ctx_list_mutex); | 72 | mutex_unlock(&iommu_ctx_list_mutex); |
| 65 | return ctx->pdev; | 73 | return ctx->pdev; |
| 66 | } | 74 | } |
| 67 | } | 75 | } |
| 76 | |||
| 77 | /* | ||
| 78 | * Otherwise, find a device which does not have any identifier stashed | ||
| 79 | * If there is no device left without identifier stashed, use any of | ||
| 80 | * the free device and explicitly remove all the stashings from it | ||
| 81 | */ | ||
| 82 | list_for_each_entry(ctx, &iommu_ctx_list, list) { | ||
| 83 | if (!ctx->allocated && !ctx_new) { | ||
| 84 | ctx_new = ctx; | ||
| 85 | dirty = true; | ||
| 86 | } | ||
| 87 | if (!ctx->allocated && !ctx->prev_identifier) { | ||
| 88 | ctx_new = ctx; | ||
| 89 | dirty = false; | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | if (ctx_new) { | ||
| 95 | if (dirty) { | ||
| 96 | /* | ||
| 97 | * Ensure that all stashed mappings are removed from this context device | ||
| 98 | * before this context device gets reassigned to some other process | ||
| 99 | */ | ||
| 100 | dma_buf_release_stash(&ctx_new->pdev->dev); | ||
| 101 | } | ||
| 102 | |||
| 103 | ctx_new->prev_identifier = identifier; | ||
| 104 | ctx_new->allocated = true; | ||
| 105 | mutex_unlock(&iommu_ctx_list_mutex); | ||
| 106 | return ctx_new->pdev; | ||
| 107 | } | ||
| 108 | |||
| 68 | mutex_unlock(&iommu_ctx_list_mutex); | 109 | mutex_unlock(&iommu_ctx_list_mutex); |
| 69 | 110 | ||
| 70 | return NULL; | 111 | return NULL; |
| @@ -200,8 +241,8 @@ static int iommu_context_dev_probe(struct platform_device *pdev) | |||
| 200 | pdev->dev.dma_parms = &ctx->dma_parms; | 241 | pdev->dev.dma_parms = &ctx->dma_parms; |
| 201 | dma_set_max_seg_size(&pdev->dev, UINT_MAX); | 242 | dma_set_max_seg_size(&pdev->dev, UINT_MAX); |
| 202 | 243 | ||
| 203 | /* disable lazy unmapping for context devices */ | 244 | /* flag required to handle stashings in context devices */ |
| 204 | dma_buf_disable_lazy_unmapping(&pdev->dev); | 245 | pdev->dev.context_dev = true; |
| 205 | 246 | ||
| 206 | dev_info(&pdev->dev, "initialized (streamid=%d)", | 247 | dev_info(&pdev->dev, "initialized (streamid=%d)", |
| 207 | iommu_get_hwid(pdev->dev.archdata.iommu, &pdev->dev, 0)); | 248 | 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 @@ | |||
| 19 | #ifndef IOMMU_CONTEXT_DEV_H | 19 | #ifndef IOMMU_CONTEXT_DEV_H |
| 20 | #define IOMMU_CONTEXT_DEV_H | 20 | #define IOMMU_CONTEXT_DEV_H |
| 21 | 21 | ||
| 22 | struct platform_device *iommu_context_dev_allocate(void); | 22 | struct platform_device *iommu_context_dev_allocate(void *identifier); |
| 23 | void iommu_context_dev_release(struct platform_device *pdev); | 23 | void iommu_context_dev_release(struct platform_device *pdev); |
| 24 | int iommu_context_dev_get_streamid(struct platform_device *pdev); | 24 | int iommu_context_dev_get_streamid(struct platform_device *pdev); |
| 25 | int iommu_context_dev_map_static(void *vaddr, dma_addr_t paddr, size_t size); | 25 | 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, | |||
| 224 | mutex_unlock(&host->vm_mutex); | 224 | mutex_unlock(&host->vm_mutex); |
| 225 | 225 | ||
| 226 | if (vm_op().init && vm->enable_hw) { | 226 | if (vm_op().init && vm->enable_hw) { |
| 227 | err = vm_op().init(vm); | 227 | err = vm_op().init(vm, identifier); |
| 228 | if (err) | 228 | if (err) |
| 229 | goto err_init; | 229 | goto err_init; |
| 230 | } | 230 | } |
