| .. | .. |
|---|
| 28 | 28 | */ |
|---|
| 29 | 29 | #include <linux/seq_file.h> |
|---|
| 30 | 30 | #include <linux/slab.h> |
|---|
| 31 | +#include <linux/uaccess.h> |
|---|
| 31 | 32 | #include <linux/debugfs.h> |
|---|
| 32 | | -#include <drm/drmP.h> |
|---|
| 33 | + |
|---|
| 33 | 34 | #include <drm/amdgpu_drm.h> |
|---|
| 34 | 35 | #include "amdgpu.h" |
|---|
| 35 | 36 | #include "atom.h" |
|---|
| .. | .. |
|---|
| 47 | 48 | * wptr. The GPU then starts fetching commands and executes |
|---|
| 48 | 49 | * them until the pointers are equal again. |
|---|
| 49 | 50 | */ |
|---|
| 50 | | -static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, |
|---|
| 51 | | - struct amdgpu_ring *ring); |
|---|
| 52 | | -static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring); |
|---|
| 53 | 51 | |
|---|
| 54 | 52 | /** |
|---|
| 55 | 53 | * amdgpu_ring_alloc - allocate space on the ring buffer |
|---|
| .. | .. |
|---|
| 135 | 133 | |
|---|
| 136 | 134 | if (ring->funcs->end_use) |
|---|
| 137 | 135 | ring->funcs->end_use(ring); |
|---|
| 138 | | - |
|---|
| 139 | | - if (ring->funcs->type != AMDGPU_RING_TYPE_KIQ) |
|---|
| 140 | | - amdgpu_ring_lru_touch(ring->adev, ring); |
|---|
| 141 | 136 | } |
|---|
| 142 | 137 | |
|---|
| 143 | 138 | /** |
|---|
| .. | .. |
|---|
| 156 | 151 | } |
|---|
| 157 | 152 | |
|---|
| 158 | 153 | /** |
|---|
| 159 | | - * amdgpu_ring_priority_put - restore a ring's priority |
|---|
| 160 | | - * |
|---|
| 161 | | - * @ring: amdgpu_ring structure holding the information |
|---|
| 162 | | - * @priority: target priority |
|---|
| 163 | | - * |
|---|
| 164 | | - * Release a request for executing at @priority |
|---|
| 165 | | - */ |
|---|
| 166 | | -void amdgpu_ring_priority_put(struct amdgpu_ring *ring, |
|---|
| 167 | | - enum drm_sched_priority priority) |
|---|
| 168 | | -{ |
|---|
| 169 | | - int i; |
|---|
| 170 | | - |
|---|
| 171 | | - if (!ring->funcs->set_priority) |
|---|
| 172 | | - return; |
|---|
| 173 | | - |
|---|
| 174 | | - if (atomic_dec_return(&ring->num_jobs[priority]) > 0) |
|---|
| 175 | | - return; |
|---|
| 176 | | - |
|---|
| 177 | | - /* no need to restore if the job is already at the lowest priority */ |
|---|
| 178 | | - if (priority == DRM_SCHED_PRIORITY_NORMAL) |
|---|
| 179 | | - return; |
|---|
| 180 | | - |
|---|
| 181 | | - mutex_lock(&ring->priority_mutex); |
|---|
| 182 | | - /* something higher prio is executing, no need to decay */ |
|---|
| 183 | | - if (ring->priority > priority) |
|---|
| 184 | | - goto out_unlock; |
|---|
| 185 | | - |
|---|
| 186 | | - /* decay priority to the next level with a job available */ |
|---|
| 187 | | - for (i = priority; i >= DRM_SCHED_PRIORITY_MIN; i--) { |
|---|
| 188 | | - if (i == DRM_SCHED_PRIORITY_NORMAL |
|---|
| 189 | | - || atomic_read(&ring->num_jobs[i])) { |
|---|
| 190 | | - ring->priority = i; |
|---|
| 191 | | - ring->funcs->set_priority(ring, i); |
|---|
| 192 | | - break; |
|---|
| 193 | | - } |
|---|
| 194 | | - } |
|---|
| 195 | | - |
|---|
| 196 | | -out_unlock: |
|---|
| 197 | | - mutex_unlock(&ring->priority_mutex); |
|---|
| 198 | | -} |
|---|
| 199 | | - |
|---|
| 200 | | -/** |
|---|
| 201 | | - * amdgpu_ring_priority_get - change the ring's priority |
|---|
| 202 | | - * |
|---|
| 203 | | - * @ring: amdgpu_ring structure holding the information |
|---|
| 204 | | - * @priority: target priority |
|---|
| 205 | | - * |
|---|
| 206 | | - * Request a ring's priority to be raised to @priority (refcounted). |
|---|
| 207 | | - */ |
|---|
| 208 | | -void amdgpu_ring_priority_get(struct amdgpu_ring *ring, |
|---|
| 209 | | - enum drm_sched_priority priority) |
|---|
| 210 | | -{ |
|---|
| 211 | | - if (!ring->funcs->set_priority) |
|---|
| 212 | | - return; |
|---|
| 213 | | - |
|---|
| 214 | | - if (atomic_inc_return(&ring->num_jobs[priority]) <= 0) |
|---|
| 215 | | - return; |
|---|
| 216 | | - |
|---|
| 217 | | - mutex_lock(&ring->priority_mutex); |
|---|
| 218 | | - if (priority <= ring->priority) |
|---|
| 219 | | - goto out_unlock; |
|---|
| 220 | | - |
|---|
| 221 | | - ring->priority = priority; |
|---|
| 222 | | - ring->funcs->set_priority(ring, priority); |
|---|
| 223 | | - |
|---|
| 224 | | -out_unlock: |
|---|
| 225 | | - mutex_unlock(&ring->priority_mutex); |
|---|
| 226 | | -} |
|---|
| 227 | | - |
|---|
| 228 | | -/** |
|---|
| 229 | 154 | * amdgpu_ring_init - init driver ring struct. |
|---|
| 230 | 155 | * |
|---|
| 231 | 156 | * @adev: amdgpu_device pointer |
|---|
| .. | .. |
|---|
| 237 | 162 | * Returns 0 on success, error on failure. |
|---|
| 238 | 163 | */ |
|---|
| 239 | 164 | int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, |
|---|
| 240 | | - unsigned max_dw, struct amdgpu_irq_src *irq_src, |
|---|
| 241 | | - unsigned irq_type) |
|---|
| 165 | + unsigned int max_dw, struct amdgpu_irq_src *irq_src, |
|---|
| 166 | + unsigned int irq_type, unsigned int hw_prio) |
|---|
| 242 | 167 | { |
|---|
| 243 | 168 | int r, i; |
|---|
| 244 | 169 | int sched_hw_submission = amdgpu_sched_hw_submission; |
|---|
| 170 | + u32 *num_sched; |
|---|
| 171 | + u32 hw_ip; |
|---|
| 245 | 172 | |
|---|
| 246 | 173 | /* Set the hw submission limit higher for KIQ because |
|---|
| 247 | 174 | * it's used for a number of gfx/compute tasks by both |
|---|
| .. | .. |
|---|
| 251 | 178 | */ |
|---|
| 252 | 179 | if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ) |
|---|
| 253 | 180 | sched_hw_submission = max(sched_hw_submission, 256); |
|---|
| 181 | + else if (ring == &adev->sdma.instance[0].page) |
|---|
| 182 | + sched_hw_submission = 256; |
|---|
| 254 | 183 | |
|---|
| 255 | 184 | if (ring->adev == NULL) { |
|---|
| 256 | 185 | if (adev->num_rings >= AMDGPU_MAX_RINGS) |
|---|
| .. | .. |
|---|
| 281 | 210 | dev_err(adev->dev, "(%d) ring fence_offs wb alloc failed\n", r); |
|---|
| 282 | 211 | return r; |
|---|
| 283 | 212 | } |
|---|
| 213 | + |
|---|
| 214 | + r = amdgpu_device_wb_get(adev, &ring->trail_fence_offs); |
|---|
| 215 | + if (r) { |
|---|
| 216 | + dev_err(adev->dev, |
|---|
| 217 | + "(%d) ring trail_fence_offs wb alloc failed\n", r); |
|---|
| 218 | + return r; |
|---|
| 219 | + } |
|---|
| 220 | + ring->trail_fence_gpu_addr = |
|---|
| 221 | + adev->wb.gpu_addr + (ring->trail_fence_offs * 4); |
|---|
| 222 | + ring->trail_fence_cpu_addr = &adev->wb.wb[ring->trail_fence_offs]; |
|---|
| 284 | 223 | |
|---|
| 285 | 224 | r = amdgpu_device_wb_get(adev, &ring->cond_exe_offs); |
|---|
| 286 | 225 | if (r) { |
|---|
| .. | .. |
|---|
| 320 | 259 | ring->max_dw = max_dw; |
|---|
| 321 | 260 | ring->priority = DRM_SCHED_PRIORITY_NORMAL; |
|---|
| 322 | 261 | mutex_init(&ring->priority_mutex); |
|---|
| 323 | | - INIT_LIST_HEAD(&ring->lru_list); |
|---|
| 324 | | - amdgpu_ring_lru_touch(adev, ring); |
|---|
| 325 | 262 | |
|---|
| 326 | | - for (i = 0; i < DRM_SCHED_PRIORITY_MAX; ++i) |
|---|
| 327 | | - atomic_set(&ring->num_jobs[i], 0); |
|---|
| 328 | | - |
|---|
| 329 | | - if (amdgpu_debugfs_ring_init(adev, ring)) { |
|---|
| 330 | | - DRM_ERROR("Failed to register debugfs file for rings !\n"); |
|---|
| 263 | + if (!ring->no_scheduler) { |
|---|
| 264 | + hw_ip = ring->funcs->type; |
|---|
| 265 | + num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds; |
|---|
| 266 | + adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] = |
|---|
| 267 | + &ring->sched; |
|---|
| 331 | 268 | } |
|---|
| 269 | + |
|---|
| 270 | + for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; ++i) |
|---|
| 271 | + atomic_set(&ring->num_jobs[i], 0); |
|---|
| 332 | 272 | |
|---|
| 333 | 273 | return 0; |
|---|
| 334 | 274 | } |
|---|
| .. | .. |
|---|
| 343 | 283 | */ |
|---|
| 344 | 284 | void amdgpu_ring_fini(struct amdgpu_ring *ring) |
|---|
| 345 | 285 | { |
|---|
| 346 | | - ring->ready = false; |
|---|
| 347 | 286 | |
|---|
| 348 | 287 | /* Not to finish a ring which is not initialized */ |
|---|
| 349 | 288 | if (!(ring->adev) || !(ring->adev->rings[ring->idx])) |
|---|
| 350 | 289 | return; |
|---|
| 290 | + |
|---|
| 291 | + ring->sched.ready = false; |
|---|
| 351 | 292 | |
|---|
| 352 | 293 | amdgpu_device_wb_free(ring->adev, ring->rptr_offs); |
|---|
| 353 | 294 | amdgpu_device_wb_free(ring->adev, ring->wptr_offs); |
|---|
| .. | .. |
|---|
| 359 | 300 | &ring->gpu_addr, |
|---|
| 360 | 301 | (void **)&ring->ring); |
|---|
| 361 | 302 | |
|---|
| 362 | | - amdgpu_debugfs_ring_fini(ring); |
|---|
| 363 | | - |
|---|
| 364 | 303 | dma_fence_put(ring->vmid_wait); |
|---|
| 365 | 304 | ring->vmid_wait = NULL; |
|---|
| 366 | 305 | ring->me = 0; |
|---|
| 367 | 306 | |
|---|
| 368 | 307 | ring->adev->rings[ring->idx] = NULL; |
|---|
| 369 | | -} |
|---|
| 370 | | - |
|---|
| 371 | | -static void amdgpu_ring_lru_touch_locked(struct amdgpu_device *adev, |
|---|
| 372 | | - struct amdgpu_ring *ring) |
|---|
| 373 | | -{ |
|---|
| 374 | | - /* list_move_tail handles the case where ring isn't part of the list */ |
|---|
| 375 | | - list_move_tail(&ring->lru_list, &adev->ring_lru_list); |
|---|
| 376 | | -} |
|---|
| 377 | | - |
|---|
| 378 | | -static bool amdgpu_ring_is_blacklisted(struct amdgpu_ring *ring, |
|---|
| 379 | | - int *blacklist, int num_blacklist) |
|---|
| 380 | | -{ |
|---|
| 381 | | - int i; |
|---|
| 382 | | - |
|---|
| 383 | | - for (i = 0; i < num_blacklist; i++) { |
|---|
| 384 | | - if (ring->idx == blacklist[i]) |
|---|
| 385 | | - return true; |
|---|
| 386 | | - } |
|---|
| 387 | | - |
|---|
| 388 | | - return false; |
|---|
| 389 | | -} |
|---|
| 390 | | - |
|---|
| 391 | | -/** |
|---|
| 392 | | - * amdgpu_ring_lru_get - get the least recently used ring for a HW IP block |
|---|
| 393 | | - * |
|---|
| 394 | | - * @adev: amdgpu_device pointer |
|---|
| 395 | | - * @type: amdgpu_ring_type enum |
|---|
| 396 | | - * @blacklist: blacklisted ring ids array |
|---|
| 397 | | - * @num_blacklist: number of entries in @blacklist |
|---|
| 398 | | - * @lru_pipe_order: find a ring from the least recently used pipe |
|---|
| 399 | | - * @ring: output ring |
|---|
| 400 | | - * |
|---|
| 401 | | - * Retrieve the amdgpu_ring structure for the least recently used ring of |
|---|
| 402 | | - * a specific IP block (all asics). |
|---|
| 403 | | - * Returns 0 on success, error on failure. |
|---|
| 404 | | - */ |
|---|
| 405 | | -int amdgpu_ring_lru_get(struct amdgpu_device *adev, int type, |
|---|
| 406 | | - int *blacklist, int num_blacklist, |
|---|
| 407 | | - bool lru_pipe_order, struct amdgpu_ring **ring) |
|---|
| 408 | | -{ |
|---|
| 409 | | - struct amdgpu_ring *entry; |
|---|
| 410 | | - |
|---|
| 411 | | - /* List is sorted in LRU order, find first entry corresponding |
|---|
| 412 | | - * to the desired HW IP */ |
|---|
| 413 | | - *ring = NULL; |
|---|
| 414 | | - spin_lock(&adev->ring_lru_list_lock); |
|---|
| 415 | | - list_for_each_entry(entry, &adev->ring_lru_list, lru_list) { |
|---|
| 416 | | - if (entry->funcs->type != type) |
|---|
| 417 | | - continue; |
|---|
| 418 | | - |
|---|
| 419 | | - if (amdgpu_ring_is_blacklisted(entry, blacklist, num_blacklist)) |
|---|
| 420 | | - continue; |
|---|
| 421 | | - |
|---|
| 422 | | - if (!*ring) { |
|---|
| 423 | | - *ring = entry; |
|---|
| 424 | | - |
|---|
| 425 | | - /* We are done for ring LRU */ |
|---|
| 426 | | - if (!lru_pipe_order) |
|---|
| 427 | | - break; |
|---|
| 428 | | - } |
|---|
| 429 | | - |
|---|
| 430 | | - /* Move all rings on the same pipe to the end of the list */ |
|---|
| 431 | | - if (entry->pipe == (*ring)->pipe) |
|---|
| 432 | | - amdgpu_ring_lru_touch_locked(adev, entry); |
|---|
| 433 | | - } |
|---|
| 434 | | - |
|---|
| 435 | | - /* Move the ring we found to the end of the list */ |
|---|
| 436 | | - if (*ring) |
|---|
| 437 | | - amdgpu_ring_lru_touch_locked(adev, *ring); |
|---|
| 438 | | - |
|---|
| 439 | | - spin_unlock(&adev->ring_lru_list_lock); |
|---|
| 440 | | - |
|---|
| 441 | | - if (!*ring) { |
|---|
| 442 | | - DRM_ERROR("Ring LRU contains no entries for ring type:%d\n", type); |
|---|
| 443 | | - return -EINVAL; |
|---|
| 444 | | - } |
|---|
| 445 | | - |
|---|
| 446 | | - return 0; |
|---|
| 447 | | -} |
|---|
| 448 | | - |
|---|
| 449 | | -/** |
|---|
| 450 | | - * amdgpu_ring_lru_touch - mark a ring as recently being used |
|---|
| 451 | | - * |
|---|
| 452 | | - * @adev: amdgpu_device pointer |
|---|
| 453 | | - * @ring: ring to touch |
|---|
| 454 | | - * |
|---|
| 455 | | - * Move @ring to the tail of the lru list |
|---|
| 456 | | - */ |
|---|
| 457 | | -void amdgpu_ring_lru_touch(struct amdgpu_device *adev, struct amdgpu_ring *ring) |
|---|
| 458 | | -{ |
|---|
| 459 | | - spin_lock(&adev->ring_lru_list_lock); |
|---|
| 460 | | - amdgpu_ring_lru_touch_locked(adev, ring); |
|---|
| 461 | | - spin_unlock(&adev->ring_lru_list_lock); |
|---|
| 462 | 308 | } |
|---|
| 463 | 309 | |
|---|
| 464 | 310 | /** |
|---|
| .. | .. |
|---|
| 479 | 325 | { |
|---|
| 480 | 326 | amdgpu_ring_emit_wreg(ring, reg0, ref); |
|---|
| 481 | 327 | amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); |
|---|
| 328 | +} |
|---|
| 329 | + |
|---|
| 330 | +/** |
|---|
| 331 | + * amdgpu_ring_soft_recovery - try to soft recover a ring lockup |
|---|
| 332 | + * |
|---|
| 333 | + * @ring: ring to try the recovery on |
|---|
| 334 | + * @vmid: VMID we try to get going again |
|---|
| 335 | + * @fence: timedout fence |
|---|
| 336 | + * |
|---|
| 337 | + * Tries to get a ring proceeding again when it is stuck. |
|---|
| 338 | + */ |
|---|
| 339 | +bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid, |
|---|
| 340 | + struct dma_fence *fence) |
|---|
| 341 | +{ |
|---|
| 342 | + ktime_t deadline = ktime_add_us(ktime_get(), 10000); |
|---|
| 343 | + |
|---|
| 344 | + if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence) |
|---|
| 345 | + return false; |
|---|
| 346 | + |
|---|
| 347 | + atomic_inc(&ring->adev->gpu_reset_counter); |
|---|
| 348 | + while (!dma_fence_is_signaled(fence) && |
|---|
| 349 | + ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0) |
|---|
| 350 | + ring->funcs->soft_recovery(ring, vmid); |
|---|
| 351 | + |
|---|
| 352 | + return dma_fence_is_signaled(fence); |
|---|
| 482 | 353 | } |
|---|
| 483 | 354 | |
|---|
| 484 | 355 | /* |
|---|
| .. | .. |
|---|
| 545 | 416 | |
|---|
| 546 | 417 | #endif |
|---|
| 547 | 418 | |
|---|
| 548 | | -static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, |
|---|
| 549 | | - struct amdgpu_ring *ring) |
|---|
| 419 | +int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, |
|---|
| 420 | + struct amdgpu_ring *ring) |
|---|
| 550 | 421 | { |
|---|
| 551 | 422 | #if defined(CONFIG_DEBUG_FS) |
|---|
| 552 | | - struct drm_minor *minor = adev->ddev->primary; |
|---|
| 423 | + struct drm_minor *minor = adev_to_drm(adev)->primary; |
|---|
| 553 | 424 | struct dentry *ent, *root = minor->debugfs_root; |
|---|
| 554 | 425 | char name[32]; |
|---|
| 555 | 426 | |
|---|
| .. | .. |
|---|
| 567 | 438 | return 0; |
|---|
| 568 | 439 | } |
|---|
| 569 | 440 | |
|---|
| 570 | | -static void amdgpu_debugfs_ring_fini(struct amdgpu_ring *ring) |
|---|
| 441 | +/** |
|---|
| 442 | + * amdgpu_ring_test_helper - tests ring and set sched readiness status |
|---|
| 443 | + * |
|---|
| 444 | + * @ring: ring to try the recovery on |
|---|
| 445 | + * |
|---|
| 446 | + * Tests ring and set sched readiness status |
|---|
| 447 | + * |
|---|
| 448 | + * Returns 0 on success, error on failure. |
|---|
| 449 | + */ |
|---|
| 450 | +int amdgpu_ring_test_helper(struct amdgpu_ring *ring) |
|---|
| 571 | 451 | { |
|---|
| 572 | | -#if defined(CONFIG_DEBUG_FS) |
|---|
| 573 | | - debugfs_remove(ring->ent); |
|---|
| 574 | | -#endif |
|---|
| 452 | + struct amdgpu_device *adev = ring->adev; |
|---|
| 453 | + int r; |
|---|
| 454 | + |
|---|
| 455 | + r = amdgpu_ring_test_ring(ring); |
|---|
| 456 | + if (r) |
|---|
| 457 | + DRM_DEV_ERROR(adev->dev, "ring %s test failed (%d)\n", |
|---|
| 458 | + ring->name, r); |
|---|
| 459 | + else |
|---|
| 460 | + DRM_DEV_DEBUG(adev->dev, "ring test on %s succeeded\n", |
|---|
| 461 | + ring->name); |
|---|
| 462 | + |
|---|
| 463 | + ring->sched.ready = !r; |
|---|
| 464 | + return r; |
|---|
| 575 | 465 | } |
|---|