.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* Copyright (c) 2017 The Linux Foundation. All rights reserved. |
---|
2 | | - * |
---|
3 | | - * This program is free software; you can redistribute it and/or modify |
---|
4 | | - * it under the terms of the GNU General Public License version 2 and |
---|
5 | | - * only version 2 as published by the Free Software Foundation. |
---|
6 | | - * |
---|
7 | | - * This program is distributed in the hope that it will be useful, |
---|
8 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | | - * GNU General Public License for more details. |
---|
11 | | - * |
---|
12 | 3 | */ |
---|
13 | 4 | |
---|
14 | 5 | #include "msm_gem.h" |
---|
.. | .. |
---|
54 | 45 | if (!ring) |
---|
55 | 46 | return; |
---|
56 | 47 | |
---|
57 | | - spin_lock_irqsave(&ring->lock, flags); |
---|
| 48 | + spin_lock_irqsave(&ring->preempt_lock, flags); |
---|
58 | 49 | wptr = get_wptr(ring); |
---|
59 | | - spin_unlock_irqrestore(&ring->lock, flags); |
---|
| 50 | + spin_unlock_irqrestore(&ring->preempt_lock, flags); |
---|
60 | 51 | |
---|
61 | 52 | gpu_write(gpu, REG_A5XX_CP_RB_WPTR, wptr); |
---|
62 | 53 | } |
---|
.. | .. |
---|
71 | 62 | bool empty; |
---|
72 | 63 | struct msm_ringbuffer *ring = gpu->rb[i]; |
---|
73 | 64 | |
---|
74 | | - spin_lock_irqsave(&ring->lock, flags); |
---|
75 | | - empty = (get_wptr(ring) == ring->memptrs->rptr); |
---|
76 | | - spin_unlock_irqrestore(&ring->lock, flags); |
---|
| 65 | + spin_lock_irqsave(&ring->preempt_lock, flags); |
---|
| 66 | + empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); |
---|
| 67 | + spin_unlock_irqrestore(&ring->preempt_lock, flags); |
---|
77 | 68 | |
---|
78 | 69 | if (!empty) |
---|
79 | 70 | return ring; |
---|
.. | .. |
---|
92 | 83 | if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) |
---|
93 | 84 | return; |
---|
94 | 85 | |
---|
95 | | - dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); |
---|
| 86 | + DRM_DEV_ERROR(dev->dev, "%s: preemption timed out\n", gpu->name); |
---|
96 | 87 | queue_work(priv->wq, &gpu->recover_work); |
---|
97 | 88 | } |
---|
98 | 89 | |
---|
.. | .. |
---|
141 | 132 | } |
---|
142 | 133 | |
---|
143 | 134 | /* Make sure the wptr doesn't update while we're in motion */ |
---|
144 | | - spin_lock_irqsave(&ring->lock, flags); |
---|
| 135 | + spin_lock_irqsave(&ring->preempt_lock, flags); |
---|
145 | 136 | a5xx_gpu->preempt[ring->id]->wptr = get_wptr(ring); |
---|
146 | | - spin_unlock_irqrestore(&ring->lock, flags); |
---|
| 137 | + spin_unlock_irqrestore(&ring->preempt_lock, flags); |
---|
147 | 138 | |
---|
148 | 139 | /* Set the address of the incoming preemption record */ |
---|
149 | 140 | gpu_write64(gpu, REG_A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO, |
---|
.. | .. |
---|
188 | 179 | status = gpu_read(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL); |
---|
189 | 180 | if (unlikely(status)) { |
---|
190 | 181 | set_preempt_state(a5xx_gpu, PREEMPT_FAULTED); |
---|
191 | | - dev_err(dev->dev, "%s: Preemption failed to complete\n", |
---|
| 182 | + DRM_DEV_ERROR(dev->dev, "%s: Preemption failed to complete\n", |
---|
192 | 183 | gpu->name); |
---|
193 | 184 | queue_work(priv->wq, &gpu->recover_work); |
---|
194 | 185 | return; |
---|
.. | .. |
---|
208 | 199 | struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); |
---|
209 | 200 | int i; |
---|
210 | 201 | |
---|
| 202 | + /* Always come up on rb 0 */ |
---|
| 203 | + a5xx_gpu->cur_ring = gpu->rb[0]; |
---|
| 204 | + |
---|
| 205 | + /* No preemption if we only have one ring */ |
---|
| 206 | + if (gpu->nr_rings == 1) |
---|
| 207 | + return; |
---|
| 208 | + |
---|
211 | 209 | for (i = 0; i < gpu->nr_rings; i++) { |
---|
212 | 210 | a5xx_gpu->preempt[i]->wptr = 0; |
---|
213 | 211 | a5xx_gpu->preempt[i]->rptr = 0; |
---|
214 | 212 | a5xx_gpu->preempt[i]->rbase = gpu->rb[i]->iova; |
---|
| 213 | + a5xx_gpu->preempt[i]->rptr_addr = shadowptr(a5xx_gpu, gpu->rb[i]); |
---|
215 | 214 | } |
---|
216 | 215 | |
---|
217 | 216 | /* Write a 0 to signal that we aren't switching pagetables */ |
---|
.. | .. |
---|
220 | 219 | |
---|
221 | 220 | /* Reset the preemption state */ |
---|
222 | 221 | set_preempt_state(a5xx_gpu, PREEMPT_NONE); |
---|
223 | | - |
---|
224 | | - /* Always come up on rb 0 */ |
---|
225 | | - a5xx_gpu->cur_ring = gpu->rb[0]; |
---|
226 | 222 | } |
---|
227 | 223 | |
---|
228 | 224 | static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu, |
---|
.. | .. |
---|
231 | 227 | struct adreno_gpu *adreno_gpu = &a5xx_gpu->base; |
---|
232 | 228 | struct msm_gpu *gpu = &adreno_gpu->base; |
---|
233 | 229 | struct a5xx_preempt_record *ptr; |
---|
234 | | - struct drm_gem_object *bo = NULL; |
---|
235 | | - u64 iova = 0; |
---|
| 230 | + void *counters; |
---|
| 231 | + struct drm_gem_object *bo = NULL, *counters_bo = NULL; |
---|
| 232 | + u64 iova = 0, counters_iova = 0; |
---|
236 | 233 | |
---|
237 | 234 | ptr = msm_gem_kernel_new(gpu->dev, |
---|
238 | 235 | A5XX_PREEMPT_RECORD_SIZE + A5XX_PREEMPT_COUNTER_SIZE, |
---|
239 | | - MSM_BO_UNCACHED, gpu->aspace, &bo, &iova); |
---|
| 236 | + MSM_BO_UNCACHED | MSM_BO_MAP_PRIV, gpu->aspace, &bo, &iova); |
---|
240 | 237 | |
---|
241 | 238 | if (IS_ERR(ptr)) |
---|
242 | 239 | return PTR_ERR(ptr); |
---|
243 | 240 | |
---|
| 241 | + /* The buffer to store counters needs to be unprivileged */ |
---|
| 242 | + counters = msm_gem_kernel_new(gpu->dev, |
---|
| 243 | + A5XX_PREEMPT_COUNTER_SIZE, |
---|
| 244 | + MSM_BO_UNCACHED, gpu->aspace, &counters_bo, &counters_iova); |
---|
| 245 | + if (IS_ERR(counters)) { |
---|
| 246 | + msm_gem_kernel_put(bo, gpu->aspace, true); |
---|
| 247 | + return PTR_ERR(counters); |
---|
| 248 | + } |
---|
| 249 | + |
---|
| 250 | + msm_gem_object_set_name(bo, "preempt"); |
---|
| 251 | + msm_gem_object_set_name(counters_bo, "preempt_counters"); |
---|
| 252 | + |
---|
244 | 253 | a5xx_gpu->preempt_bo[ring->id] = bo; |
---|
| 254 | + a5xx_gpu->preempt_counters_bo[ring->id] = counters_bo; |
---|
245 | 255 | a5xx_gpu->preempt_iova[ring->id] = iova; |
---|
246 | 256 | a5xx_gpu->preempt[ring->id] = ptr; |
---|
247 | 257 | |
---|
.. | .. |
---|
250 | 260 | ptr->magic = A5XX_PREEMPT_RECORD_MAGIC; |
---|
251 | 261 | ptr->info = 0; |
---|
252 | 262 | ptr->data = 0; |
---|
253 | | - ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT; |
---|
254 | | - ptr->rptr_addr = rbmemptr(ring, rptr); |
---|
255 | | - ptr->counter = iova + A5XX_PREEMPT_RECORD_SIZE; |
---|
| 263 | + ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE; |
---|
| 264 | + |
---|
| 265 | + ptr->counter = counters_iova; |
---|
256 | 266 | |
---|
257 | 267 | return 0; |
---|
258 | 268 | } |
---|
.. | .. |
---|
264 | 274 | int i; |
---|
265 | 275 | |
---|
266 | 276 | for (i = 0; i < gpu->nr_rings; i++) { |
---|
267 | | - if (!a5xx_gpu->preempt_bo[i]) |
---|
268 | | - continue; |
---|
269 | | - |
---|
270 | | - msm_gem_put_vaddr(a5xx_gpu->preempt_bo[i]); |
---|
271 | | - |
---|
272 | | - if (a5xx_gpu->preempt_iova[i]) |
---|
273 | | - msm_gem_put_iova(a5xx_gpu->preempt_bo[i], gpu->aspace); |
---|
274 | | - |
---|
275 | | - drm_gem_object_unreference(a5xx_gpu->preempt_bo[i]); |
---|
276 | | - a5xx_gpu->preempt_bo[i] = NULL; |
---|
| 277 | + msm_gem_kernel_put(a5xx_gpu->preempt_bo[i], gpu->aspace, true); |
---|
| 278 | + msm_gem_kernel_put(a5xx_gpu->preempt_counters_bo[i], |
---|
| 279 | + gpu->aspace, true); |
---|
277 | 280 | } |
---|
278 | 281 | } |
---|
279 | 282 | |
---|