diff options
author | Sami Kiminki <skiminki@nvidia.com> | 2017-11-14 08:56:09 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-11-15 16:26:19 -0500 |
commit | 69e032653df5aae335764f6346703a1e55c96a2d (patch) | |
tree | 4554eb5596bed720865e70a448674c7b1da4e1b9 | |
parent | 44f8b11f47bc31aafd0e3d2486125e1d87725fd4 (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.c | 50 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/vm.c | 27 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/comptags.h | 20 |
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 | ||
43 | int gk20a_alloc_or_get_comptags(struct gk20a *g, | 45 | int 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 | |
105 | exit_locked: | ||
106 | nvgpu_mutex_release(&priv->lock); | ||
107 | |||
108 | return err; | ||
96 | } | 109 | } |
97 | 110 | ||
98 | void gk20a_mark_comptags_cleared(struct nvgpu_os_buffer *buf) | 111 | bool 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 | |||
129 | void 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); |
75 | void gk20a_get_comptags(struct nvgpu_os_buffer *buf, | 75 | void gk20a_get_comptags(struct nvgpu_os_buffer *buf, |
76 | struct gk20a_comptags *comptags); | 76 | struct gk20a_comptags *comptags); |
77 | void 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 | */ | ||
93 | bool gk20a_comptags_start_clear(struct nvgpu_os_buffer *buf); | ||
94 | void gk20a_comptags_finish_clear(struct nvgpu_os_buffer *buf, | ||
95 | bool clear_successful); | ||
78 | 96 | ||
79 | #endif | 97 | #endif |