| .. | .. |
|---|
| 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" |
|---|
| .. | .. |
|---|
| 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 | |
|---|
| .. | .. |
|---|
| 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; |
|---|
| .. | .. |
|---|
| 220 | 218 | |
|---|
| 221 | 219 | /* Reset the preemption state */ |
|---|
| 222 | 220 | set_preempt_state(a5xx_gpu, PREEMPT_NONE); |
|---|
| 223 | | - |
|---|
| 224 | | - /* Always come up on rb 0 */ |
|---|
| 225 | | - a5xx_gpu->cur_ring = gpu->rb[0]; |
|---|
| 226 | 221 | } |
|---|
| 227 | 222 | |
|---|
| 228 | 223 | static int preempt_init_ring(struct a5xx_gpu *a5xx_gpu, |
|---|
| .. | .. |
|---|
| 231 | 226 | struct adreno_gpu *adreno_gpu = &a5xx_gpu->base; |
|---|
| 232 | 227 | struct msm_gpu *gpu = &adreno_gpu->base; |
|---|
| 233 | 228 | struct a5xx_preempt_record *ptr; |
|---|
| 234 | | - struct drm_gem_object *bo = NULL; |
|---|
| 235 | | - u64 iova = 0; |
|---|
| 229 | + void *counters; |
|---|
| 230 | + struct drm_gem_object *bo = NULL, *counters_bo = NULL; |
|---|
| 231 | + u64 iova = 0, counters_iova = 0; |
|---|
| 236 | 232 | |
|---|
| 237 | 233 | ptr = msm_gem_kernel_new(gpu->dev, |
|---|
| 238 | 234 | A5XX_PREEMPT_RECORD_SIZE + A5XX_PREEMPT_COUNTER_SIZE, |
|---|
| 239 | | - MSM_BO_UNCACHED, gpu->aspace, &bo, &iova); |
|---|
| 235 | + MSM_BO_UNCACHED | MSM_BO_MAP_PRIV, gpu->aspace, &bo, &iova); |
|---|
| 240 | 236 | |
|---|
| 241 | 237 | if (IS_ERR(ptr)) |
|---|
| 242 | 238 | return PTR_ERR(ptr); |
|---|
| 243 | 239 | |
|---|
| 240 | + /* The buffer to store counters needs to be unprivileged */ |
|---|
| 241 | + counters = msm_gem_kernel_new(gpu->dev, |
|---|
| 242 | + A5XX_PREEMPT_COUNTER_SIZE, |
|---|
| 243 | + MSM_BO_UNCACHED, gpu->aspace, &counters_bo, &counters_iova); |
|---|
| 244 | + if (IS_ERR(counters)) { |
|---|
| 245 | + msm_gem_kernel_put(bo, gpu->aspace, true); |
|---|
| 246 | + return PTR_ERR(counters); |
|---|
| 247 | + } |
|---|
| 248 | + |
|---|
| 249 | + msm_gem_object_set_name(bo, "preempt"); |
|---|
| 250 | + msm_gem_object_set_name(counters_bo, "preempt_counters"); |
|---|
| 251 | + |
|---|
| 244 | 252 | a5xx_gpu->preempt_bo[ring->id] = bo; |
|---|
| 253 | + a5xx_gpu->preempt_counters_bo[ring->id] = counters_bo; |
|---|
| 245 | 254 | a5xx_gpu->preempt_iova[ring->id] = iova; |
|---|
| 246 | 255 | a5xx_gpu->preempt[ring->id] = ptr; |
|---|
| 247 | 256 | |
|---|
| .. | .. |
|---|
| 250 | 259 | ptr->magic = A5XX_PREEMPT_RECORD_MAGIC; |
|---|
| 251 | 260 | ptr->info = 0; |
|---|
| 252 | 261 | 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; |
|---|
| 262 | + ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE; |
|---|
| 263 | + |
|---|
| 264 | + ptr->rptr_addr = shadowptr(a5xx_gpu, ring); |
|---|
| 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 | |
|---|