summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Kiminki <skiminki@nvidia.com>2017-11-14 08:56:09 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-11-15 16:26:19 -0500
commit69e032653df5aae335764f6346703a1e55c96a2d (patch)
tree4554eb5596bed720865e70a448674c7b1da4e1b9
parent44f8b11f47bc31aafd0e3d2486125e1d87725fd4 (diff)
gpu: nvgpu: Add synchronization to comptag alloc and clearing
Comptags allocation and clearing was not synchronized for a buffer. Fix this race by serializing the operations with the gk20a_dmabuf_priv lock. While doing that, add an error check in the cbc_ctrl call. Bug 1902982 Change-Id: Icd96f1855eb5e5340651bcc85849b5ccc199b821 Signed-off-by: Sami Kiminki <skiminki@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1597904 Reviewed-by: Alex Waterman <alexw@nvidia.com> Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/common/linux/comptags.c50
-rw-r--r--drivers/gpu/nvgpu/common/mm/vm.c27
-rw-r--r--drivers/gpu/nvgpu/include/nvgpu/comptags.h20
3 files changed, 80 insertions, 17 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/comptags.c b/drivers/gpu/nvgpu/common/linux/comptags.c
index 7d095793..353f6363 100644
--- a/drivers/gpu/nvgpu/common/linux/comptags.c
+++ b/drivers/gpu/nvgpu/common/linux/comptags.c
@@ -37,7 +37,9 @@ void gk20a_get_comptags(struct nvgpu_os_buffer *buf,
37 return; 37 return;
38 } 38 }
39 39
40 nvgpu_mutex_acquire(&priv->lock);
40 *comptags = priv->comptags; 41 *comptags = priv->comptags;
42 nvgpu_mutex_release(&priv->lock);
41} 43}
42 44
43int gk20a_alloc_or_get_comptags(struct gk20a *g, 45int gk20a_alloc_or_get_comptags(struct gk20a *g,
@@ -55,20 +57,26 @@ int gk20a_alloc_or_get_comptags(struct gk20a *g,
55 if (!priv) 57 if (!priv)
56 return -ENOSYS; 58 return -ENOSYS;
57 59
60 nvgpu_mutex_acquire(&priv->lock);
61
58 if (priv->comptags.allocated) { 62 if (priv->comptags.allocated) {
59 /* 63 /*
60 * already allocated 64 * already allocated
61 */ 65 */
62 *comptags = priv->comptags; 66 *comptags = priv->comptags;
63 return 0; 67
68 err = 0;
69 goto exit_locked;
64 } 70 }
65 71
66 ctag_granularity = g->ops.fb.compression_page_size(g); 72 ctag_granularity = g->ops.fb.compression_page_size(g);
67 lines = DIV_ROUND_UP_ULL(buf->dmabuf->size, ctag_granularity); 73 lines = DIV_ROUND_UP_ULL(buf->dmabuf->size, ctag_granularity);
68 74
69 /* 0-sized buffer? Shouldn't occur, but let's check anyways. */ 75 /* 0-sized buffer? Shouldn't occur, but let's check anyways. */
70 if (lines < 1) 76 if (lines < 1) {
71 return -EINVAL; 77 err = -EINVAL;
78 goto exit_locked;
79 }
72 80
73 /* store the allocator so we can use it when we free the ctags */ 81 /* store the allocator so we can use it when we free the ctags */
74 priv->comptag_allocator = allocator; 82 priv->comptag_allocator = allocator;
@@ -89,16 +97,44 @@ int gk20a_alloc_or_get_comptags(struct gk20a *g,
89 * would not be safe to re-allocate comptags anyways on 97 * would not be safe to re-allocate comptags anyways on
90 * successive calls, as that would break map aliasing. 98 * successive calls, as that would break map aliasing.
91 */ 99 */
100 err = 0;
92 priv->comptags.allocated = true; 101 priv->comptags.allocated = true;
93 102
94 *comptags = priv->comptags; 103 *comptags = priv->comptags;
95 return 0; 104
105exit_locked:
106 nvgpu_mutex_release(&priv->lock);
107
108 return err;
96} 109}
97 110
98void gk20a_mark_comptags_cleared(struct nvgpu_os_buffer *buf) 111bool gk20a_comptags_start_clear(struct nvgpu_os_buffer *buf)
99{ 112{
100 struct gk20a_dmabuf_priv *priv = dma_buf_get_drvdata(buf->dmabuf, 113 struct gk20a_dmabuf_priv *priv = dma_buf_get_drvdata(buf->dmabuf,
101 buf->dev); 114 buf->dev);
102 if (priv) 115 bool clear_started = false;
103 priv->comptags.needs_clear = false; 116
117 if (priv) {
118 nvgpu_mutex_acquire(&priv->lock);
119
120 clear_started = priv->comptags.needs_clear;
121
122 if (!clear_started)
123 nvgpu_mutex_release(&priv->lock);
124 }
125
126 return clear_started;
127}
128
129void gk20a_comptags_finish_clear(struct nvgpu_os_buffer *buf,
130 bool clear_successful)
131{
132 struct gk20a_dmabuf_priv *priv = dma_buf_get_drvdata(buf->dmabuf,
133 buf->dev);
134 if (priv) {
135 if (clear_successful)
136 priv->comptags.needs_clear = false;
137
138 nvgpu_mutex_release(&priv->lock);
139 }
104} 140}
diff --git a/drivers/gpu/nvgpu/common/mm/vm.c b/drivers/gpu/nvgpu/common/mm/vm.c
index c3f6b79d..ebe8e381 100644
--- a/drivers/gpu/nvgpu/common/mm/vm.c
+++ b/drivers/gpu/nvgpu/common/mm/vm.c
@@ -874,12 +874,17 @@ struct nvgpu_mapped_buf *nvgpu_vm_map(struct vm_gk20a *vm,
874 */ 874 */
875 if (comptags.needs_clear) { 875 if (comptags.needs_clear) {
876 if (g->ops.ltc.cbc_ctrl) { 876 if (g->ops.ltc.cbc_ctrl) {
877 g->ops.ltc.cbc_ctrl( 877 if (gk20a_comptags_start_clear(os_buf)) {
878 g, gk20a_cbc_op_clear, 878 err = g->ops.ltc.cbc_ctrl(
879 comptags.offset, 879 g, gk20a_cbc_op_clear,
880 (comptags.offset + 880 comptags.offset,
881 comptags.lines - 1)); 881 (comptags.offset +
882 gk20a_mark_comptags_cleared(os_buf); 882 comptags.lines - 1));
883 gk20a_comptags_finish_clear(
884 os_buf, err == 0);
885 if (err)
886 goto clean_up;
887 }
883 } else { 888 } else {
884 /* 889 /*
885 * Cleared as part of gmmu map 890 * Cleared as part of gmmu map
@@ -920,6 +925,9 @@ struct nvgpu_mapped_buf *nvgpu_vm_map(struct vm_gk20a *vm,
920 goto clean_up; 925 goto clean_up;
921 } 926 }
922 927
928 if (clear_ctags)
929 clear_ctags = gk20a_comptags_start_clear(os_buf);
930
923 map_addr = g->ops.mm.gmmu_map(vm, 931 map_addr = g->ops.mm.gmmu_map(vm,
924 map_addr, 932 map_addr,
925 sgt, 933 sgt,
@@ -935,14 +943,15 @@ struct nvgpu_mapped_buf *nvgpu_vm_map(struct vm_gk20a *vm,
935 false, 943 false,
936 batch, 944 batch,
937 aperture); 945 aperture);
946
947 if (clear_ctags)
948 gk20a_comptags_finish_clear(os_buf, map_addr != 0);
949
938 if (!map_addr) { 950 if (!map_addr) {
939 err = -ENOMEM; 951 err = -ENOMEM;
940 goto clean_up; 952 goto clean_up;
941 } 953 }
942 954
943 if (clear_ctags)
944 gk20a_mark_comptags_cleared(os_buf);
945
946 nvgpu_init_list_node(&mapped_buffer->buffer_list); 955 nvgpu_init_list_node(&mapped_buffer->buffer_list);
947 nvgpu_ref_init(&mapped_buffer->ref); 956 nvgpu_ref_init(&mapped_buffer->ref);
948 mapped_buffer->addr = map_addr; 957 mapped_buffer->addr = map_addr;
diff --git a/drivers/gpu/nvgpu/include/nvgpu/comptags.h b/drivers/gpu/nvgpu/include/nvgpu/comptags.h
index 99e2d657..679a0f9e 100644
--- a/drivers/gpu/nvgpu/include/nvgpu/comptags.h
+++ b/drivers/gpu/nvgpu/include/nvgpu/comptags.h
@@ -74,6 +74,24 @@ int gk20a_alloc_or_get_comptags(struct gk20a *g,
74 struct gk20a_comptags *comptags); 74 struct gk20a_comptags *comptags);
75void gk20a_get_comptags(struct nvgpu_os_buffer *buf, 75void gk20a_get_comptags(struct nvgpu_os_buffer *buf,
76 struct gk20a_comptags *comptags); 76 struct gk20a_comptags *comptags);
77void gk20a_mark_comptags_cleared(struct nvgpu_os_buffer *buf); 77
78/*
79 * These functions must be used to synchronize comptags clear. The usage:
80 *
81 * if (gk20a_comptags_start_clear(os_buf)) {
82 * // we now hold the buffer lock for clearing
83 *
84 * bool successful = hw_clear_comptags();
85 *
86 * // mark the buf cleared (or not) and release the buffer lock
87 * gk20a_comptags_finish_clear(os_buf, successful);
88 * }
89 *
90 * If gk20a_start_comptags_clear() returns false, another caller has
91 * already cleared the comptags.
92 */
93bool gk20a_comptags_start_clear(struct nvgpu_os_buffer *buf);
94void gk20a_comptags_finish_clear(struct nvgpu_os_buffer *buf,
95 bool clear_successful);
78 96
79#endif 97#endif